C语言基础知识10---栈、队列、树
目录
栈操作
1.1 栈的定义
1.2 栈操作
1.2.1 顺序栈---数组作为栈空间 粮仓模型
1.2.2 链式栈---链表作为栈空间 子弹夹模型
队列操作
2.1 队列定义
2.2 队列操作
2.2.1 顺序队列---数组
2.2.2 顺序队列中的溢出现象
2.2.3 链式队列---链表
树结构
3.1 树结构分类
3.2 树结构名词
3.3 顺序存储
3.4 链式存储
栈操作
1.1 栈的定义
栈是一种“先进后出”的线性表。限定只能在表尾进行插入和删除的线性表,并将表尾称为栈顶,表头称为栈底。
1.2 栈操作
1.2.1 顺序栈---数组作为栈空间 粮仓模型
栈顶指针:1. 指向下一个准备使用的空间
2. 指向最新存储数据的空间
栈底指针:不会动
栈空:栈顶指针==栈底指针
栈满:栈顶指针-栈底指针==MAX-1
入栈/压栈:数据新增
出栈/弹出:数据删除
清空栈:栈顶指针=栈底指针
1.2.2 链式栈---链表作为栈空间 子弹夹模型
栈顶指针: 头指针
栈底指针: NULL
栈空: 头指针==NULL
栈满: 理论上没有栈满
入栈/压栈: 头插法
出栈/弹出: 删除头指针指向的节点
清空栈: 依次删除头指针指向的节点
队列操作
2.1 队列定义
队列是一种“先进先出”的线性表。他只允许在表的一端(称表尾)插入元素,在表的另一端(表头)删除元素。
2.2 队列操作
2.2.1 顺序队列---数组
循环队列:理论上循环(通过求余实现),但是实际地址不循环
浪费了一个空间,但是节省了操作时间
队头指针:即将出队的数据
队尾指针:即将入队空间
队空:队头指针==队尾指针
队满:(队尾指针+MAX-队头指针)%MAX == MAX-1
入队:先存储数据,再 队尾指针=(队尾指针+1)%MAX
出队:先删除数据,再 队头指针=(队头指针+1)%MAX
清空队列:队头指针=队尾指针
2.2.2 顺序队列中的溢出现象
① "下溢"现象
当队列为空时,做出队运算产生的溢出现象。“下溢”是正常现象,常用作程序控制转移的条件。
② "真上溢"现象
当队列满时,做进队运算产生空间溢出的现象。“真上溢”是一种出错状态,应设法避免。
③ "假上溢"现象
由于入队和出队操作中,头尾指针只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于向量空间的规模时,也可能由于尾指针已超越向量空间的上界而不能做入队操作。该现象称为"假上溢"现象。
解决“假溢出”的方法有两种:
(1) 采用平移元素的方法,即一旦发生“假溢出”就把整个队列的元素平移到存储区的首部。平移元素的方法效
率是很低的。
(2) 将整个队列作为循环队列来处理,。这样,虽然物理上队尾在队首之前,但逻辑上队首仍然在前,作插入和删除运算时仍按"先进先出"的原则。
循环队列
为充分利用向量空间,克服"假上溢"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。
在循环队列中只凭等式 rear==front 无法判别队空还是队满。因此,而把尾指针加 1后等于头指针作为队满的标志。这意味着损失一个空间,或者反过来说,拥有 MAXSIZE 个数组元素的数组仅能表示一个长度为MAXSIZE-1 的循环队列。
循环队列满的条件:(rear + 1) % MAXSIZE == front
循环队列空的条件:rear == front
循环队列出队:front = (front + 1) % MAXSIZE
循环队列入队:rear = (rear + 1) % MAXSIZE
循环队列的长度:(MAXSIZE + rear – front)% MAXSIZE
2.2.3 链式队列---链表
队头指针:头指针
队尾指针:NULL
队空:头指针==NULL
队满:理论没有队满
入队:尾插法
出队:删除头指针指向的节点
清空栈: 依次删除头指针指向的节点
树结构
3.1 树结构分类
无序树
有序树
二叉树
满二叉树
完全二叉树
3.2 树结构名词
树根:根节点C 语言阶段教学笔记 2025 年 3 月 26 日
父子节点:A 下面链接 B,那么 A 就是 B 的父节点,B 就是 A 的子节点
左子树:左边子节点为根节点的树
右子树:右边子节点为根节点的树
父亲节点/双亲节点:
节点的度:节点的子节点个数
树的度:所有节点最大的度
树的高度/深度:树的最大层数
分枝节点/非终端节点:度不为 0 的节点
叶子节点/终端节点:度为 0 的节点
3.3 顺序存储
按顺序从第一层由左到右依次存储到数组中(从数组下标 1 开始使用)
当前节点下标为 i
左孩子:下标为 2i
右孩子:下标为 2i+1
数组大小:2 的 n 次方-1 个元素
3.4 链式存储
先根遍历、中根遍历、后根遍历
struct A{
char n;
struct A * l;
struct A * r;
};
void fun(struct A * root)
{
if(root == NULL)
{}
else
{
printf(“%c”,root->n); // 先根遍历
fun(root->l);
printf(“%c”,root->n); // 中根遍历
fun(root->r);
printf(“%c”,root->n); // 后根遍历
}
}
先根遍历:ABDECFG
中根遍历:DBEAFCG
后根遍历:DEBFGCA