3.2 双链表
3.2.1 双链表的定义
-
定义
单链表的缺点:无法逆向操作,插入删除时只能从头开始遍历,很不方便。
双链表:每个结点都定义两个指针prior和next,分别指向前驱和后继,可进可退。
typedef struct DNode{
ElemType data;
struct DNode *prior,*next; //前驱指针和后继指针
}DNode,*DLinklist;
-
初始化双链表
bool InitDLinkList(DLinklist &L){ L=(DNode*)malloc(sizeof(DNode)); //分配头结点 if(L==NULL)return false; L->prior=NULL; //头结点的前驱指针永远指向NULL L->next=NULL; //头结点还暂时没有后继 }
-
判空(带头结点)
bool Empty(DLinkList L){ if(L->next==NULL) return true; else return false; }
3.2.2 双链表的插入
-
步骤
如图
1.要插入结点s连接p的后继结点:
s->next=p->next
;2.p的后继结点连接s:
p->next->prior=s
;3.要插入结点s与p连接:
s->prior=p
;4.p与s连接:
p->next=s
;- 注:语句顺序不唯一,但不任意。
bool InsertNextDNode(DNode*p,DNode*s){
if(p==NULL||s=NULL)return false;
s->next=p->next;
if(p->next!=NULL)p->next->prior=s; //先判断p有没有后继结点,防止p为链尾结点时产生的空指针
s->prior=p;
p->next=s;
return true;
}
- 时间复杂度: O ( 1 ) O(1) O(1)
3.2.3 双链表的删除
-
步骤
如图:
1.将p指向要删结点q的后继结点:
p->next=q->next
2.将q的后继结点与p连接:
q->next->prior=p
3.释放要删结点q:
free(q)
- 时间复杂度: O ( 1 ) O(1) O(1)
//删除结点p的后继结点
bool DeleteNextDNode(DNode *p){
if(p==NULL)return false;
DNode *q=p->next; //q为要删结点
if(q==NULL)return false;
p->next=q->next;
if(q->next!=NULL)q->next->prior=p; //该判断防止q是最后一个结点,从而指针制空
free(q);
return true;
}
-
销毁双链表
void DestoryList(DLinklist &L){ //循环释放各结点数据 while(L->next!=NULL) DeleteNextNode(L); free(L); //释放头结点 L=NULL; //头指针指向NULL }
*完整代码 双链表
以上只解释了双链表的定义、插入、删除,其他查找等操作与单链表一样,可看文章:
【数据结构】单链表解析+完整代码(创建 增删 查找等)
这里不再赘述,只在代码中展现。
#include<stdio.h>
#include<stdlib.h>
#define ElemType int
typedef struct DNode {
ElemType data;
struct DNode* prior,*next;
}DNode, * DLinkList;
//初始化
bool InitList(DLinkList& L) {
L = (DNode*)malloc(sizeof(DNode));
L->next = NULL;
L->prior = NULL;
return true;
}
//求表长
int Length(DLinkList L) {
int len = 0;
DNode* p = L;
while (p->next != NULL) {
len++;
p = p->next;
}
return len;
}
//头插法建立
DLinkList List_HeadInsert(DLinkList& L) {
L = (DNode*)malloc(sizeof(DNode));
L->next = NULL;
DNode* s;
int x;
scanf("%d", &x);
while (x != 9999) {
s = (DNode*)malloc(sizeof(DNode));
s->data = x;
s->next = L->next;
L->next = s;
scanf("%d", &x);
}
return L;
}
//尾插法建立
DLinkList List_TailInsert(DLinkList& L) {
int x;
L = (DNode*)malloc(sizeof(DNode)); //创建头结点
DNode* s, * r = L; //s指向头结点,r指向尾结点
scanf("%d", &x);
while (x != 9999) {
s = (DNode*)malloc(sizeof(DNode));
s->data = x;
r->next = s;
r = s;
scanf("%d", &x);
}
r->next = NULL;
return L;
}
//按序查找
DNode* GetItem(DLinkList& L, int i) {
DNode* p = L->next;
int j = 0;
while (j < i && p != NULL) {
p = p->next;
j++;
}
return p;
}
//按值查找
int LocateElem(DLinkList& L, ElemType e) {
DNode* p = L;
int j = 0;
while (p != NULL && p->data != e) {
p = p->next;
j++;
}
return j;
}
//按位序插入
bool ListInsert(DLinkList& L, int i, ElemType e) {
if (i < 0)return false;
DNode* p = L;
int j = 0;
while (j < i - 1 && p != NULL) {
p = p->next;
j++;
}
if (p == NULL)return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
//指定结点后插操作
bool InsertNextDNode(DNode* p, DNode* s) {
if (p == NULL||s==NULL)return false;
s->next = p->next;
if (p->next != NULL)p->next->prior = s; //先判断p有没有后继结点,防止p为链尾结点时产生的空指针
s->prior = p;
p->next = s;
return true;
}
//删除结点p的后继结点
bool DeleteNextDNode(DNode* p) {
if (p == NULL)return false;
DNode* q = p->next; //q为要删结点
if (q == NULL)return false;
p->next = q->next;
if (q->next != NULL)q->next->prior = p; //该判断防止q是最后一个结点,从而指针制空
free(q);
return true;
}
void PrintList(DLinkList& L) {
DNode* p = L->next;
while (p != NULL) {
printf("%d ", p->data);
p = p->next;
}
printf("\n\n");
}
void DestroyList(DLinkList& L) {
//循环释放各结点数据
while (L->next != NULL)
DeleteNextDNode(L);
free(L); //释放头结点
L = NULL; //头指针指向NULL
}
int main() {
DLinkList L;
printf("头插法建立链表,输入以9999结束:\n");
L = List_HeadInsert(L);
PrintList(L);
DestroyList(L);
printf("尾插法建立链表,输入以9999结束:\n");
L = List_TailInsert(L);
PrintList(L);
printf("求表长:%d\n", Length(L));
printf("\n");
printf("按位序插入:\n");
int pos = 1, e = 998;
ListInsert(L, pos, e);
PrintList(L);
printf("指定结点的后插操作:\n");
DNode* p = L->next;
DNode* q=(DNode*)malloc(sizeof(DNode));
q->data = 222;
q->next = NULL;
q->prior = NULL;
InsertNextDNode(p, q);
PrintList(L);
printf("按值查找:\n");
printf("查找222的位序是:%d\n", LocateElem(L, 222));
printf("\n");
printf("按序查找:\n");
DNode*x = GetItem(L, 2);
printf("查找第3个元素值是:%d\n", x->data);
printf("\n");
printf("按指定结点删除:\n");
p = L->next;
DeleteNextDNode(p);
PrintList(L);
}