zoukankan      html  css  js  c++  java
  • 栈(基于数组&基于链表)与队列(基于数组&基于链表)

    一、栈

        1、栈(stack)是一种线性存储结构

        • 栈中的数据元素遵守先进后出的原则,FILO结构
        • 限定只能在栈顶进行插入与删除操作
        • 栈的操作包括压栈出栈

        2、栈的常用操作

        • 压栈(push)
        • 弹栈或出站(pop)
        • 求栈的大小
        • 判断栈是否为空
        • 获取栈顶元素的值

        3、栈的常见分类

        • 基于数组的栈,以数组为底层数据结构,通常以数组头为栈底,数组头到数组尾为栈顶的生长方向
        • 基于单链表的栈,以链表为底层的数据结构时,以链表头为栈顶,便于节点的插入与删除,压栈产生的结点将一直出现在链表的头部

        4、使用标准库的栈时,需要包含对应的头文件,

    • 1 #include<stack>
      2 stack<int>  s;
      3 s.empty();
      4 s.size();
      5 s.top();
      6 s.push();
      7 s.pop();
    • 基于数组的栈
      •  1 #include <stack>
         2 #include <iostream>
         3 using namespace std;
         4  
         5 int main()
         6 {
         7     stack<int> mystack;
         8     int sum = 0;
         9     for (int i = 0; i <= 10; i++){
        10         mystack.push(i);
        11     }
        12     cout << "size is " << mystack.size() << endl;
        13     while (!mystack.empty()){
        14         cout << " " << mystack.top();
        15         mystack.pop();
        16     }
        17     cout << endl;
        18     system("pause");
        19     return 0;
        20 }
        21 //size is 11
        22 // 10 9 8 7 6 5 4 3 2 1 0
    • 基于单链表的栈
      •  1 #include <iostream>
         2 using namespace std;
         3 template<class T>class Stack
         4 {
         5 private:
         6     struct Node
         7     {
         8         T data;
         9         Node *next;
        10     };
        11     Node *head;
        12     Node *p;
        13     int length;
        14  
        15 public:
        16     Stack()
        17     {
        18         head = NULL;
        19         length = 0;
        20     }
        21     void push(T n)//入栈
        22     {
        23         Node *q = new Node;
        24         q->data = n;
        25         if (head == NULL)
        26         {
        27             q->next = head;
        28             head = q;
        29             p = q;
        30         }
        31         else
        32         {
        33             q->next = p;
        34             p = q;
        35         }
        36         length++;
        37     }
        38  
        39     T pop()//出栈并且将出栈的元素返回
        40     {
        41         if (length <= 0)
        42         {
        43             abort();
        44         }
        45         Node *q;
        46         int data;
        47         q = p;
        48         data = p->data;
        49         p = p->next;
        50         delete(q);
        51         length--;
        52         return data;
        53     }
        54     int size()//返回元素个数
        55     {
        56         return length;
        57     }
        58     T top()//返回栈顶元素
        59     {
        60         return p->data;
        61     }
        62     bool isEmpty()//判断栈是不是空的
        63     {
        64         if (length == 0)
        65         {
        66             return true;
        67         }
        68         else
        69         {
        70             return false;
        71         }
        72     }
        73     void clear()//清空栈中的所有元素
        74     {
        75         while (length > 0)
        76         {
        77             pop();
        78         }
        79     }
        80 };
        81 int main()
        82 {
        83     Stack<char> s;
        84     s.push('a');
        85     s.push('b');
        86     s.push('c');
        87     while (!s.isEmpty())
        88     {
        89         cout << s.pop() << endl;
        90     }
        91     system("pause");
        92     return 0;
        93 }



    二、队列

        1、队列与栈一样是一种线性存储结构

        • 队列中的数据元素遵循先进先出的原则即FIFO原则
        • 在队尾添加元素,在队头删除元素
        • 队的操作包括入队和出队

        2、队列的操作

        • 入队(push)
        • 出队(pop)
        • 求队列中元素的个数
        • 判断队列是否为空
        • 获取队首元素

        3、队列的分类

        • 基于数组的循环队列(循环队列)
        • 基于链表的队列(链队列)

        4、C++队列queue模板类定义在<queue>头文件中,queue模板类需要两个模板参数,一个是元素类型,一个是容器类型。元素类型是必要的,容器类型是可选的,默认为deque类型。C++队列Queue是一种容器适配器,它给予程序员一种先进先出(FIFO)的数据结构。

    • 如何判断队列是空队列还是已满呢
        • 栈空:队首标志=队尾标志,表示栈空
        • 栈满:队尾+1=队首时,表示栈满
    • 使用标准库的队列时,应包含相关头文件,
      • #include<queue>
        queue<int> q;
        q.empty();
        q.size();
        q.push();
        q.pop();
        q.front();
        q.back();

      • 基于数组的循环队列
        • 以数组作为底层数据结构时,一般将队列实现为循环队列。这是因为队列在顺序存储上的不足:每次从数组头部删除元素(出队)后,需要将头部以后的所有元素往前移动一个位置,这是一个时间复杂度为O(n)的操作。
        • 循环队列可以将数组看成一个首位相连的圆环,删除元素时将队首标志往后移动,添加元素时若数组尾部已经没有空间,则考虑数组头部的空间是否空闲,如果是则在数组头部进行插入。
        •  1 #include <queue>
           2 #include <iostream>
           3 using namespace std;
           4  
           5 int main(){
           6     queue<int> q;
           7     for (int i = 0; i < 10; i++){
           8         q.push(i);
           9     }
          10     if (!q.empty()){
          11         cout << "队列q非空!" << endl;
          12         cout << "q中有" << q.size() << "个元素" << endl;
          13     }
          14     cout << "队头元素为:" << q.front() << endl;
          15     cout << "队尾元素为:" << q.back() << endl;
          16     for (int j = 0; j < 10; j++){
          17         int tmp = q.front();
          18         cout << tmp << " ";
          19         q.pop();
          20     }
          21     cout << endl;
          22     if (!q.empty()){
          23         cout << "队列非空!" << endl;
          24     }
          25     system("pause");
          26     return 0;
          27 }
        • 循环队列基于数组的C++实现代码如下:
        •   1 #include <iostream>
            2 #include <queue>
            3 #include <string>
            4 using namespace std;
            5  
            6 template <typename T>
            7 class LoopQueue
            8 {
            9 public:
           10     LoopQueue(int c = 10);
           11     ~LoopQueue();
           12     bool isEmpty();        //队列的判空
           13     int size();            //队列的大小
           14     bool push(T t);        //入队列
           15     bool pop();            //出队列
           16     T front();            //队首元素
           17  
           18 private:
           19     int capacity;
           20     int begin;
           21     int end;
           22     T*  queue;
           23 };
           24  
           25  
           26 template<typename T>
           27 LoopQueue<T>::LoopQueue(int c = 10)
           28     :capacity(c), begin(0), end(0), queue(nullptr)
           29 {
           30     queue = new T[capacity];
           31 };
           32  
           33 template<typename T>
           34 LoopQueue<T>::~LoopQueue()
           35 {
           36     delete[]queue;
           37 }
           38  
           39 template <typename T>
           40 bool LoopQueue<T>::isEmpty()                   //判断循环队列是否为空
           41 {
           42     if (begin == end)
           43         return true;
           44     return false;
           45 };
           46  
           47 template<typename T>
           48 int LoopQueue<T>::size()
           49 {
           50     return (end - begin + capacity) % capacity; //计算循环队列的长度
           51 };
           52  
           53 template<typename T>
           54 bool LoopQueue<T>::push(T t)
           55 {
           56     if (end + 1 % capacity == begin)            //判断队列是否已满
           57     {
           58         return false;
           59     }
           60     queue[end] = t;
           61     end = (end + 1) % capacity;
           62     return true;
           63 };
           64  
           65 template <typename T>
           66 bool LoopQueue<T>::pop()                        //判断队列是否为空
           67 {
           68     if (end == begin) 
           69     {
           70         return false;
           71     }
           72     begin = (begin + 1) % capacity;
           73     return true;
           74 };
           75  
           76 template <typename T>
           77 T LoopQueue<T>::front()
           78 {
           79     if (end == begin)
           80     {
           81         return false;
           82     }
           83     return queue[begin];
           84 };
           85  
           86 int main()
           87 {
           88     LoopQueue<string> queue(6);
           89     queue.push("one");
           90     queue.push("two");
           91     queue.push("three");
           92     queue.push("four");
           93     queue.push("five");
           94     cout << "队列长度" << queue.size() << endl;
           95     while (!queue.isEmpty())
           96     {
           97         cout << queue.front() << endl;
           98         queue.pop();
           99     }
          100     getchar();
          101     //system("pause");
          102     return 0;
          103 }

      • 基于链表的队列(链队列)
        • 链队列是基于链表实现的队列,它不存在数组的O(n)的元素移动问题和内存空间浪费问题。我们所要确定的就是链表哪头做队首,哪头做队尾。显然我们应该将链表头做队首,链表尾做队尾。存储一个指向队尾的指针,方便从链表尾插入元素,使用带头结点的链表,方便从链表头删除元素。
        • 链式队列的C++实现
          •   1 #include <iostream>
              2 #include <cstdlib>
              3 using namespace std;
              4  
              5 struct QNode    //定义队列结点的数据结构
              6 {
              7     QNode *next; //指针域,指向下一个结点
              8     double data;    //数据域,存储队列信息
              9 };
             10  
             11 struct LinkQueue    //定义队列的数据结构
             12 {
             13     QNode *front;      //队首指针,指向QNode类型的指针
             14     QNode *rear;       //队尾指针
             15 };
             16  
             17 void InitQueue(LinkQueue &Q)     //构造一个空的队列
             18 {
             19     QNode *q;
             20     q = new QNode;    //申请一个结点的空间
             21     q->next = NULL;   //当作头结点
             22     //队首与队尾指针都指向这个结点,指针域为NULL
             23     Q.front = q;
             24     Q.rear = q;
             25 }
             26  
             27 int IsEmpty(LinkQueue &Q)    //判断队列是否为空
             28 {
             29     if (Q.rear == Q.front)
             30         return 0;
             31     else
             32         return 1;
             33 }
             34  
             35 void EnQueue(LinkQueue &Q, double e)     //从队列尾部插入元素
             36 {
             37     QNode *p;    //新创建一个结点
             38     p = new QNode;
             39     p->next = NULL;
             40     p->data = e;  //输入数据信息
             41     //将新结点插入队列尾部
             42     Q.rear->next = p;
             43     Q.rear = p;       //设置新的尾结点
             44 }
             45  
             46 void DeQueue(LinkQueue &Q, double &e)   //从队列首部删除一个结点
             47 {
             48     QNode *p;
             49     p = Q.front->next;
             50     e = p->data;    //保存要出队列的数据
             51     Q.front->next = p->next;       //将下一个结点当作头结点后面链接的第一个结点
             52     if (Q.rear == p)    //如果要删除的元素即为尾结点,则将头指针赋予尾指针,一同指向头结点,表示队列为空
             53         Q.rear = Q.front;
             54     delete p;
             55 }
             56  
             57 void DestoryQueue(LinkQueue &Q)       //销毁一个队列
             58 {
             59     while (Q.front)
             60     {
             61         Q.rear = Q.front;    //从头节点开始,一个一个删除队列结点,释放空间
             62         delete Q.front;
             63         Q.front = Q.rear;
             64     }
             65 }
             66 int main()
             67 {
             68     LinkQueue *Q;  //定义一个队列Q
             69     Q = new LinkQueue;
             70     InitQueue(*Q);
             71     cout << "开始往队列里输入数据,以-1作为结束符" << endl;
             72     cout << "请输入一个数:" << endl;
             73     double a, x;
             74     cin >> a;
             75     while (a != -1)
             76     {
             77         EnQueue(*Q, a);
             78         cout << "请输入一个数:" << endl;
             79         cin >> a;
             80     }
             81     //输出队列元素,队首->队尾
             82     QNode *p;
             83     p = Q->front->next;
             84     if (p == NULL)     //如果为空表,直接退出
             85     {
             86         cout << "队列为空!" << endl;
             87         return 0;
             88     }
             89     cout << "队列数据依次为:" << endl;
             90     while (p != NULL)
             91     {
             92         cout << p->data << " ";
             93         p = p->next;
             94     }
             95     cout << endl;
             96     //删除队列元素
             97     while (!IsEmpty(*Q))
             98     {
             99         DeQueue(*Q, x);
            100         cout << x << " ";
            101     }
            102     //释放内存空间
            103     delete Q->front;
            104     delete Q;
            105     system("pause");
            106     return 0;
            107 }
          • 用单链表表示的链式队列特别适合于数据元素变化较大的情况,而且不存在溢出的情况。
          • 循环队列中判断队空的方法是front==rear,队满的方法是判断front=(real+1)%MAXSIZE。(为什么不用一个length表示队长,当length=MAXSIZE时表示队满,原因就是,在频繁的队列操作中多出一个变量会大量的增加执行时间,所以不如浪费一个数组空间划算。)
  • 相关阅读:
    pinyin4j使用示例
    迭代器模式
    适配器模式
    策略模式
    装饰模式
    责任链模式
    命令模式
    中介者模式
    原型模式
    代理模式
  • 原文地址:https://www.cnblogs.com/southcyy/p/10327173.html
Copyright © 2011-2022 走看看