《大话数据结构》 阅读整理
栈和队列
栈的定义
定义
栈是限定仅在表尾进行插入和删除操作的线性表
性质
允许插入和删除的一端称为栈顶 另一端称为栈底
不含任何数据元素的栈称为空栈
后进先出 LIFO结构
栈的插入操作叫做进栈 压栈 入栈
栈的删除操作叫做 出栈 弹栈
栈的顺序存储结构
顺序栈的定义
定义一个top变量用来存放栈顶元素的位置
1 2 3 4 5 6
| typedef struct { SElemType data[MAXSIZE]; int top; }SqStack;
|
顺序栈的入栈
从栈顶添加元素 头指针上移
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Status Push(SqStack *s, SElemType e) {
if (s->top == MAXSIZE - 1) { return ERROR; }
s->top++;
s->data[s->top] = e; return OK;
}
|
顺序栈的出栈
从栈顶元素移除元素 头指针下移
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Status Pop(SqStack* s, SElemType e) {
if (s->top == -1) { return ERROR; }
e = s->data[s->top];
s->top--;
return OK;
}
|
两栈共享空间
出发点
让一个栈的栈底为数组的始端 下标为0出 另一个栈为数组的末端 下标的数组长度为n-1 增加元素 两端向中间延伸
栈二为空 栈一 top1 == n-1 栈一满
栈一为空 栈二 top2 == 0 栈二满
两栈见面 top1 + 1 = top2
共享栈的定义
1 2 3 4 5 6 7 8 9
| typedef struct { SElemType data[MAXSIZE]; int top1; int top2; }SqDoubleStack;
|
共享栈的入栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| Status Push(SqDoubleStack* s, SElemType e, int stackNumber) {
if (s->top1 + 1 == s->top2) { return ERROR; }
if (stackNumber == 1) {
s->data[++s->top1] = e; } else if (stackNumber == 2) { s->data[--s->top2] = e; }
return OK; }
|
共享栈的出栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| Status Pop(SqDoubleStack* s, SElemType e, int stackNumber) {
if (stackNumber == 1) { if (s->top1 == -1) { return ERROR; }
e = s->data[s->top1--]; } else if (stackNumber == 2) { if (s->top2 == MAXSIZE) { return ERROR; } e = s->data[s->top2++]; }
return OK; }
|
栈的链式存储结构
定义
栈顶放在单链表的头部
通常情况下不存在栈满情况 除非内存已经没有可使用的空间了
top == null 说明空栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| typedef struct StackNode{
SElemType data; struct StackNode* next;
}StackNode,*LinkStackPtr;
typedef struct {
LinkStackPtr top;
int count;
}LinkStack;
|
链栈的入栈
开辟一块内存空间给一个新结点 将数据赋值给新节点以及头指针指向新结点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Status Push(LinkStack* S, SElemType e) {
LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
s->data = e;
s->next = S->top;
S->top = s; S->count++;
return OK;
}
|
链栈的出栈
将头指针指向下一结点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| Status Pop(LinkStack* S, SElemType* e) {
LinkStackPtr p;
if (StackEmpty(*S)) { return ERROR; }
*e = S->top->data;
p = S->top;
S->top = S->top->next;
free(p);
S->count--;
return OK; }
|
注意
如果栈的使用过程中元素变化不可预料最好使用链栈 反之顺序栈
递归
递归定义
把一个直接调用自己或通过一系列的调用语句间接地调用自己的函数
每个递归定义必须至少有一个条件 满足时递归不再进行 不再引用自身而是返回值退出
经典的菲波那切数列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| # include <stdio.h>
int fbi(int i) {
if (i < 2) { return i == 0 ? 0 : 1; }
return fbi(i - 1) + fbi(i - 2);
}
int main() {
int i;
printf("递归现实菲波那切数列\n");
for (i = 0; i < 40; i++) { printf("%d", fbi(i)); }
return 0; }
|
栈的应用(四则运算表达式求值)
后缀(逆波兰)表示法
原式(中缀表达式):9+(3 - 1) * 3 + 10 / 2
后缀表达式:9 3 1 - 3 * + 10 2 / +
所有的符号都在要运算数字的后面
后缀表达式计算结果
从左到右遍历表达式的每个数字和符号 遇到是数字就进栈 遇到符号就将处于站定两个数字出栈 进行计算 运算结果进栈 一直到最终获得结果
中缀表达式转后缀表达式
从左到右遍历中缀表达式的每个数字和符号 若是数字就输出 即成为后缀表达式的一部分 若是符号 则判断其与栈顶符号的优先级 是右括号或优先级不高于栈顶符号(乘除优先加减) 则栈顶元素依次出栈并输出 并将当前符号进栈 一直到最终输出后缀表达式为止
队列的定义
只允许在一端进行插入操作 而在另一端进行删除操作的线性表
性质
先进先出的线性表 FIFO
允许插入的一端称为队尾 允许删除的一端称为队头
循环队列
队列顺序存储的不足
就是当出队是后面的都要动 时间复杂度为O(n)
当前面有空位置时后面却已经满了 无法入队
这种现象称作 假溢出
循环队列的定义
头尾相接的顺序存储结构称为循环队列
循环队列的判断条件
设置一个标志量flag 当front == rear 且flag = 0时为空队列
当front == rear 且 flag = 1时为队列满
当队列为空 条件是front == rear 队列满时 保留一个元素空间
队列满的条件是 (rear + 1) % QueueSize == front
(rear - front + QueueSize) % QueueSize
循环队列顺序结构定义
1 2 3 4 5
| typedef struct { QElemType data[MAXSIZE]; int front; int rear; }SqQueue;
|
循环队列初始化
1 2 3 4 5 6 7 8 9 10 11
| Status InitQueue(SqQueue* Q) {
Q->front = 0;
Q->rear = 0;
return OK; }
|
循环队列长度
1 2 3 4 5 6
| int QueueLength(SqQueue *Q) { return (Q->rear - Q->front + MAXSIZE) % MAXSIZE; }
|
循环队列入队
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Status EnQueue(SqQueue *Q,QElemType e){
if ((Q->rear + 1) % MAXSIZE == Q->front) { return ERROR; }
Q->data[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAXSIZE;
return OK; }
|
循环队列出队
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Status DeQueue(SqQueue* Q, QElemType *e) {
if (Q->front == Q->rear) { return ERROR; } *e = Q->data[Q->front];
Q->front = (Q->front + 1) % MAXSIZE;
return OK; }
|
链式队列
链式队列定义
1 2 3 4 5 6 7 8 9 10 11
| typedef struct QNode{ QElemType data; struct QNode *next; }QNode,*QueuePtr;
typedef struct { QueuePtr front, rear; }LinkQueue;
|
链式队列入队
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| Status EnQueue(LinkQueue* Q, QElemType e) { QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
if (!s) { exit(_CRT_GUARDOVERFLOW); }
s->data = e;
s->next = NULL;
Q->rear->next = s;
Q->rear = s; }
|
链式队列出队
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| Status DeQueue(LinkQueue* Q, QElemType* e) {
QueuePtr p;
if (Q->front == Q->rear) { return ERROR; }
p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
if (Q->rear == p) { Q->rear = Q->front; }
free(p);
return OK; }
|
你知道的越多 你不知道的越多 嘿 我是小博 带你一起看我目之所及的世界……