【数据结构-栈和队列】详解栈和队列(代码+STL+原理)
一、栈的应用
栈是一种先进后出(FILO)的数据结构
1.1 栈的操作实现
清空(clear):
// 栈的清空操作就是把栈顶top置为-1 void clear(){top=-1; } // 清空栈,由于没有直接用于清空栈的元素,所以使用while和pop组合 while(!st.size()) st.pop();
获取栈内元素个数(size):
// 由于栈顶指针top始终指向栈顶元素,而下标是从0开始的,所以栈内元素要把top+1 int size(){return top+1; }
判空(empty):
// 由栈顶指针top判断的定义可知,仅当top==-1是为空,返回true,否则返回false bool empty(){if(top==-1) return true; //栈空else return false; //栈非空 }
进栈(push):
// push(x)操作将元素x置于栈顶,由于top始终指向栈顶元素,所以需要把top+1然后再把x存入top位置 void push(int x){st[++top]=x; }
出栈(pop):
// pop()操作将栈顶元素出栈,而事实上可以将栈顶指针-1来实现这个效果 void pop(){top--; }
取栈顶元素(top):
// 由于栈顶指针top始终指向栈顶元素,所以st[top]就是栈顶元素 int top(){return st[top]; }
1.2 STL中stack的常见用法
栈,后进先出(FILO)
stack的定义:
// 定义一个stack需要添加头文件#include <stack> stack<int> st;
stack容器内的元素访问:
// 只能通过top()函数来访问栈顶元素 st.top();
push()函数:
// push(x)将x入栈 st.push(1);
top()函数:
// top()函数获得栈顶元素 st.top();
pop()函数:
// 使用pop()函数弹出栈顶元素 st.pop();
empty()函数:
// empty()可以检测stack内是否为空,true为空,false为非空 if(st.enpty()==true)
size()函数:
// 通过size()函数来获得栈的元素个数 st.size();
1.3 使用队列实现栈
class MyStack {
public:/** Initialize your data structure here. */MyStack() {}/** Push element x onto stack. */void push(int x) {queue<int> tempQ;tempQ.push(x);while(!data.empty()) {tempQ.push(data.front());data.pop();}while(!tempQ.empty()){data.push(tempQ.front());tempQ.pop();}}/** Removes the element on top of the stack and returns that element. */int pop() {int ans = data.front();data.pop();return ans;}/** Get the top element. */int top() {return data.front();}/** Returns whether the stack is empty. */bool empty() {return data.empty();}
private:queue<int> data;
};
二、队列
队列是一种先进先出的数据结构,通常用一个队首元素front指向 队首元素的前一个位置, 而使用队尾指针来指向队尾元素。
初始状态(队空条件)∶$Q.front() ==Q.rear()==0 $
进队操作∶队不满时,先送值到队尾元素,再将队尾指针加1
出队操作∶队不空时,先取队头元素值,再将队头指针加1
但 Q.rear()==sizeQ.rear() == sizeQ.rear()==size 不能作为队满的条件。
如下图所示,Q.rear()==sizeQ.rear() == sizeQ.rear()==size 满足前面的条件,但是显然,整个队列还有可以添加的其他元素的(未满)
2.1 队列的操作实现
清空(clear):
// 使用数组来实现队列是,初始状态为front=-1,rear=-1 void clear(){front=rear=-1; }
获得队列中的元素个数(size):
// rear-front是队列内元素的个数 int size(){return rear-front; }
判空(empty):
// 若rear等于front,则队列为空 bool empty(){if(front==rear) return true;else return false; }
入队(push):
// 入队,由于指针rear指向队尾元素,因此把元素入队时,需要先把rear+1,在存放到rear指向的位置 void push(int x){q[++rear]=x; }
出队(pop):
// 直接把队首指针加1来实现出队效果 void pop(){front++; }
取队首元素(get_front):
// 由于队首指针front指向的队首元素的前一个元素,因此front+1才是队首元素的位置 int get_front(){return q[front+1]; }
取队尾元素(get_rear):
// 由于队尾指针rear指向的队尾元素,因此直接访问rear是队尾元素的位置 int get_rear(){return q[rear]; }
2.2 STL中queue的常见用法
- 判断队列是否为空
Q.empty()
- 返回队列头部元素
Q.front()
- 返回队列尾部元素
Q.back()
- 弹出队列头部元素
Q.pop()
- 将x添加至队列
Q.push(x)
- 返回队列的存储元素的个数
Q.size()
2.3 使用栈实现队列
class MyQueue {
public:/** Initialize your data structure here. */MyQueue() {}/** Push element x to the back of queue. */void push(int x) {stack<int> tempS;while(!data.empty()) {tempS.push(data.top());data.pop();}tempS.push(x);while(!tempS.empty()){data.push(tempS.top());tempS.pop();}}/** Removes the element from in front of queue and returns that element. */int pop() {int ans = data.top();data.pop();return ans;}/** Get the front element. */int peek() {return data.top();}/** Returns whether the queue is empty. */bool empty() {return data.empty();}
private:stack<int> data;
};
2.4 循环队列
如前面所讲,队列在判断队满的情况下力有不逮,所以就引出了循环队列。
将循环队列想象成一个环状的空间,即在逻辑上视为一个环。
初始时:Q.front==Q.rear==0Q.front==Q.rear==0Q.front==Q.rear==0
队首指针进1:Q.front=(Q.front+1)%MaxSizeQ.front=(Q.front+1)\%MaxSizeQ.front=(Q.front+1)%MaxSize
队尾指针进1:Q.rear=(Q.rear+1)%MaxSizeQ.rear=(Q.rear+1)\%MaxSizeQ.rear=(Q.rear+1)%MaxSize
队列长度:len=(Q.rear+MaxSize−Q.front)%MaxSizelen=(Q.rear+MaxSize-Q.front)\%MaxSizelen=(Q.rear+MaxSize−Q.front)%MaxSize
为了区分队空还是队满的情况,有三种处理方式∶
牺牲一个单元来区分队空和队满,入队时少用一个队列单元,这是一种较为普遍的做法,约定以**“队头指针在队尾指针的下一位置作为队满的标志”**,如图下图e所示。
队满条件:(Q.rear+1)%MaxSize==Q.front(Q.rear+1)\%MaxSize==Q.front(Q.rear+1)%MaxSize==Q.front
队空条件仍:Q.front==Q.rearQ.front==Q.rearQ.front==Q.rear
队列中元素的个数:(Q.rear−Q.front+MaxSize)%MaxSize(Q.rear-Q.front+MaxSize)\% MaxSize(Q.rear−Q.front+MaxSize)%MaxSize
类型中增设表示元素个数的数据成员。这样,队空的条件为 Q.size==0Q.size==0Q.size==0;队满的条件为 Q.size==MaxSizeQ.size==MaxSizeQ.size==MaxSize;这两种情况都有 Q.front==Q.rearQ.front==Q.rearQ.front==Q.rear 。
类型中增设 tag 数据成员,以区分是队满还是队空。tag==0tag == 0tag==0 时,若因删除导致 Q.front==Q.rearQ.front==Q.rearQ.front==Q.rear,则为队空;tag==1tag==1tag==1 时,若因插入导致 Q.front==Q.rearQ.front==Q.rearQ.front==Q.rear,则为队满。
- 初始化
void InitQueue(SqQueue &Q){Q.rear=Q.front=0; // 初始化队首、队尾指针
}
- 判队空
bool isEmpty(SqQueue &Q){if(Q.rear==Q.front) return true; // 队空条件else return false;
}
- 入队
bool EnQueue(SqQueue &Q,ElemType x){if ((Q.rear+1)%MaxSize==Q.front) return false; // 队满 Q.data[Q.rear]=x; Q.rear= (Q.rear+1)%MaxSize; // 队尾指针加 1 取模return true;
}
- 出队
bool DeQueue(SqQueue sQ,ElemType x){if(Q.rear==Q.front) return false; //队空,报错x=Q.data[Q.front];Q.front=(Q.front+1)%MaxSize; //队头指针加 1 取模return true;
}
2.5 双端队列
双端队列是指允许两端都可以进行入队和出队操作的队列,
输出受限的双端队列∶允许在一端进行插入和删除,但在另一端只允许插入的双端队列称为输出受限的双端队列,如下图
输入受限的双端队列∶允许在一端进行插入和删除,但在另一端只允许删除的双端队列称为输入受限的双端队列,如下图
三、STL容器中的queue和priority queue的实现方式
priority_queue<int> big_heap;//默认构造是最大堆
priority_queue<int, vector<int>, greate<int> > small_heap; //最小堆构造方法
priority_queue<int, vector<int>, less<int> > big_heap2;//最大堆构造方法big_heap.empty() // 判断堆是否为空
big_heap.pop() // 弹出堆顶元素(最大值)
big_heap.push(x) // 将元素x添加至二叉堆
big_heap.top() // 返回堆顶元素(最大值)
big_heap.size() // 返回堆中元素个数
【数据结构-栈和队列】详解栈和队列(代码+STL+原理)相关推荐
- php循环取redis队列,详解Redis和队列
下面由Redis教程栏目给大家详解Redis和队列,希望对需要的朋友有所帮助! 概要 Redis不仅可作为缓存服务器,还可用作消息队列.它的列表类型天生支持用作消息队列.如下图所示: 由于Redis的 ...
- java 消息队列详解_Java消息队列-Spring整合ActiveMq的详解
本篇文章主要介绍了详解Java消息队列-Spring整合ActiveMq ,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 1.概述 首先和大家一起回顾一下Java 消息服 ...
- 数据结构《顺序栈》知识点详解+C语言完整代码-超详细
顺序栈 栈 1. 定义 2. 逻辑结构 3. 存储结构 4. 运算规则 5. 实现方式 C语言代码实现 1. 顺序栈的表示 2. 结构体 3.初始化 4.入栈 5.出栈 6. 取栈顶元素 7.求长 8 ...
- 【数据结构-树】3.详解二叉排序树(理论+代码)
二叉排序树 二叉排序树的定义 二叉排序树也称为二叉查找树.二叉排序树或者是一棵空树,或者是一棵具有如下特性的非空为茶树 若左子树非空,则左子树所有结点关键字值均小于根结点的关键字值 若右子树非空,则右 ...
- HBase数据结构与基本语法详解
HBase数据结构与基本语法详解.背景: 阅读新闻 [日期:2019-01-06] 来源:Linux社区 作者:Linux [字体:大 中 小] HBase中的表一般有这样的特点: 1 大:一个表可以 ...
- 【数据结构与算法】详解什么是图结构,并用代码手动实现一个图结构
本系列文章[数据结构与算法]所有完整代码已上传 github,想要完整代码的小伙伴可以直接去那获取,可以的话欢迎点个Star哦~下面放上跳转链接 https://github.com/Lpyexplo ...
- C/C++堆、栈及静态数据区详解
五大内存分区 在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区.下面分别来介绍: 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区.里面 ...
- 堆、栈及静态数据区详解
堆.栈及静态数据区详解 五大内存分区 在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区. 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储 ...
- 40000+字超强总结?阿里P8把Java全栈知识体系详解整理成这份PDF
40000 +字长文总结,已将此文整理成PDF文档了,需要的见文后下载获取方式. 全栈知识体系总览 Java入门与进阶面向对象与Java基础 Java 基础 - 面向对象 Java 基础 - 知识点 ...
- JavaScript数据结构与算法——队列详解(下)
接下来会借助本人另一篇文章JavaScript数据结构与算法--队列详解(上)中实现的队列类及其方法实现一个应用. 配对问题 需求分析:在一个文件中保存着一份男女混合的数据,名称前以B开头表示男士,以 ...
最新文章
- 字符串json怎么把双引号去掉_Java Json字符串的双引号("")括号如何去掉
- aws lambda使用_使用AWS Lambda安排Slack消息
- Java 性能优化的 45 个细节
- ubuntu升级python_ubuntu升级python版本
- 除了数据还是数据?2018年5大 AI (人工智能)预测
- 关于css position和scroll事件的一些理解
- 机房收费系统=三层+设计模式
- 马路军团求职平台用户需求
- 修改Cmder命令提示符
- html访问手机相册,使用HTML5的FileReader读取手机图片(还可选择拍照), 并自动异步上传到服务器上...
- Integer的缓存机制
- linux实验报告makefile,linux实验二交叉编译和Makefile实验报告.doc
- Java Kafka 简单示例
- C#Redis 事务操作
- 曼彻斯特编码_网络工程师考点集锦(数字编码和编码效率)
- 2019最新版Eclipse下载与安装
- android交叉编译工具链,NDK 交叉编译工具链使用
- 科学道德与学风-2021雨课堂答案-第5章
- 【Java】Java基础之Lambda表达式和Stream流
- 5G SA的网络架构和关键技术