第1章第2节 线性表的链式表示(2)

最后更新于:2022-04-01 19:50:33

单链表中只有一个指向其后继结点的指针,使得单链表只能从前向后依次遍历,若要访问某个结点的前驱结点(或插入,删除操作时),只能从头开始遍历,访问后继结点的时间复杂度为O(1),而访问前驱结点时,其事件复杂度为O(n)。 为了克服单链表的上述缺点,引入了双链表。 ## 一.双链表的定义 在双链表中引入了两个指针,分别为指向前驱结点的指针prior和指向后继结点的指针next。如下图所示: ![双链表结点结构](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-14_56e669475e2ef.jpg "") 对于双链表结点的描述如下: ~~~ typedef struct DNode{ ElemType data; struct DNode *prior, *next; }DNode, *DLinkList; ~~~ 双链表仅仅在单链表的基础上增加了一个指向前驱的prior指针,因此,在双链表执行按值查找和按位查找时的操作与单链表无异。但双链表在插入和删除操作的实现上与单链表相比有着较大的不同,因为在对“链”进行修改时不仅仅需要修改next指针域,此时还需要照顾到prior指针域,此时在操作时就必需保证在修改过程中不会断链。此外双链表可以很方便的找到其前驱结点,因此插入,删除结点时的时间复杂度仅为O(1)。 ## 二.双链表基本操作的实现 ### 2.1建立双链表 #### 2.1.1头插法建立双链表 该方法中,首先建立一个具有头结点的空双链表,然后每生成一个读取到数据的新节点,就将其放置到头结点之后。如下图所示: ![头插法建立双链表](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-14_56e669476d903.jpg "") 算法描述如下: ~~~ DLinkList CreatList(DNode *head) { DNode *s; ElemType x; scanf("%d",&x); while(x!=999){ s=(DNode*)malloc(sizeof(DNode)); s->data=x; s->next=head->next; if(head->next){ head->next->prior=s; } s->prior=head; head->next=s; scanf("%d",&x); } return head; } ~~~ #### 2.1.2尾插法建立双链表 该方法中同样首先建立一个具有头结点的空双链表,然后每生成一个读取到数据的新节点,就将它插入到表尾;为了达到这样的目的,必须增加一个尾指针r,使其始终指向当前链表的尾结点。如下图所示: ![尾插法建立双链表](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-14_56e669477fecf.jpg "") 算法描述如下: ~~~ DLinkList CreatList(DNode *head) { DNode *s; DNode *r=head; ElemType x; scanf("%d",&x); while(x!=999){ s=(DNode*)malloc(sizeof(DNode)); s->next=NULL; s->data=x; r->next=s; s->prior=r; r=s; scanf("%d",&x); } r->next=NULL; return head; } ~~~ ### 2.2双链表的插入操作 #### 2.2.1插入后继结点 在双链表p所指的结点之后插入结点*s,其指针的变化过程一定不能乱,否则会断链,具体过程如下图所示: ![双链表插入后继结点](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-14_56e669478e3f8.jpg "") ~~~ void InsertDNode(DNode* p, ElemType x) { DNode *s; s=(DNode*)malloc(sizeof(DNode)); s->data=x; s->next=p->next; p->next->prior=s; s->prior=p; p->next=s; } ~~~ #### 2.2.2插入前驱结点 在双链表p所指的结点之前插入结点*s,其指针的变化过程一定不能乱,否则会断链,具体过程如下图所示: ![双链表插入前驱结点](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-14_56e669479f10f.jpg "") 算法描述如下所示: ~~~ void InsertDNode(DNode* p, ElemType x) { DNode *s; s=(DNode*)malloc(sizeof(DNode)); s->data=x; s->next=p; p->prior->next=s; s->prior=p->prior; p->prior=s; } ~~~ ### 2.3双链表的删除操作 删除双链表中结点*p的后继结点*q,其指针的变化过程如下图所示: ![双链表的删除操作](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-14_56e66947b3893.jpg "") 算法描述如下: ~~~ void DelList(DNode *p) { DNode *q=p->next; p->next=q->next; q->next->prior=p; free(q); } ~~~
';