理论:

共同特点:

栈:是限制在表的一端进行插入和删除运算的线性表。栈又称后进先出简称:LIFO表 队列:也是一种运算受限的线性表。它只允许在标的一端进行插入,而在另一端进行删除。队列亦称:先进先出FIFO表

不同点:

队列是先进先出:就像一条路,有一个入口和一个出口,先进去的就可以先出去。

而栈就像一个箱子,后放的在上边,所以后进先出。

进程中每个线程都有自己的堆栈,这是一段线程创建时保留下的地址区域。我们的“栈内存”即在此。至于“堆”内存,在未用new定义时,堆应该就是未“保留”未“提交”的自由空间,new的功能是在这些自由空间中保留(并提交)出一个地址范围。

栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有FIFO的特性,在编译的时候可以指定需要的Stack的大小。在编程中,例如C/C++中,所有的局部变量都是从栈中分配内存空间,实际上也不是什么分配,只是从栈顶向上用就行,在退出函数的时候,只是修改栈指针就可以把栈中的内容销毁,所以速度最快。 

堆(Heap)是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程,C/C++分别用malloc/New请求分配Heap,用free/delete销毁内存。由于从操作系统管理的内存分配所以在分配和销毁时都要占用时间,所以用堆的效率低的多!但是堆的好处是可以做的很大,C/C++对分配的Heap是不初始化的。 

堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。{堆是指程序运行是申请的动态内存,而栈只是指一种使用堆的方法(即先进后出)。}

栈是先进后出的,但是于堆而言却没有这个特性,两者都是存放临时数据的地方。 对于堆,我们可以随心所欲的进行增加变量和删除变量,不要遵循什么次序,只要你喜欢。

转载于

1.队列先进先出,栈先进后出。
2. 对插入和删除操作的"限定"。 栈是限定只能在表的一端进行插入和删除操作的线性表。 队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。 从"数据结构"的角度看,它们都是线性结构,即数据元素之间的关系相同。但它们是完全不同的数据类型。除了它们各自的基本操作集不同外,主要区别是对插入和删除操作的"限定"。 栈和队列是在程序设计中被广泛使用的两种线性数据结构,它们的特点在于基本操作的特殊性,栈必须按"后进先出"的规则进行操作,而队列必须按"先进先出" 的规则进行操作。和线性表相比,它们的插入和删除操作受更多的约束和限定,故又称为限定性的线性表结构。

3.遍历数据速度不同。栈只能从头部取数据 也就最先放入的需要遍历整个栈最后才能取出来,而且在遍历数据的时候还得为数据开辟临时空间,保持数据在遍历前的一致性队列怎不同,他基于地址指针进行遍历,而且可以从头或尾部开始遍历,但不能同时遍历,无需开辟临时空间,因为在遍历的过程中不影像数据结构,速度要快的多

栈(Stack)是限定只能在表的一端进行插入和删除操作的线性表。
队列(Queue)是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
从"数据结构"的角度看,它们都是线性结构,即数据元素之间的关系相同。但它们是完全不同的数据类型。除了它们各自的基本操作集不同外,主要区别是对插入和删除操作的"限定"。

栈和队列是在程序设计中被广泛使用的两种线性数据结构,它们的特点在于基本操作的特殊性,栈必须按"后进先出"的规则进行操作,而队列必须按"先进先出"的规则进行操作。和线性表相比,它们的插入和删除操作受更多的约束和限定,故又称为限定性的线性表结构。可将线性表和栈及队列的插入和删除操作对比如下:

线性表

Insert(L,i,x)
(1≤i≤n+1)
Delete(L,i)
(1≤i≤n)

如线性表允许在表内任一位置进行插入和删除

Insert(L,n+1,x)
Delete(L,n)

而栈只允许在表尾一端进行插入和删除

队列

Insert(L,n+1,x)
Delete(L,1)

队列只允许在表尾一端进行插入,在表头一端进行删除

应用:

堆栈和队列是最基本的两个ADT,简单但是重要。先讲堆栈在计算机中的应用。

堆栈:

1.用于符号匹配。

在编译器的语法检查中,一个过程就是检查各种括号是否匹配,比如 ([]) ,这就是匹配的,而 {[}] 就不匹配了。可以用堆栈来实现括号匹配。

具体算法如下:

