双向链表——单链表改进之二

来源:互联网 发布:涩谷 涉谷 知乎 编辑:程序博客网 时间:2024/05/17 03:51

       在单链表中,我们可以通过next指针使得查找下一个结点的时间复杂度为O(1)。但如果我们想访问上一个结点,则最坏的时间复杂度为O(n),因为我们需要从头开始遍历查找。因此,产生了双向链表。双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。所以在双向链表中的结点都有两个指针域,一个指向直接后继,一个指向直接前驱。下面是双向链表的结构示意图。


       有关双向链表,我们重点关注其插入与删除操作,因为在进行上述两项操作时,我们需要更改两个指针变量,而其他操作只需要改动一个方向的指针。

下面是详细操作:

与之前相同,代码预处理与双向链表定义:即定义部分需要加一个前驱指针。

#include <stdio.h>#include <malloc.h>#include <stdlib.h>#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASTABLE -1#define OVERFLOW -2typedef int status;typedef struct DULNODE{struct DULNODE *prior;int data;struct DULNODE *next;}DulNode,*DuLinklist;

打印双向链表与之前相同,因为也只需要一个方向的指针。

void Print(DuLinklist L){DuLinklist p;p = L->next;while (p != NULL){printf("%d ", p->data);p = p->next;}printf("\n");}

创建链表需要为每一个插入的结点指明前驱和后继:

void CreatDouble(DuLinklist &L){DuLinklist p,nail;L = (DulNode*)malloc(sizeof(DulNode));L->next = NULL;nail = L;p = (DulNode*)malloc(sizeof(DulNode));printf("请输入双向链表元素,按Ctrl+Z结束:\n");while ((scanf("%d", &(p->data))) != EOF){p->next = NULL;p->prior = nail;nail->next = p;nail = p;p = (DulNode*)malloc(sizeof(DulNode));}}

下面程序会用到双向链表的长度,故这里给出:

int DoubleLength(DuLinklist L){DuLinklist p;p = L;int j = 0;while (p->next){p = p->next;j++;}return j;}

接下来就是插入操作,注意插入的顺序:

status InsertDouble(DuLinklist &L, int i, int e){int j = 0;DuLinklist p, q;p = L;while (p&&j < i - 1){p = p->next;j++;}//用p找到插入位置if (!p || j>i - 1)return ERROR;q = (DulNode*)malloc(sizeof(DulNode));if (q == NULL)return ERROR;q->data = e;q->next = p->next;q->prior = p;//先搞定插入结点的前驱和后继p->next->prior = q;p->next = q;//再搞定后结点的前驱和前结点的后继return OK;}

理解了插入操作就不难理解删除操作,即对被删除的结点的前驱和后继进行连接:

status DeleteDouble(DuLinklist &L, int i, int &e){DuLinklist p;p = L;int j = 0;while (p->next&&j < i ){p = p->next;j++;}//用p确定删除的位置if (!p->next || j>i){e = p->data;p->prior->next = p->next;free(p);return OK;}//若P为最后一个结点,则将null赋值给p前一个结点的后继e = p->data;p->prior->next = p->next;//将p的后结点作为p的前结点的后继p->next->prior = p->prior;//将p的前结点作为p的后结点的前驱free(p);//释放p结点return OK;}

最后为主函数调用:

int main(){DuLinklist L1;CreatDouble(L1);printf("建立的双向链表为:\n");Print(L1);int i, e;printf("请输入插入元素的位置:\n");scanf("%d", &i);while (i<1 || i>DoubleLength(L1) + 1){printf("插入位置有误,重新输入!\n");scanf("%d", &i);}printf("请输入插入元素:\n");scanf("%d", &e);InsertDouble(L1, i, e);printf("插入后的双向链表为:\n");Print(L1);int i1, e1;printf("请输入删除元素的位置:\n");scanf("%d", &i1);while (i1<1 || i1>DoubleLength(L1) ){printf("删除位置有误,重新输入!\n");scanf("%d", &i);}DeleteDouble(L1, i1, e1);printf("删除后的双向链表为:\n");Print(L1);printf("被删除元素为:%d\n",e1);system("pause");return 0;}

        此外既然单链表可以有循环,那么双向链表也可以循环,称之为双向循环链表,对其的操作可以参照循环链表和双向链表。对于双向链表的讲解就到此为止了,小编最近还回推出有关链表操作的究极强化版,敬请期待!


1 0
原创粉丝点击