C++队列、堆栈、堆的区别

一、queue模板类

      queue 队列是一个线性存储表,构成了一个先进先出(FirstInFirstOut) 表。该容器内存结构最好为链式结构,最知名的特点是先进先出,能动态调整大小,适用于包含大量增、删操作的情况,但不适用于含有大量查找操作的数据

      队头&队尾:插入一端称为队尾,删除一端称为队首

①队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

②队列中没有元素时,称为空队列。

③建立顺序队列结构必须为其静态分配或动态申请一片连续的存储空间,并设置两个指针进行管理。一个是队头指针front,它指向队头元素;另一个是队尾指针rear,它指向下一个入队元素的存储位置。

④队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部,而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素。所谓的动态创建,动态释放。因而也不存在溢出等问题。由于链表由结构体间接而成,遍历也方便。(先进先出)

                                             

front指向头,rear指向尾的下一个元素(就是下次入队的位置)。

另外一种就是front指向头,rear指向尾,每个人习惯不同,要看具体的代码才知道它们到底指向什么。

循环队列

     对于队列最好的方法是使用链表实现,因为对于数组来说,队列可能会出现下面这种情况:

    

    如图所示,不可以继续添加元素,否则会造成数组越界而遭致程序出错。然而此时又不应该扩充数组,因为还有大量实际空间未被占用。此时我们应该如何解决这个问题呢?我们将其实现为循环队列

 何谓循环队列?首先我们要说明的是循环队列仍然是基于数组实现的。但是为了形象化的说明问题,我们如下图所示

          

1、要求front指向队头,rear指向队尾,那么初始化front=0,rear究竟是0还是n-1,不妨假设rear=0,那么很明显此时已经有一个元素入队了,在a[0]的位置,此时front=rear=0,与初始为空矛盾.所以rear=(0-1)%n=n-1.

2、循环队列为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。

rear和front互相追赶着,这个追赶过程就是队列添加和删除的过程,如果rear追到head说明队列满了,如果front追到rear说明队列为空。

  • 循环列表存在满和空两种情况,我们需要分别判断:

 :当队列添加元素到rear的下一个元素是head的时候,也就是转圈子要碰头了,我们就认为队列满了。(Q.rear+1)%MAXSIZE=Q.front

 :当队列删除元素到head=rear的时候,我们认为队列空了。Q.rear==Q.front,不一定为0。图示:

    

from:https://www.cnblogs.com/chenliyang/p/6554141.html

   队列可以用线性表(list)或双向队列(deque)来实现:( 默认使用双端队列deque来实现)

queue<list<int> > q1;
queue<deque<int> > q2;

      C++ STL对queue队列的泛化,是通过模板类型,将默认的deque双端队列类型导入,在内部创建一个序列容器对象,来处理 queue队列的数据存储和操作,包括queue队列是否为空、取队首元素、取队尾元素、元素入队和元素出队等。由于仅需要取队首和队尾元素的操作,因此queue队列容器并不提供任何类型的迭代器

  • queue模板类的定义在<queue>头文件中。
  • queue 模板类也需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque 类型。

定义queue 对象的示例代码如下:

queue<int> q1;
queue<double> q2;

在C++中只要#include<queue>即可使用队列类,其中常用的成员函数如下:

1. push() 在末尾加入一个元素

queue<string> q;
q.push("Hello World!");
q.push("China");
4 cout<<q.front()<<endl;

可以输出:Hello World!

2. pop() 删除第一个元素,注意,并不会返回被弹出元素的值。

q.pop();
cout<<q.front()<<endl;
可以输出:China

注意:Hello World!已经被移除了。 

3. size() 返回队列中元素的个数

返回值类型为unsigned int。如:

q.pop();
cout<<q.size()<<endl;
q.push("Hello World!");
q.push("China");
cout<<q.size()<<endl;

输出两行,分别为0和2,即队列中元素的个数。

4. empty() 如果队列空则返回真

5. front() 返回第一个元素

注意这里只是返回最早进入的元素,并没有把它剔除出队列。如:

cout<<q.front()<<endl;
q.pop();
cout<<q.front()<<endl;

输出两行,分别是Hello World!和China。只有在使用了pop以后,队列中的最早进入元素才会被剔除。

6. back() 返回最后一个元素,也就是最晚进去的元素

q.push("Hello World!");
cout<<q.back()<<endl;

输出值为Hello World!因为它是最后进去的。这里back仅仅是返回最后一个元素,也并没有将该元素从队列剔除掉。

