【前端算法】两个栈实现一个队列

简介: 介绍栈和队列的区别,以及如何使用栈实现一个队列
  • 请用两个栈,实现一个队列
  • 功能 add delete length

队列

  • 先进先出
  • API : add delete length

逻辑结构 VS 物理结构

  • 队列是逻辑结构,抽象模型
  • 简单的,可以使用数组、链表实现
  • 复杂的队列服务,需单独设计

思路

  • 入队直接使用push填入栈1
  • 出队:先将栈1的元素pop到栈2,然后栈2使用pop,最后栈2在pop到栈1

示例:入队===> ABCD === 【DCBA】

——
D
C
B
A
——

此时A在栈底,但是队列是先进先出,要删除A,需要将A放到栈顶。

出队:1、栈1【DCBA】===pop===>栈2【ABCD】

——
A
B
C
D
——

此时栈2中,A是在栈顶,可以删除A,满足队列先进先出的规则。

2、栈2【ABCD】===pop(A)===> 【BCD】

——
B
C
D
——

此时已经删除完了A,但是后续继续增加新的元素E或F,应该在D的后面,

3、栈2【BCD】===pop===> 栈1【DCB】

——
D
C
B
——

所以第三步D在栈顶,新增新的元素E或F,就在D的后面,满足的队列的先进先出规则。

代码实现

class MyQueue {
  private stack1: number[] = []
  private stack2:number[] = []

  add(num:number) {
    this.stack1.push(num)
  }

  delete():number | null {
    let res;
    const stack1 = this.stack1
    const stack2 = this.stack2
    // 将stck1 所有元素移动到stack2中
    while(stack1.length){
      const n:number = stack1.pop() as number
      if (n != null){
        stack2.push(n)
      }
      
    }
    // stack2 pop
    res = stack2.pop()

    // 将 stack2 所有元素“还给”stack1
    while(stack2.length){
      const n = stack2.pop() as number
      if (n != null) {
        stack1.push(n)
      }
      
    }

    return res || null

  }

  get length():number {
    return this.stack1.length
  }
}

功能测试

const q = new MyQueue()

q.add(100)
q.add(200)
q.add(300)
console.log(q.length) // 3
console.log(q.delete()) // 100
console.log(q.length) // 2

满足队列先进先出的规则

单元测试

describe('两个栈,一个队列',() => {
    it('add and length', () => {
        const q = new MyQueue()
        q.add(100)
        q.add(200)
        q.add(300)
        expect(q.length).toBe(3)
    })
    
    it('delete', () => {
        const q = new MyQueue()
        expect(q.delete()).toBeNull()
        q.add(100)
        q.add(200)
        q.add(300)
        expect(q.length).toBe(3)
        expect(q.delete()).toBe(100)
        expect(q.length).toBe(2)
        expect(q.delete()).toBe(200)
        expect(q.length).toBe(1)
        expect(q.delete()).toBe(300)
        expect(q.length).toBe(0)
    })
})

性能分析

  • 时间复杂度:add==>O(1); delete ==> O(n)
  • 空间复杂度,整体是O(n)

虽然在delete中有两次循环,但不是嵌套关系,所以它是时间和空间复杂度都是O(n);

相关文章
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
65 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
1月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
31 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
21天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
算法
数据结构与算法二:栈、前缀、中缀、后缀表达式、中缀表达式转换为后缀表达式
这篇文章讲解了栈的基本概念及其应用,并详细介绍了中缀表达式转换为后缀表达式的算法和实现步骤。
46 3
|
1月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
21 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
2月前
|
存储 算法 前端开发
深入理解操作系统:进程调度与优先级队列算法
【9月更文挑战第25天】在操作系统的复杂世界中,进程调度是维持系统稳定运行的核心机制之一。本文将深入探讨进程调度的基本概念,分析不同的进程调度算法,并着重介绍优先级队列算法的原理和实现。通过简洁明了的语言,我们将一起探索如何优化进程调度,提高操作系统的效率和响应速度。无论你是计算机科学的初学者还是希望深化理解的专业人士,这篇文章都将为你提供有价值的见解。
|
1月前
|
移动开发 算法 前端开发
前端常用算法全解:特征梳理、复杂度比较、分类解读与示例展示
前端常用算法全解:特征梳理、复杂度比较、分类解读与示例展示
22 0
|
2月前
|
算法 前端开发 机器人
一文了解分而治之和动态规则算法在前端中的应用
该文章详细介绍了分而治之策略和动态规划算法在前端开发中的应用,并通过具体的例子和LeetCode题目解析来说明这两种算法的特点及使用场景。
一文了解分而治之和动态规则算法在前端中的应用
|
2月前
|
存储 JSON 前端开发
栈在前端中的应用,顺便再了解下深拷贝和浅拷贝!
该文章探讨了栈在前端开发中的应用,并深入讲解了JavaScript中深拷贝与浅拷贝的区别及其实现方法。
栈在前端中的应用,顺便再了解下深拷贝和浅拷贝!
|
1月前
|
算法 C++
【算法单调栈】 矩形牛棚(C/C++)
【算法单调栈】 矩形牛棚(C/C++)