【考纲内容】
(1). 栈和队列的基本概念
(2). 栈和队列的顺序存储结构
(3). 栈和队列的链式存储结构
(4). 栈和队列的应用
【知识框架】
【复习提示】
(1). 本章通常以选择题的形式考查,题目不算难,但命题的形式比较灵活
(2). 其中,栈(出入栈的过程 、出栈序列的合法性)和队列的操作及其特征是考查重点
(3). 栈和队列都是线性表的应用和推广,因此也容易出现在算法设计题中
(4). 此外,栈和队列的顺序存储 、链式存储及其特点 、双端队列的特点 、栈和队列的常见应用,以及数组和特殊矩阵的压缩存储都是必须要掌握的内容
栈是一种操作受限的线性表,类似于线性表,栈也有两种存储方式
概念 | 采用顺序存储的栈,称为顺序栈 |
顺序栈的实现 | (i). 利用一组地址连续的存储单元,存放从栈底到栈顶的数据元素 (ii). 附设一个指针(top)指向当前栈顶元素的位置 所谓指针,其实是一个整数,保存栈顶元素的下标 |
栈的顺序存储 类型描述 |
#define MaxSize 50 // 定义栈中元素的最大个数 typedef struct { ElemType data[MaxSize]; // 存放栈中元素 int top; // 栈顶指针 } SqStack; |
栈顶指针 | S->top ,初始状态设置为 S->top = -1 |
栈顶元素 | S->data[S->top] |
进栈操作 | 栈不满时,先将栈顶指针 top 加 1 ,再将值插入新的栈顶位置; S->top++; S->data[S->top] = x; |
出栈操作 | 栈非空时,先获取栈顶元素,再将栈顶指针减 1 ; x = S->data[S->top]; S->top--; |
栈空条件 | 判断 S->top == -1 |
栈满条件 | 判断 S->top == MaxSize - 1 |
栈长 (实际元素个数) |
S->top + 1 |
说明 | 由于顺序栈的入栈操作受数组上限的约束,当对栈的最大使用空间估计不足时, 有可能发生栈上溢,此时应及时向用户报告消息,以便及时处理,避免出错 |
注意 | 栈和队列的判空 、判满条件,会因具体实现而不同,上面提到的方法以及下面的代码 实现只是在栈顶指针设定的条件下的相应方法 top == -1 为栈空条件,这是接口代码实现的前提 |
下面是顺序栈上常用的基本运算的实现
注意:假如存储空间是在栈空间或静态空间上分配的,则无需手动销毁
#define INIT_SIZE 50
#define INCREASEMENT_SIZE 10
#define OK 1
#define ERROR -1
#define YES 1
#define NO 0
typedef int Status;
typedef int ElemType;
typedef struct {
ElemType *data;
int top;
} SeqStack;
/*
* 初始化
*/
Status Init(SeqStack *S)
{
S->data = (ElemType*)malloc(sizeof(ElemType) * INIT_SIZE);
if (S->data == NULL)
{
printf("Out of memory !\n");
return ERROR;
}
S->top = -1;
return OK;
}
/*
* 判栈空
*/
Status Empty(SeqStack *S)
{
if (S->top == -1)
return YES;
else
return NO;
}
/*
* 进栈
*/
Status Push(SeqStack *S, ElemType x)
{
if (S->top == INIT_SIZE - 1)
return ERROR;
S->top++;
S->data[S->top] = x;
return OK;
}
/*
* 出栈
*/
Status Pop(SeqStack *S, ElemType *x)
{
if (S->top == -1)
return ERROR;
*x = S->data[S->top];
S->top--;
return OK:
}
/*
* 获取栈顶元素
*/
Status GetTop(SeqStack *S, ElemType *x)
{
if (S->top == -1)
return ERROR;
*x = S->data[S->top];
return OK;
}
/*
* 销毁栈
*/
Status Destroy(SeqStack *S)
{
free(S->data);
S->data = NULL;
return OK;
}
#include
#include
#include
#include
using namespace std;
#define MaxSize 50
using ElemType = int;
class Stack
{
public:
Stack() = default;
Stack(int initsize);
~Stack();
bool empty();
void push(ElemType x);
void pop();
ElemType getop();
private:
ElemType *elem;
int top;
};
int main(int argc, char* argv[])
{
Stack stack{10};
stack.push(2);
stack.push(3);
stack.push(7);
stack.push(11);
stack.push(13);
std::cout << stack.getop() << std::endl;
stack.pop();
std::cout << stack.getop() << std::endl;
stack.pop();
std::cout << stack.getop() << std::endl;
stack.pop();
return 0;
}
/* 构造函数 */
Stack::Stack(int initsize)
: top(-1)
{
elem = new ElemType[initsize];
std::cout << "Construct" << std::endl;
}
/* 析构函数 */
Stack::~Stack()
{
delete[] elem;
std::cout << "Destroy" << std::endl;
}
/* 判栈空 */
bool Stack::empty()
{
return top == -1;
}
/* 进栈 */
void Stack::push(ElemType x)
{
if (top == MaxSize - 1)
{
std::cout << "Stack is full !\n" << std::endl;
return;
}
std::cout << "push element is " << x << std::endl;
++top;
elem[top] = x;
}
/* 出栈 */
void Stack::pop()
{
if (top == -1)
{
std::cout << "Stack is empty !\n" << std::endl;
return;
}
std::cout << "pop element is " << elem[top] << std::endl;
top--;
}
/* 获取栈顶元素 */
ElemType Stack::getop()
{
if (top == -1)
{
std::cout << "Stack is empty !\n" << std::endl;
return ElemType{};
}
return elem[top];
}
(1). 链式栈的描述
#include
#include
typedef int ElemType;
struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;
struct Node
{
ElemType Elem;
Position Next;
};
List InitStack(List L);
int Empty(List L);
void PrintEmpty(List L);
void Push(List L, ElemType E);
void Pop(List L);
ElemType Top(List L);
void PrintTop(List L);
void DestroyStack(List L);
int main(int argc, char* argv[])
{
List L = NULL;
L = InitStack(L);
PrintEmpty(L);
Push(L, 2);
Push(L, 3);
Push(L, 5);
Push(L, 7);
Push(L, 11);
Push(L, 13);
PrintEmpty(L);
/*
PrintTop(L);
Pop(L);
PrintTop(L);
Pop(L);
PrintTop(L);
Pop(L);
PrintTop(L);
Pop(L);
PrintTop(L);
Pop(L);
*/
DestroyStack(L);
PrintEmpty(L);
return 0;
}
List InitStack(List L)
{
L = (List)malloc(sizeof(struct Node));
if (!L)
return NULL;
L->Next = NULL;
return L;
}
int Empty(List L)
{
return L->Next == NULL;
}
void PrintEmpty(List L)
{
if (Empty(L) != 0)
printf("Empty\n");
else
printf("Not Empty\n");
}
void Push(List L, ElemType E)
{
Position NewCell;
NewCell = (Position)malloc(sizeof(struct Node));
if (NewCell == NULL)
{
printf("Out of memory!\n");
exit(0);
}
NewCell->Elem = E;
NewCell->Next = L->Next;
L->Next = NewCell;
}
void Pop(List L)
{
Position TmpCell = NULL;
if (L->Next == NULL)
{
printf("Empty Stack!\n");
return;
}
TmpCell = L->Next;
L->Next = TmpCell->Next;
free(TmpCell);
return;
}
ElemType Top(List L)
{
ElemType data;
if (L->Next == NULL)
{
printf("Empty Stack!\n");
return data;
}
data = L->Next->Elem;
return data;
}
void PrintTop(List L)
{
ElemType Elem = Top(L);
printf("Top Elem is %d\n", Elem);
}
void DestroyStack(List L)
{
Position P, TmpCell;
P = L->Next;
L->Next = NULL;
while (P != NULL)
{
TmpCell = P->Next;
printf("Current destroyed element is %d\n", P->Elem);
free(P);
P = TmpCell;
}
}
初始设置一个空栈 | |
bool isValid(string s)
{
if (s.size() % 2 == 1)
{
return false;
}
std::stack chStack;
for (auto ch : s)
{
switch (ch)
{
case '(':
case '[':
case '{':
chStack.push(ch);
break;
case ')':
if (chStack.empty() == true || chStack.top() != '(')
return false;
else
chStack.pop();
break;
case ']':
if (chStack.empty() == true || chStack.top() != '[')
return false;
else
chStack.pop();
break;
case '}':
if (chStack.empty() == true || chStack.top() != '{')
return false;
else
chStack.pop();
break;
default:
return false;
}
}
return chStack.empty();
}
队列的基本概念 | |
队列的定义 | 队列(Queue)简称 "队" ,也是一种操作受限的线性表 |
只允许在线性表的一端进行插入,在线性表的另一端进行删除 | |
入队 | 向线性表的可以插入元素的一端,插入元素,称为 " 入队或进队 " |
出队 | 从线性表的可以删除元素的一端,删除元素,称为 " 出队或离队 " |
队列特性 | 最早入队的元素,也是最早出队 特点就是 " 先进先出 "(First In First Out,FIFO) |
队头(Front) | 允许删除元素的一端,又称队首 |
队尾(Rear) | 允许插入元素的一端 |
空队列 | 不含任何元素的空线性表 |
队列常见的基本操作 | |
InitQueue(&Q) | 初始化队列,构造一个空队列 |
QueueEmpty(Q) | 判别队列是否为空,队列为空返回 true ,队列不为空返回 false |
EnQueue(&Q, x) | 入队,若队列 Q 未满,将元素 x 插入队尾,并使 x 成为新的队尾元素 |
DeQueue(&Q, &x) | 出队,若队列 Q 非空,删除对头元素,并用元素 x 返回 |
GetHead(Q, &x) | 读取对头元素,若队列 Q 非空,则将对头元素赋值给元素 x |
注意 | 栈和队列都是操作受限的线性表; 因此,不是任何对线性表的操作都可以作为栈和队列的操作; 比如,不可以随便读取栈或队列中间的某个元素 |