一、链式表:list
元素(结点)的数据项:
数据域:可以是任何类型的若干个数据项
指针域:指向下一个结点
由若干个结点通过指针域连接到一起就形成了链表
不带头结点的单链表:
第一个结点的数据域存储有效数据
缺点:添加、删除结点时,可能修改指向第一个结点的指针,参数需要使用二级指针,
才能更改指针的指向,比较麻烦
带头结点的单链表:
第一个结点的数据域不存储有效元素,仅仅只是使用它的指针域永远指向链表的第一个数据有效的结点
优点:添加、删除时会比不带头结点的链表更方便
注意:其它操作要从头结点的下一个结点开始
二、功能受限的表结构
对表结构的部分功能加以限制,形成特殊的表结构
栈:
只有一个进出口的表结构,先进后出,FILO
顺序栈:
数据域:
存储元素的内存首地址
栈的容量
栈顶位置
运算:
创建、销毁、入栈、出栈、栈顶、栈满、栈空
栈的应用:
1、函数的调用、栈内存特点
2、生产者和消费者模型(仓库->栈)
3、表达式解析 3-3*20/2
栈的常考笔试面试题:
某个序列是一个栈的入栈顺序,判断哪个是正确的出栈顺序
1 2 3 4 5 入栈
1 2 3 4 5 yes
3 2 1 4 5 yes
3 1 2 5 4 no
有可能边入边出
问题:两个容量相同的顺序栈,如何能够让空间利用率最高?
让两个栈相对着入栈
练习1:实现一个函数,序列a为入栈顺序,判断序列b是否是序列a的出栈顺序?
bool is_pop_stack(int a[],int b[],int len)
{
// 创建一个栈
// 按照a的顺序依次入一个
// 能不能按照b的顺序出,能就出,不能出就继续入a
// 判断是否栈空
}
链式栈:
栈结构数据项:
栈顶结点
结点数量
运算:
创建、销毁、入栈、出栈、栈空、栈顶
问题:顺序栈和链式栈的区别
队列:
有两个端口,一个端口只能入队,另一个只能出队
先进先出 FIFO
顺序队列:
数据项:
存储元素的内存首地址
容量
队头下标 //出队
队尾下标 //入队
运算:
创建、销毁、入队、出队、队空、队满、查队头、查队尾、数量
顺序队列的注意点:
由一维数组+队头下标front+队尾下标tail组成,入队tail++,出队front++,为了让队列能够反复使用,我们把队列想象成一个环,因此当front和tail加1后都需要用队列容量求余再重新赋值
front = (front+1)%cal;
tail = (tail+1)%cal;
如何判断队空、队满:
额外多申请一个元素的内存
队空:front == tail
队满:(tail+1)%cal == front
代价是空了一个位置不能使用,计算数量时较为麻烦('最常考')
计算数量:(tail-front+cal)%cal
另一种方式是队列结构中多增加一项数据项用于记录队列中元素个数
判断空或满直接判断该数据项即可,更方便
链式队列:
由链表结点组成的队列结构
数据项
队头指针
队尾指针
结点数量
运算:
创建、销毁、入队、出队、队空、查队头、查队尾
队列应用:
1,消息队列
2,树的层序遍历使用队列
3,图的广度优先遍历使用队列
4,封装线程池,数据池
作业:
使用两个顺序栈来模拟一个队列
栈2必须空栈,栈1才能入栈2
从栈1到栈2 必须一个不留的入
Queue
{
Stack* s1;
Stack* s2;
}