一、双链表的基本概念
1.定义:双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
2.特点:
**优点:**对于任意的节点,都可以很轻松的获取前节点和后节点。
**缺点:**每个节点都需要保存next和prior两个属性,因此需要更多的空间开销,同时节点的插入和删除也会更费时间,因为需要更多的指向操作。
二、双链表的算法
2.1 双链表的结构定义
双链表节点类型DLinkList的声明如下:
typedef struct DLinkList
{
ElemType data; // 存储链表数据
struct DLinkList *prior; // 指向前驱节点
struct DLinkList *next; // 指向后继节点
}DLinkList; //声明双链表的节点类型
如果没有特别说明,假设单链表都是带头节点的单链表。
2.2 双链表的算法
2.2.1 建立双链表的算法
1. 采用头插法建立双链表
该方法从一个空链表开始,读取数组a中的元素,生成新的节点,将读取的数据存储到新节点的数据域中,然后将新节点插入到当前的链表的表头上,直到结束为止。算法如下:
void CreateDListF(DLinkList *&L, ElemType a[], int n)
{
DLinkList *s;
int i;
L=(DLinkList *)malloc(sizeof(DLinkList )); //创建头节点
L->next=L->prior=NULL;
for(int i=0;i<n;i++)
{
s = (DLinkedlist *)malloc(sizeof(DLinkedlist ));
s->data = a[i];
s->next = L->next; //s指向下一个
if ( L->next!=NULL)
{
L->next->prior=s;
}
L->next = s; //再将s给单链表L的表头
s->prior=L;
}
}
本算法的时间复杂度是O(n);
2. 采用尾插法建立双链表
该方法是将新节点插到当前链表的表位上,为止必须增加一个尾节点指针r,使其始终指向当前链表的尾节点。
双链表的尾插法:
Status CreateDListR(DLinkList *&L, ElemType a[], int n)
{
DLinkedlist *s, *r;
int i;
L=(DLinkList *)malloc(sizeof(DLinkList )); //创建头节点
r = L;
for(i = 1; i< = n; i++)
{
s =(DLinkList *)malloc(sizeof(DLinkList ));
s->data = a[i];
r->next = s;
s->prior = r;
r = s;
}
r->next = NULL;
}
本算法的时间复杂度是O(n);
2.2.2 链表的基本运算算法
1.按元素值查找算法
在链表L中从头开始查找第一个值域与x相等的节点,若存在这样的节点,则返回其逻辑序号,否则返回0。
int Finfnode(DLinkList *L, ElemType x)
{
DLinkList *p = L->next;
int i=1;
while(p != NULL && p->data != x)
{
i++;
p = p->next;
}
if (p==NULL) return 0; //未找到时返回0;
else return i; //找到时,返回序号
}
本算法的时间复杂度是O(n);
2.插入节点操作
假设在双链表中p所指的结点之后插入一个结点s,其操作语句描述为:
s->next = p->next;
s->next->prior = s;
s->prior = p;
p->next = s;
指针变化过程如图:
算法如下:
//在单链表的第i个元素之前插入元素x
int InsElem(DLinkedlist *&L, ElemType x, int i)
{
int j=0;
DLinkedlist *p = L, *s;
while(p!=NULL && j<i-1) //查找第i-1个结点*p
{
j++;
p = p->next;
}
if(p == NULL) return 0; //未找到结点返回0
else
{
s = (DLinkedlist *)malloc(sizeof(DLinkedlist )); //创建新结点
s->data = x; //存放元素x
s->next = p->next; //s指向i的元素位置,即p->next的指向
if (p->next != NULL) p->next->prior=s;
s->prior=p;
p->next = s; //插入s后,那么p指向s
return 1; //成功返回1
}
}
本算法的时间复杂度是O(n);
3.删除节点的操作
设要删除双链表中p结点的后继结点,其操作的语句为:
q= p->next;
p->next= q->next;
q->next->prior= p;
free(q);
指针变化过程如图所示:
算法如下:
int DelElem((DLinkedlist *&L, ElemType x, int i)
{
int j=0;
DLinkedlist *p = L, *q; //q是要被删除的元素
if(i<=0) return 0;
while(p!=NULL && j<i-1)
{ //查找第i-1个结点*p
j++;
p = p->next;
}
if(p == NULL) return 0; //未找到结点返回0
else{
q = p->next;
if(q == NULL) return 0;
p->next = q->next; //i-1指针指向i的指针
if (p->next != NULL) p->next->prior=p
free(q); //释放q
return 1; //成功返回1
}
}
}
本算法的时间复杂度是O(n);
[上一篇]:数据结构之单链表的建立、删除、查找、插入、删除和归并(合并)
[下一篇]:数据结构之循环链表的建立、查找、插入和删除(附C++程序)