双向链表——单链表改进之二
来源:互联网 发布:涩谷 涉谷 知乎 编辑:程序博客网 时间: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
- 双向链表——单链表改进之二
- 实验二——双向链表
- 数据结构与算法专题之线性表——链表(二)双向链表
- 单链表之双向链表
- Linux双向链表(二)——逻辑判断
- 详解Linux内核之双向循环链表(二)
- 双向循环链表设计分析之二
- 面试系列之二:C艹翻转双向链表
- 数据结构与算法之双向链表 <二>
- 数据结构面试之二——双向链表表、循环链表、有序链表的常见操作
- 数据结构面试之二——双向链表表、循环链表、有序链表的常见操作
- 数据结构面试之二——双向链表表、循环链表、有序链表的常见操作
- jquery 双向选择器之改进版
- 作业二 双向链表
- 数据结构——链表之双向链表
- 数据结构之线性表——双向链表
- 数据结构——练习之双向链表实现
- 数据结构之——循环双向链表的实现
- 【NYoj】34 - 韩信点兵(CRT)
- 【大话设计模式】设计模式系统学习大合集
- 一年很短,一天很长
- SpringMVC常用注解
- php字符串操作
- 双向链表——单链表改进之二
- HDOJ 5780 abs(枚举)
- 内部类和接口
- 操作系统
- HDOJ-----5326
- HDU1856More is better(并查集)
- Cow Exhibition
- [转]union和struct辨析
- java面试题