栈和队列
栈的基本概念
- 栈(Stack)是只允许在一端进行插入或删除操作的线性表
- 逻辑结构:与普通线性表相同
- 栈的基本操作:
(1)InitStack(&S):初始化栈。构造一个空栈 S,分配内存空间。
(2)DestroyStack(&S):销毁栈。销毁并释放栈 S 所占用的内存空间。
(3)Push(&S,x):进栈,若栈S未满,则将x加入使之成为新栈顶。
(4)Pop(&S,&x):出栈,若栈S非空,则弹出栈顶元素,并用x返回。
(5)GetTop(S, &x):读栈顶元素。若栈 S 非空,则用 x 返回栈顶元素 - 其他常用操作:
(6)StackEmpty(S):判断一个栈 S 是否为空。若S为空,则返回true,否则返回false - n个不同元素进栈,出栈元素不同排列的个数为 {(2n)!/n!} / {(n+1)}
栈的顺序存储实现(静态数组)
栈的定义
#define MaxSize 10//定义栈中最大个数
typedef int Elemtype;
typedef struct {
Elemtype data[MaxSize]; //静态数组存放栈中元素
int top; //栈顶指针
} SqStack;
栈的初始化以及是否为空
// 初始化
void InitStack(SqStack &S) {
// ①第一种方式 ,S.top=-1,当Stack中有数据时,top指向的地方就是有数据的
S.top = -1;
// ②第二种方式,S.top=0,当Stack中有数据时,top指向的地方是没有数据的
}
//判断是否为空
bool IsStack(SqStack S) {
if (S.top == -1) { // S.top=0为第二种方式
return true;
} else {
return false;
}
}
进栈、出栈、取栈顶元素
bool Push(SqStack &S, Elemtype e) {
if (S.top == MaxSize-1 ) { // S.top==MaxSize为第二种方式
return false;
}
S.data[++S.top] = e; //因为开始S.top==-1,保证top指的地方有数据则指针先+1后存入数据
//S.data[S.top++]=e;因为开始S.top==0,保证top指的地方没有数据则先存入数据后指针+1
return true;
}
bool Pop(SqStack &S,Elemtype &e){
if(S.top==-1){ //S.top==0为第二种方式
return false;
}
e=S.data[S.top--];//因为S.top==-1为空且S.top指向的地方有数据故先取数据后移动指针
// e=S.data[--S.top];因为S.top==0为空且S.top指向的地方无数据故先移动指针后取数据。
return true;
}
bool GetTop(SqStack S,Elemtype &e){
if(S.top==-1){ //S.top==0为第二种方式
return false;
}
e=S.data[S.top]; //因为S.top==-1为空且S.top指向的地方有数据故直接取元素
// e=S.data[S.top-1];因为S.top==0为空且S.top指向的地方无数据故先移动指针后取数据。
}
栈的顺序存储实现(共享栈课本)
栈的定义
#define MaxSize 10//定义栈中最大个数
typedef int Elemtype;
typedef struct {
Elemtype *base; //栈底指针
Elemtype *top; //栈顶指针
int stackSize; //栈的大小
} SqStack;
栈的初始化以及是否为空
bool InitStack(SqStack &S) {
S.base = new Elemtype[MaxSize]; //动态生成一片连续的区域
if (!S.base) { //未创建成功返回false
return false;
}
S.top = S.base; // 栈顶指针与栈底指针指向同一片区域如图(a)均指向第一个元素且为空
S.stackSize = MaxSize; //栈的大小为最大数值
return true;
}
bool IsEmpty(SqStack S) {
if (S.top == S.base) {
return true;
} else {
return false;
}
}
进栈、出栈、取栈顶元素
bool Push(SqStack &S, Elemtype e) {
if (S.top - S.base == S.stackSize) { //栈满了
return false;
}
*S.top++ = e; //为保证top所指区域无数值,所以先赋值后指针+1
return true;
}
bool Pop(SqStack &S, Elemtype &e) {
if (S.top == S.base) { //栈空
return false;
}
e = *--S.top;
return true;
}
Elemtype GetTop(SqStack S) {
if (S.top != S.base) {
return *(S.top - 1);
} else {
return false;
}
}
链栈的表示和实现
链栈的定义
typedef int Elemtype;
typedef struct StackNode {
Elemtype data;
StackNode *next;
} StackNode, *LinkStack;
链栈的初始化以及是否为空
bool InitLinkStack(LinkStack &S) {
S = NULL; //栈顶指针为空
return true;
}
bool IsEmpty(LinkStack S) {
if (S == NULL) {
return true;
} else {
return false;
}
}
进栈、出栈、取栈顶元素
)
bool Push(LinkStack &S, Elemtype e) {
StackNode *p;
p = new StackNode(); //生成新的节点
p->data = e; //值为e
p->next = S; //将新节点插入栈顶
S = p; // 修改栈顶指针为p
return true;
}
bool Pop(LinkStack &S, Elemtype &e) {
StackNode *p; //p临时保存栈顶元素以备释放
if (S == NULL) { //栈空
return false;
}
e = S->data;
p = S;
S = S->next; //修改指针
delete p; //释放栈顶元素
return true;
}
Elemtype GetTop(LinkStack S) {
if (S != NULL) { //栈非空
return S->data;
}
}
队列的基本概念
队列(Queue) 是只允许在一端进行插入,在另一端删除的线性表
特点 :先进先出
队列的基本操作
(1)InitQueue(&Q):初始化队列,构造一个空队列Q。
(2)DestroyQueue(&Q):销毁队列。销毁并释放队列Q所占用的内存空间。
(3)EnQueue(&Q,x):入队,若队列Q未满,将x加入,使之成为新的队尾。
(4)DeQueue(&Q,&x):出队,若队列Q非空,删除队头元素,并用x返回。
(5)GetHead(Q,&x):读队头元素,若队列Q非空,则将队头元素赋值给x。
其他常用操作:
(6)QueueEmpty(Q):判队列空,若队列Q为空返回true,否则返回false
循环队列的顺序表表示和实现(动态数组)
循环队列的定义
#define Elemtype int
#define MaxSize 10//定义栈中最大个数
typedef struct {
Elemtype *base; //存储空间的基地址
int font; //队头指针
int rear; //队尾指针
} SqQueue;
循环队列的初始化以及判空
bool InitSqQueue(SqQueue &Q) {
Q.base = new Elemtype[MaxSize]; //动态生成储存空间
if (!Q.base) { //判断是都动态生成成功
return false;
}
Q.front = Q.rear = 0; //对头队尾均指向第一个元素位置
return true;
}
bool IsEmpty(SqQueue Q) {
if (Q.rear == Q.front) {
return true;
} else {
return false;
}
}
循环队列的入队、出队、取队头、求队长
bool EnQueue(SqQueue &Q,Elemtype e){
if((Q.rear+1)%MaxSize==Q.front){ //判断是否队满
return false;
}
Q.base[Q.rear]=e; //新元素插入队尾
Q.rear=(Q.rear+1)%MaxSize; //队尾指针加1
return true;
}
bool DeQueue(SqQueue &Q,Elemtype &e){
if(Q.front==Q.rear){ //判断是否队空
return false;
}
e=Q.base[Q.front]; //保存队头元素
Q.front=(Q.front+1)%MaxSize; //队头指针加1
return true;
}
Elemtype GetHead(SqQueue Q){
if(Q.front!=Q.rear){ //判断是否队空
return Q.base[Q.front]; //返回队头元素的值,队头指针不变
}
}
int SqQueueLen(SqQueue Q){
return (Q.rear-Q.front+MaxSize)%MaxSize;
}
队列的链式表示和实现(带头结点推荐)
链式队列的定义
#define Elemtype int
#define MaxSize 4//定义栈中最大个数
typedef struct QNode {
Elemtype data;
struct QNode *next;
} QNode,*QueuePtr;
typedef struct {
QueuePtr front; //对头指针
QueuePtr rear; //队尾指针
}LinkQueue;
链式队列的初始化以及判空
bool InitSqQueue(LinkQueue &Q) {
Q.rear = Q.front = new QNode(); //生成新结点作为头结点,队头和队尾指针指向此结点
Q.front->next = NULL; //头结点的指针域置空
return true;
}
bool IsEmpty(LinkQueue Q) {
if (Q.front == Q.rear) {
return true;
} else {
return false;
}
}
链式队列的入队、出队、取队头
bool EnQueue(LinkQueue &Q, Elemtype e) {
QNode *p;
p = new QNode(); //为入队元素分配结点空间,用指针p指向
p->data = e; //将新结点数据域置为e
p->next = NULL; //将新结点插入到队尾
Q.rear->next = p; //修改队尾指针
Q.rear = p;
return true;
}
bool DeQueue(LinkQueue &Q, Elemtype &e) {
QNode *p = Q.front->next; //p指向队头元素以备释放
if (Q.front == Q.rear) { //判断是否队空
return false;
}
e = Q.front->data; //取元素值
Q.front->next = p->next; //头结点指向下一个节点
if (Q.rear == p) { //最后一个元素被删, 队尾指针指向头结点
Q.rear = Q.front;
}
delete p;
return true;
}
Elemtype GetHead(LinkQueue Q) {
if (Q.front != Q.rear) { //判断是否队空
return Q.front->next->data; //返回队头元素的值,队头指针不变
}
}
队列的变种
双端队列:允许从两端插入、两端删除的队列
输入受限的双端队列:允许从两端删除、从一端插入的队列
输出受限的双端队列:允许从两端插入、从一端删除的队列
考点: 对输出序列合法性的判断 (在栈中合法的输出序列,在双端队列中必定合法)
栈的应用
栈在括号匹配的应用
问题描述:给定一个字符串,其中的字符只包含三种括号:花括号{}、中括号[]、圆括号(),即它仅由“()[]{}” 这六个字符组成。 设计算法,判断该字符串是否有效,即字符串中括号是否匹配。括号匹配要求括号必须以正确的顺序配对,如“{()}” 或“[({}[])]” 等为正确的格式,而“[(])” 或“{[()]” 或“({}])” 均为不正确的格式。
#include <iostream>
#include "stack"
using namespace std;
int main() {
char ch;
int flag = 1;
stack<char>S;
cin >> ch;
while (ch != '#' && flag){
switch (ch) { //左括号全部入栈
case '(':
case '{':
case '[':S.push(ch);break;
//右括号与栈顶元素匹配,匹配成功则栈顶出栈,反之flag标记为0
case ')':if(!S.empty()&&S.top()=='('){
S.pop();
} else
flag=0;
break;
case ']':if(!S.empty()&&S.top()=='['){
S.pop();
} else
flag=0;
break;
case '}':if(!S.empty()&&S.top()=='{'){
S.pop();
} else
flag=0;
break;
}
cin>>ch;
}
//栈空且flag为1匹配成功
if(S.empty()&&flag==1){
cout<<"匹配成功"<<endl;
}else{
cout<<"匹配失败"<<endl;
}
return true;
}