1.栈的定义
定义:栈是只允许在一端进行插入和删除操作的线性表。后进先出(LIFO)
栈顶:线性表允许进行插入和删除的那一端。
栈底:固定的,不允许进行插入和删除的那一端。
卡特兰数:n个元素进栈,一共会有C(n,2n)/(n+1)种不同的出栈结果。
2.队列的定义
定义:队列也是一种操作受限的线性表,只允许在表的一端进行插入,在表的另一端进行删除。先进先出(FIFO)
队头:允许进行删除的一端,又称为队首。
队尾:允许进行插入的一端。
3.顺序栈的定义及特点
定义:采用顺序存储的栈称为顺序栈,它是利用一组连续的存储单元存放自栈底到栈顶的数据元素,同时附设一个指针(top)指示当前栈顶元素的位置。
特点:当对栈的最大使用空间估计不足时,有可能会发生栈上溢。
4.链式栈的定义及特点
定义:采用链式存储的栈称为链栈。
特点:优点是便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。在表头进行插入和删除。
5.顺序队列的定义及特点
定义:队列的顺序实现是指分配一块连续的存储单元存放队列中的元素,并附设两个指针:队头指针front指向队头元素,队尾指针rear指向队尾元素的下一个位置。
特点:连续的存储单元存放。
6.链式队列的定义及特点
定义:队列的链式表示为链队列,它实际上是一个同时带有队头指针和队尾指针的单链表。头指针指向队头结点,尾指针指向队尾结点,即单链表的最后一个结点。
特点:不存在队列溢出的情况。
7.栈的应用
(1)栈在括号匹配中的应用
遇到左括号就入栈,遇到有括号就从栈中取出一个左括号匹配。
(2)栈在表达式求值的应用
后缀表达式中,遇到数字就入栈,遇到运算符就从栈中取出两个数字运算,运算结果在放回栈中。
(3)栈在递归中的应用
条件:
(1)递归表达式(递归体)
(2)边界条件(递归出口)
递归的精髓在于能否将原始问题转换为属性相同但规模较小的问题。
优点:代码简单,容易理解。
缺点:递归次数过多容易造成栈溢出。
例题:
1 int Fib(int n){
2 if(n == 0){ //边界条件
3 return 0;
4 }
5 else if(n == 1){ //边界条件
6 return 1;
7 }
8 else{
9 return Fib(n-1) + Fib(n-2);
10 }
11 }
8.队列的应用
(1)队列在层次遍历中的应用
(2)队列在计算机系统中的应用
FCFS(先来先服务)
9.顺序存储结构对栈基本操作的实现
(1)结构体定义
1 #define MaxSize 50
2 typedef struct{
3 ElemType data[MaxSize];
4 int top;
5 }SqStack;
(2)栈的初始化
1 void InitStack(SqStack &S){
2 S.top = -1;
3 }
(3)进栈
1 bool Push(SqStack &S, ElemType x){
2 if(S.top == MaxSize -1){
3 return false;
4 }
5 S.data[++S.top] = x;
6 return true;
7 }
(4)出栈
1 bool Pop(SqStack &S, ElemType &e){
2 if(S.top == -1){
3 return false;
4 }
5 e = S.data[S.top--];
6 return true;
7 }
10.顺序存储结构对队列基本操作的实现
(1)结构体的定义
1 #define MaxSize 50
2 typedef struct{
3 ElemType data[MaxSize];
4 int front,rear;
5 }SqQueue;
(2)队列判空
1 bool isEmpty(SqQueue Q){
2 if(Q.rear == Q.front)
3 return true;
4 else
5 return false;
6 }
11.链式存储结构对栈基本操作的实现
(1)结构体定义
1 typedef struct Linknode{
2 ElemType data;
3 struct Linknode *next;
4 }*LiStack
12.链式存储结构对队列基本操作的实现
(1)结构体定义
1 typedef struct{ //链式队列结点
2 ElemType data;
3 struct LinkNode *next;
4 }LinkNode;
5 typedef struct{ //链式队列指针
6 LinkNode *front,*rear;
7 }LinkQueue;
(2)链式队列初始化
1 void InitQueue(LinkQueue &Q){
2 Q.front = Q.rear = (LinkNode *)malloc(sizeof(LinkNode));
3 Q.front ->next = NULL;
4 }
(3)链式队列入队
1 void EnQueue(LinkQueue &Q, ElemType x){
2 LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
3 s->data = x;
4 s->next = NULL;
5 Q.rear->next = s;
6 Q.rear = s;
7 }
(4)链式队列出队
1 bool DeQueue(LinkQueue &Q, ElemType &e){
2 if(Q.front == Q.rear) //空队
3 return false;
4 LinkNode *p = Q.front->next; //p->队头元素
5 e = p->data;
6 Q.front->next = p->next;
7 if(Q.rear == p){
8 Q.rear = Q.front;
9 }
10 free(p);
11 return true;
12 }
13.顺序存储结构中实现循环队列
初始化:Q.front = Q.rear = 0
出队:Q.front = (Q.front+1)%MaxSize
入队:Q.rear = (Q.rear+1)%MaxSize
为了区分队空队满的三种方式:
(1)牺牲一个单元来区分队空和队满(队头指针在队尾指针的下一个位置作为队满的标志)
(2)类型中新增表示元素个数的数据成员。如Q.size = 0等。
(3)类型中新增tag数据成员,以区分是队满还是队空。
tag=0时,front=rear表示队空;
tag=1时,front=rear表示队满;
(1)循环队列入队
1 bool EnQueue(SqQueue &Q, ElemType x){
2 if((Q.rear+1)%MaxSize == Q.front){
3 return false;
4 }
5 Q.data[Q.rear] = x;
6 Q.rear = (Q.rear+1)%MaxSize;
7 return true;
8 }
(2)循环队列出队
1 bool DeQueue(SqQueue &Q, ElemType &e){
2 if(Q.rear == Q.front){
3 return false;
4 }
5 e = Q.data[Q.front];
6 Q.front = (Q.front-1)%MaxSize;
7 return true;
8 }