1.内容小结:
栈(FILO)和队列(FIFO),是插入和删除限定在“端点”的线性表,都有顺序存储结构和链式存储结构。
1.1 栈:
栈的实现和基本操作:
1 顺序栈:
2 #define MAXSIZE 100//栈存储空间可能的最大值
3 typedef struct{
4 SElemType *base;//栈底指针
5 SElemType *top; //栈顶指针
6 int stacksize; //栈可用的最大容量
7 }SqStack;
8
9 Status InitStack(SqStack &s){
10 s.base = new SElemType[MAXSIZE];//为顺序栈分配一个最大容量
11 if(!s.base) exit(OVERFLOW); //存储空间分配失败
12 s.top = s.base; //top初始化为base,空栈
13 s.stacksize = MAXSIZE; //stacksize设置为栈的最大容量
14 return OK;
15 }
16
17 Status Push(SqStack &s, SElemType e){
18 if(s.top - s.base == s.stacksize){//栈满
19 return ERROR;
20 }
21 *s.top++ = e; //e(先)入栈,(后)栈顶指针加1
22 return OK;
23 }
24
25 Status Pop(SqStack &s, SElemType &e){
26 if(s.top == s.base){ //栈空
27 return ERROR;
28 }
29 e = *--s.top; //栈顶指针(先)减1,(后)栈顶元素赋给 e
30 }
31
32
33 链栈:
34 typedef struct StackNode{
35 ElemType data;
36 StackNode *next;
37 }StackNode, *LinkStack;
38
39 Status InitStack(LinkStack &s){//初始化空栈
40 s = NULL;
41 return OK;
42 }
43
44 Status Push(LinkStack &s, SElemType e){//考虑到栈FILO的特性,这里使用头插法添加新节点,且无需附加头节点
45 StackNode *p = new StackNode;
46 p -> data = e;
47 p ->next = s;
48 s = p;
49 return OK;
50 }
51
52 Status Pop(LinkStack &s, SElemType &e){
53 if(s == NULL) return ERROR;//栈空
54 e = s -> data;
55 StackNode *temp = s;
56 s = s -> next;
57 delete temp; //释放原栈顶元素空间
58 return OK;
59 }
栈的应用:
栈的应用有很多,这里要说的是递归。
利用栈和递归可以解决以下三类问题:
- 定义是递归的,如打印Fibonacci数列,打印n的阶乘;
- 数据结构是递归的,如本章所学的栈,以及后面要学习的广义表;
- 问题的解法是递归的,如Hanoi塔问题。
递归的优点是很可观的,逻辑清晰,代码简洁。然而,递归往往会消耗大量的时间和空间,有时候还会有重复计算的问题。
1.2 队列
队列的实现和基本操作:
1 顺序队列:
2 #define MAXSIZE 100 //队列可能的最大长度
3 typedef struct{
4 QElemType *base; //存储空间的基地址
5 int front; //头指针
6 int rear; //尾指针
7 }SqQueue;
8
9 Status IninQueue(SqQueue &q){ //初始化空队列
10 q.base = new QElemType[MAXSIZE];
11 if(!q.base) exit(OVERFLOW); //存储空间分配失败
12 q.front = q.rear = 0;
13 return OK;
14 }
15
16 Status Enter(SqQueue &q, QElemtype e){
17 if( (q.rear + 1) % MAXSIZE == q.front){//尾指针再循环意义上加1后等于头指针
18 return ERROR;//队列已满
19 }
20 q.base[q.rear] = e; //新元素插入队尾
21 q.rear = (q.rear + 1) % MAXSIZE; //队尾指针加1
22 return OK;
23 }
24
25 Status Exit(SqQueue &q, QElemtype &e){
26 if(q.front == q.rear) return ERROR;//队空
27 e = q.base[q.front];
28 q.front = (q.front + 1) % MAXSIZE;//队头指针加1
29 return OK;
30 }
31
32 链式队列:
33 typedef struct QNode{
34 QElemType data;
35 struct QNode *next;
36 }QNode;
37 typedef struct{
38 QNode *front; //队头指针
39 QNode *rear; //队尾指针
40 }LinkQueue;
41
42 Status InitQueue(LinkQueue &q){
43 q.front = q.rear = new QNode; //队头队尾指针指向头节点
44 q.front -> next = NULL;
45 return OK;
46 }
47
48 Status Enter(LinkQueue &q, QElemType e){
49 QNode *p = new QNode;
50 p -> data = e;
51 p -> next = NULL;
52 q.rear -> next = p; //将新元素节点插入队尾
53 q.rear = p;//更新尾指针
54 return OK;
55 }
56
57 Status Exit(LinkQueue &q, QElemType &e){
58 if(q.front == q.rear) return ERROR;//空队
59 QNode *p = q.front -> next; //p指向队头元素
60 e = p -> data;
61 q.front -> next = p -> next; //修改头节点的指针域
62 if(q.rear == p) q.rear = q.front; //若出队的是最后一个元素,尾指针归位
63 delete p;
64 return OK;
65 }
2.心得体会:
完成一道题目后,还要注重对时间和空间的考量,有时候题目即使没提示,也是可以通过一点小技巧节省时间和空间的。
3.资料推荐:
基础的知识可以看课本看mooc,也可以去社区或网站了解更多。
4.上阶段的完成情况及后续目标:
上阶段的目标是学好本章,基本完成,不足的是对递归还不熟悉。
后续目标当然是学好第四章啦,一步一个脚印。