线性表
1. 双链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表
typedef struct DNode {
ElemType data;
struct DNode *prior, *next;
}DNode,*DLinklist;
1.1 插入操作
s->next = p->next;
p->next->prior = s;
s->prior = p;
p->next = s;
1.2 删除操作
准备删除的结点q的后继节点赋给p的后继节点,q结点的下一个结点的前驱结点指向 p
p->next = q->next;
q->next-> prior = p;
free(q);
2. 循环链表
循环链表是一种链式存储结构,它的最后一个结点指向头结点,形成一个环。因此,从循环链表中的任何一个结点出发都能找到任何其他结点。循环链表的操作和单链表的操作基本一致,差别仅仅在于算法中的循环条件有所不同。
2.1 循环单链表
2.2 循环双链表
2.3 循环链表判空
2.3.1 循环单链表
L->next == L;
2.3.2 循环双链表
L->next ==L;
L->prior == L;
3. 静态链表
静态链表和单链表的区别
静态链表:把地址改成数组下标,下一个结点地址改为下一个结点的下标
#define Maxsize 50
typedef struct DNode{
ElemType data;
int next;
SLinkList[Maxsize] ;
4. 顺序表与链表比较
4.1 存取方式
单链表只能顺序存取,顺序表可以通过计算得到相应的数据元素地址从而达到随机存取。
4.2 逻辑结构、物理结构
单链表:数据元素存放位置可能相邻可能不相邻
顺序表:一定相邻
4.3 基本操作
插入:
单链表:修改指针即可
顺序表:依次向后移位
删除:
顺序表:依次向前移位
单链表:修改结点的指针
查找:
1.按值查
顺序表:依次遍历,O(n)
单链表:依次遍历,O(n)
2.按序号查:
顺序表:数组下标直接查找
单链表:依次遍历
4.4 内存空间
顺序存储:无论静态分配还是非静态都需要预先分配合适的内存空间
静态分配时预分配空间太大回造成浪费,太小会造成溢出
动态分配时虽不会溢出但是扩充需要大量移动元素,操作效率低
链式存储:在需要时分配结点空间即可,高效方便,但指针要使用额外空间
总结
区别 | 顺序表 | 单链表 |
---|---|---|
存取方式 | 顺序表可以实现顺序存取和随机存取 | 单链表只能实现顺序存取 |
逻辑、物理存储 | 顺序表逻辑相邻物理上也相邻,通过相邻表示逻辑关系 | 单链表逻辑相邻物理上不一定相邻,通过指针表示逻辑关系 |
内存空间 | 动态分配时扩充效率低 | 高效、方便 |
基本操作 | 顺序表 | 单链表 |
---|---|---|
插入&删除 | O{n)且需要大量移动元素 | O(1)(节点指针已知);O(n)(节点指针未知),但操作时只需修改指针 |
查找(按序) | O(1) | O(n) |
查找(按值且无序) | O(n) | O(n) |
4.5 怎样选择线性表的存储结构
4.6 三个常用操作
4.6.1 最值:
4.6.1.1 顺序表
顺序表:变量:min、max ,遍历数组分别与最大值最小值比较,如果比最大值大或比最小值小就替换预设变量。时间复杂度:O(n)
int min = L[O];
int max = L[O];
for(int i = o;i < n;i++){
if(min > L[O])
min = L[O];
if(max<L[O])
max = L[0];
4.6.1.2 单链表
单链表:设变量,遍历链表,时间复杂度:O(n)
int min = p-> next ->data;
int max = p -> next ->data;
for( ; p != NULL; p = p ->next){
if(min > p ->data)
min = p ->data;
if(max< p ->data)
max = p ->data;
4.6.2 逆置
4.6.2.1 顺序表:
设置标志i、j,分别放到数组的最后和最前,ij的元素交换,i向后移,j向前移。一直到j=i;时间复杂度O(n)
inti= o;
int j = n-1;
while(i< j){
temp =L[i];
L[i]= L[j];
L[j]= temp;
}
4.6.2.2 单链表
单链表:头结点指针、尾结点指针。头结点插入尾结点,一直到r只向头结点
while(p ->next != r){
temp = p-> next;
p -> next = temp -> next;
temp -> next = r-> next;
r -> next = temp;
4.6.3 合并
4.6.3.1 顺序表
两个数组依次比较,最小的放入新数组,并且依次后移
int i= 0,j = O;
int k = O;
for( ; i<L1_Size &&j <L2_Size; k++){
if(L1[i]<L2[j]
L[k]=L1[i++];
else
L[k]= L2[j++];
}
while(i<L1_Size)
L[k++]=L1[i++];
while(j<L2_Size)
L[k++]=L1[i++];
4.6.3.2 单链表
单链表:两个链表循环比较,移动指针。
while(p->next!=NULL &&q->next!=NULL){
if(p->next->data < q->next->data){
r->next = p->next;
p->next= p->next- > next;
r= r- >next;
}
else{
r- >next = q->next;
q->next= q->next- >next;
r = r- >next;
}
}
if(p->next != NULL) r-> next = p ->next;
if(q->next != NULL)r-> next = q ->ne
free(p); free(a);
这里与顺序表不同,当一个链表的为空后,只需将下一个链表的指针指向新表,不需要再次循环。