建立一个空的堆栈。
    while( 文件没有结束 ) {
        读取一个字符。
        if 遇到一个左括号,把它入栈。
        else if 遇到右括号 then 检查堆栈,{
            if 堆栈为空 then 报告错误,终止程序(括号不匹配)。
            else if 堆栈非空 then {
                if 栈顶不是对应的左括号 then 报错,终止程序。
                弹出栈顶。
            }
     }
    if 栈非空 then 报错。

2.用于计算代数式。( 也可以用二叉树来解决 )

如果我们要计算 6 + 4 * 8 ,要考虑到优先级的问题,这时候就可以用到堆栈了。

先要把代数式构造成 6 4 8 * + (构造方法也是用堆栈,在下一条会讲到)。逐个读取数据,当读到数字时, 把数字入栈,

读到运算符时,弹出栈中的两个元素(因为这里的是二元运算符,所以弹出两个,如果是sin等一元运算符就弹出一个),根据读取

的运算符执行运算,把结果压入栈中,然后继续读取数据,读取结束后栈顶元素就是结果。

比如读取6,4,8,由于是数字,所以依次入栈,

读到 "*" 时,弹出 4 和 8,相乘得到 32,把32入栈。读到 "+" 时,

弹出 6 和 32 ,执行运算得到 38,压入栈中,接着读取结束,栈顶的 38 就是结果。

3.构造表达式。( 也可以用二叉树来解决 )

比如一个正常的代数式(叫他infix), a + b * c + ( d * e + f ) * g , 转化成表达式 a b c * + d e * f + g * +, 这个表达式我们叫他 postfix。

把postfix按照 2 中的算法计算就能得到正确的计算顺序。

先规定优先级,加减的优先级最低,左括号优先级最高

创建一个字符串output储存 postfix。
创建一个空栈 operators。
while ( )
    逐个读取 infix 中的元素,储存在 temp 中。
 
    if temp 是数字(operand)then 把 temp 压入 output 字符串。
    if temp 是除了右括号 ")" 之外的运算符(operator)
        if operators 栈空 then temp 入栈。
        if operators 栈非空,
            while ( 栈顶元素优先级大于或等于 temp 并且 栈顶元素不等于左括号 )
                    弹出栈顶元素到 output 。
    if temp 是右括号 ")" 
        while ( 栈顶元素不等于左括号 )
                弹出栈顶元素到 ouput.
        弹出左括号, 但是不输出到 output

比如 a * ( b * c + d ),左边是堆栈中的情况,右边是输出

1.  输出 a,把 "*" 入栈                              
operators                output
 
top  *                       a
 
2. "(" 入栈,输出 b
operators                output
 
top  (
      *                       a  b  
 
3. "*"入栈,输出 c
operators                output
 

top  *                       a  b  c 
      (
      *
4. 读到 + 号,因为栈顶的 * 优先级大于 + 号,所以弹出栈顶到 output,也就是弹出 "*" ,并输出 "*" 
operators                output
 
top  +                       a  b  c  * d
      (
      *
5.读到 ")" 右括号,弹出左括号 "(" 上的所有运算符,并弹出左括号 "(" ,注意此时左括号没有输出
operators                output
 
top  *                       a  b  c  *  d  + 
 
6.最后所有元素依次出栈
operators                output
 
top                          a  b  c  *  d  +  *

4.用于函数调用

因为CPU一次只能执行一个命令,而寄存器也是公用的,

当前函数 current() 在运行时,数据储存在寄存器中,如果要调用另外一个函数 target(),而target() 也要求使用寄存器,为了防止数据丢失并且在执行完 target()

能够返回到 current() 继续执行, 这时候就要把当前函数的重要数据储存起来,压入内存中的栈中( 包括变量的值和函数地址 )。这样target()函数就可以无所顾忌的使用寄存器了。

target() 函数执行结束就取栈顶的返回地址继续执行 current()。如果target()中又调用另外一个函数,相应的操作也是一样的。

这种机制和括号匹配有点相似,函数调用就像遇到了一个左括号,函数返回就像遇到一个右括号。

递归返回地址就是自己。(这句话可能有问题,我就是这么理解的)。

栈的空间有限,如果递归没有结束条件,就会不断的压栈,然后栈溢出,程序出错。

队列:

当多个任务分配给打印机时,为了防止冲突,创建一个队列,把任务入队,按先入先出的原则处理任务。

当多个用户要访问远程服务端的文件时,也用到队列,满足先来先服务的原则。

……

有一个数学的分支,叫队列理论(queuing theory )。用来计算 预测用户在队中的等待时间,队的长度等等问题。

答案取决于用户到达队列的频率,用户的任务的处理时间。如果比较简单的情况,可以单单用分析解决。一个简单的例子就是,

一部电话,一个接线员。当一个电话打进来,如果接线员很忙,就电话放到等待线路后。接线员从队头开始应答。

如果有k个接线员,问题就变的复杂了。通常难以分析解决的问题就用模拟来解决。 可以用一个队列来模拟这个问题。如果k的值很大,

我们也可能需要其他数据结构来模拟问题。通过模拟,可以找到最小的 k 值,使队列满足一个合理的等待时间。