二、栈

     栈(stack),又名堆栈,是一种运算受限制的线性表类型的数据结构。其限制是只允许在栈的一段进行插入和删除运算这一端被称为栈顶,相对地,把另一端称为栈底。 
    可以想像往子弹夹中装子弹的情形,正常情况下只能往子弹夹入口那端装入子弹,这一步就好比向栈中压入元素,称为 push,射击的时候,弹夹会从顶端弹出子弹,这一步就好比从栈顶弹出元素,称为 pop,可以发现,从栈顶弹出的子弹是最后一个压进去的子弹,这也是栈的一个重要性质先进后出(FILO——first in last out)。用一个 top 指针表示当前栈顶的位置。下图演示栈的 push 和 pop 的过程。 

                                      这里写图片描述

     用 stack 表示存储栈的空间,top 表示当栈顶的指针位置,方法 push( ) 压入一个数 x 到栈顶,方法 pop( ) 从栈顶弹出一个元素,方法 topval( ) 获取栈顶元素。  C++ 中已经有写好的栈的对象,可以直接用。

#include <stack>
#include <iostream>
using namespace std;
stack<int> S;
int main() {
    S.push(1);
    S.push(10);
    S.push(7);
    while (!S.empty()) {
        cout << S.top() << endl;
        S.pop();
    }
    return 0;
}

上面是 C++ 里的 stack 的用法。push,pop 分别是压栈和出栈,top 是栈顶元素,empty 判断栈是否为空。

     栈的经典的应用:火车车厢入站和出站顺序确定。火车进展的时候车厢编号为从前到后一次 1,2,3,4,5,然后确定一个出站顺序是否合法。这里站台就是一个栈的结构。需要遵循先进后出的顺序。用一个栈模拟就可以得到出站顺序是否合理。

                                  

练习、剑指offer面试题30——包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。

class Solution {
public:
    stack<int> stackData;//保存数据用的栈stackData
    stack<int> stackMin;//保存最小的数的栈stackMin,其中它的栈顶始终为最小的数
    void push(int value) {
        stackData.push(value);
        if(stackMin.empty()) 
            stackMin.push(value);//如果stackMin为空,则value是最小的值,入栈
        else{
            if(stackMin.top()>=value) 
                stackMin.push(value);//否则当value小于等于stackMin的栈顶元素时,入栈(等于的时候也入栈是因为我考虑有相同的数)
        }
  }
  void pop() {
      if(stackData.top()==stackMin.top())//如果出栈的数刚好是最小的数,那么stackMin也应该出栈
        stackMin.pop();
      stackData.pop();
  }
  int top() {
    return stackData.top();//栈顶元素应返回stackData的栈顶元素
  }
  int min() {
    return stackMin.top();//stackMin的栈顶元素即是最小的数
  }
};

from:https://blog.csdn.net/Richard__Ting/article/details/79490665

总结:堆、栈、堆栈、队列

1、队列是先进先出:先进去的就可以先出去。

2、首先堆栈和栈是一个概念!!!栈就像一个子弹夹,后放的子弹在上边,所以后进先出。栈是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除。

3、堆和它们不同,不存在是先进后出还是先进先出。堆通常是一个可以被看做一棵树的数组对象。堆满足下列性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

①堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。

②堆是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程。

③堆是指程序运行时申请的动态内存,而栈只是指一种使用堆的方法(即先进后出)。

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

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

区别:

堆和栈都是一种数据项按序排列的数据结构。

栈:就像装数据的桶或箱子,它是一种具有后进先出性质的数据结构。

堆:一种经过排序的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。由于堆的这个特性,常用来实现优先队列,堆的存取是随意,这就如同我们在图书馆的书架上取书,虽然书的摆放是有顺序的,但是我们想取任意一本时不必像栈一样,先取出前面所有的书,书架这种机制不同于箱子,我们可以直接取出我们想要的书。

堆和栈的变量存储区别:

*程序的局部变量存在于(栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中;

①所谓的栈其实是由寄存器ebp和esp指向的一片内存空间(ebp指向栈底,esp指向栈顶),原则上是由高地址向低地址生长的一片空间,会保存一些临时的数据,比如一个函数中的临时变量以及返回地址。

全局变量实际上是存在一个可读可写的内存空间,这个空间是在你写程序编译好的空间地址(由编译器决定),是固定的。全局静态区用于保存全局变量和静态变量;

②堆事先是没有在进程空间里分配的,一般是由程序动态的分配出来,一旦分配了以后,一般需要程序去释放自己的堆空间。堆用于保存new 和malloc这些自定义的内存变量;两者都是存放临时数据的地方。 对于堆,我们可以随心所欲的进行增加变量和删除变量,不要遵循什么次序,只要你喜欢。

堆栈数据结构区别:

①堆(数据结构):堆可以被看成是一棵树,如:堆排序。

②栈(数据结构):一种先进后出的数据结构。

堆栈缓存方式区别:

①栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。

②堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值