栈(基于数组&基于链表)与队列(基于数组&基于链表)
Posted southcyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了栈(基于数组&基于链表)与队列(基于数组&基于链表)相关的知识,希望对你有一定的参考价值。
一、栈
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时表示队满,原因就是,在频繁的队列操作中多出一个变量会大量的增加执行时间,所以不如浪费一个数组空间划算。)
-
-
以上是关于栈(基于数组&基于链表)与队列(基于数组&基于链表)的主要内容,如果未能解决你的问题,请参考以下文章
算法漫游指北(第五篇):栈队列栈结构实现基于列表实现栈基于链表实现栈基于列表实现队列基于链表实现队列