栈
栈是一种特殊的线性表,这种线性表仅允许在表尾(栈顶)进行插入和删除工作:将可以被插入和删除元素的位置称为栈顶
, 将另一端称为 栈底
, 如果栈没有任何的元素, 这个栈被称为 空栈
;栈的数据元素的进出遵循后进先出的原则,简称为 LIFO (Last In First Out) 结构;栈的插入被称为入栈, 栈的删除被称为出栈, 在程序中我们可以将其称为 push
和 pop
;在 js 中, 我们使用数组的 push
和 pop
方法模拟栈的入栈和出栈操作;栈的应用
递归
我们将调用函数自身或者间接调用自身的函数称为 递归 在每一层递归的过程中, 我们需要存储当前调用函数的局部变量, 参数值等数据信息存储到栈中,当递归返回之后, 再将这些数据从栈中弹出数据使用栈实现四则运算表达式
如下面程序, 实现将一串运算表达式进行计算的代码:1 | // 对于逆波兰法表示的后缀表达式计算求值 |
队列
队列是只允许在一端进行插入操作, 而在另一端进行删除操作的线性表队列遵循的是先进先出的线性表, 在程序设计中的应用, 比如我们在显示器上记事本上文字的输出。在日常生活中, 比如我们购买火车票时的排队。
队列的线式存储结构
在 js 中, 我们使用数组的push
和 shift(表头弹出)
这两个 api 实现队列的模拟。顺序存储
使用顺序存储时,我们将队列数据元素按照顺序存储到数组中, 当我们想要对于队列进行出列操作时, 因为出列操作是在表头出列, 因此,出列数据元素后面的每一个数据都会向前移动一个元素位置, 这样会造成程序性能的损耗。 这个时候的时间复杂度为O(n)
为了解决这个移动队列数据元素的问题, 我们可以引入两个指针: front
: 指向队头元素, rear
: 指向队尾元素的下一个位置当我们对于队列进行添加和删除元素的时候, 只要改变 front
和 rear
指针的位置就可以了, 不需要移动每个队列元素:1 | function queue(queueLen) { |
1 | const queueList = queue(2); |
循环队列
循环队列相比上面的存储方法而言, 有一些不同, 主要是体现在rear
指针的指向,rear
指针在队列初始化的时候指向下标 为 0 的位置, 当到达队列列尾的时候, rear
指针移动到队列列头1 | function queue(queueSize) { |
链式存储结构
队列的链式存储结构其实就是单链表。与普通的单链表不同的是, 只能操作链表的头部和尾部节点,队列的链式存储结构被称为链队列
;总结
当已知队列空间大小的情况下, 可以使用循环队列
, 否则, 如果不知道队列的长度, 使用 链对列