1.线性表
定义n个数据元素的有限序列,记作(a1, a2, …, an)ai 是表中数据元素,n 是表长度
线性表特点
除第一个结点(元素)外,其他每一个结点有一个且仅有一个直接前驱结点。
除最后一个结点(元素)外,其他每一个结点有一个且仅有一个直接后继结点。
2.顺序表定义和特点
将线性表中的元素相继存放在一个连续的存储空间中。
可利用一维数组描述存储结构
特点 线性表的顺序存储方式
遍历 顺序访问, 可以随机存取
4.链表
链表分为单链表、静态链表、循环链表、双向链表
每个元素(表项)由结点(Node)构成。
线性结构
结点可以连续,可以不连续存储 结点的逻辑顺序与物理顺序可以不一致 表可扩充
5单链表定义
typedef char ListData;
typedef struct node { //链表结点
ListData data; //结点数据域
struct node * link; //结点链域
} ListNode;
typedef ListNode * LinkList;
LinkList first; //链表头指针
单链表插入
5.1头插
newnode->link = first ;
first = newnode;
5.2 中间插
newnode->link = p->link;
p->link = newnode;
6.带表头结点的单链表
表头结点位于表的最前端,本身不带数据,仅标志表头。
设置表头结点的目的是
统一空表与非空表的操作
简化链表操作的实现。
7.头插法建立单链表
从一个空表开始,重复读入数据:
生成新结点
将读入数据存放到新结点的数据域中
将该新结点插入到链表的前端
直到读入结束符为止。
8.尾插法建立单链表
每次将新结点加在链表的表尾;
设置一个尾指针 r,总是指向表中最后一个结点,新结点插在它的后面;
尾指针 r 初始时置为指向表头结点地址
9.循环链表
循环链表是单链表的变形。
循环链表最后一个结点的 link 指针不 为NULL,而是指向了表的前端。
为简化操作,在循环链表中往往加入表头结点。
循环链表的特点是:只要知道表中某一结点的地址,就可搜寻到所有其他结点的地址。
10.双向链表
双向链表是指在前驱和后继方向都能游历(遍历)的线性链表。
双向链表通常采用带表头结点的循环链表形式。
11.顺序表与链表的比较
基于空间的比较
存储分配的方式
顺序表的存储空间是静态分配的
链表的存储空间是动态分配的
存储密度 = 结点数据本身所占的存储量/结点结构所占的存储总量
顺序表的存储密度 = 1
链表的存储密度 < 1
基于时间的比较
存取方式
顺序表可以随机存取,也可以顺序存取
链表是顺序存取的
插入/删除时移动元素个数
顺序表平均需要移动近一半元素
链表不需要移动元素,只需要修改指针
若插入/删除仅发生在表的两端,宜采用带尾指针的循环链表
12.栈
定义
●只允许在一端插入和删除的线性表;
●允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom)
特点:后进先出 (LIFO)
13.栈的主要操作
ADT Stack {
//对象:由数据类型为StackData的元素构成
int Push (stack *S, StackData x); //进栈
int Pop (stack *S, StackData &x); //出栈
int GetTop (stack *S, StackData &x); //取栈顶
void InitStack (stack *S); //置空栈
int StackEmpty (stack *S); //判栈空否
int StackFull (stack *S); //判栈满否
}
14.栈的数组表示 — 顺序栈
#define StackSize 100
typedef char StackData;
typedef struct { //顺序栈定义
StackData data[StackSize]; //栈数组
int top; //栈顶指针
} SeqStack;
int StackEmpty (SeqStack *S) {
//判断栈是否空?空则返回1,否则返回0
return S->top == -1;
}
int StackFull (SeqStack *S) {
//判断栈是否满?满则返回1,否则返回0
return S->top == StackSize-1;
}
void InitStack ( SeqStack *S) { //置空栈
S->top = -1;
}
int Push (SeqStack *S, StackData x) {
//若栈满返回0, 否则新元素 x 进栈并返回1
if ( StackFull (S) ) return 0;
S->data[++S->top] = x; //加入新元素
return 1;
}
int Gettop (SeqStack *S, StackData &x) {
//若栈空返回0, 否则栈顶元素读到x并返回1
if ( StackEmpty(S) ) return 0;
x = S->data[S->top];
return 1;
}
int pop (SeqStack *S, StackData &x) {
//若栈空返回0, 否则栈顶元素退出到x并返回1
if ( StackEmpty(S) ) return 0;
x = S->data[S->top--];
return 1;
}
15.链式栈
链式栈无栈满问题,空间可扩充
插入与删除仅在栈顶处执行
链式栈的栈顶在链头
适合于多栈操作
16.队列
定义
队列是只允许在一端删除,在另一端插入的线性表
允许删除的一端叫做队头(front),允许插入的一端叫做队尾(rear)。
特性
先进先出(FIFO, First In First Out)
17队列进队和出队原则
进队时队尾指针先进一 rear = rear + 1,再将新元素按 rear 指示位置加入。
出队时队头指针先进一 front = front + 1,再将下标为 front 的元素取出。
队满时再进队将溢出出错;
队空时再出队将队空处理。
解决办法之一:将队列元素存放数组首尾相接,形成循环(环形)队列。
18.循环队列
队列存放数组被当作首尾相接的表处理。
队头、队尾指针加1时从QueueSize -1直接进到0,可用语言的取模(余数)运算实现。
队头指针进1: front = (front+1) % QueueSize;
队尾指针进1: rear = (rear+1) % QueueSize;
队列初始化:front = rear = 0;
队空条件:front == rear;
队满条件:(rear+1) % QueueSize == front
19.队列的链接表示 — 链式队列
队头在链头,队尾在链尾。
链式队列在进队时无队满问题,但有队空问题。
队空条件为 front == NULL