一、双链表的定义
- 在线性表的链式存储结构中,没一个物理节点增加一个指向后继节点的指针域和一个指向前趋节点的指针域就叫双链表
- 双链表的优点
A、从任一节点出发可以快速找到其前趋节点和后继节点
B、从任一节点出发可以访问其他节点 - 一般来说,双链表的存储密度会低于单链表
二、双链表的类型定义(DLinkList)
typedef struct DNode //双链表节点类型
{
ElemType data;
struct DNode *prior; //指向前趋节点
struct DNode *next; //指向后继节点
}DLinkList;
三、双链表的建立
(1)头插法建表(链表的节点顺序与逻辑次序相反)
void CreateListF(DLinkList *&L,ElemType a[],int n)
{
DLinkList *s;
int i;
L=(DLinkList *)malloc(sizeof(DLinkList)); //创建头节点
L->prior=L->next=NULL; //前后指针域域置为NULL
for(i=0;i<n;i++) //循环建立数据节点
{
s=(DLinkList *)malloc(sizeof(DLinkList));
s->data=a[i]; //创建数据节点 *s
s->next=L->next; //将*s插在原开始节点之前,头节点之后
if(L->next!=NULL) //若L存在数据节点,修改前趋指针
L->next->prior=s;
L->next=s;
s->prior=L;
}
}
(2)尾插法建表(链表的节点顺序与逻辑次序相同)
void CreateListR(DLinkList *&L,ElemType a[],int n)
{
DLinkList *s ,*r ;
int i;
L=(DLinkList *)malloc(sizeof(DLinkList)); //创建头节点
r=L; //r始终指向尾节点,开始时指向头节点
for(i=0;i<n;i++) //循环建立数据节点
{
s=(DLinkList *)malloc(sizeofD(LinkList));
s->data=a[i]; //创建数据节点 *s
r->next=s; s->prior=r; //将*s插入 *r之后
r=s;
}
r->next=NULL; //尾节点next域置为NULL
}
四、线性表基本运算在双链表中的实现
和单链表相比,双链表主要是插入和删除运算不同
(1)双链表的插入运算
bool ListInsert(DLinkList *&L, int i,ElemType e)
{
int j=0;
DLinkList *p=L,*s ; //p指向头节点,j设置为0
while(j<i-1 && p!=NULL ) //查找第i-1个节点
{
j++;
p=p->next;
}
if( p ==NULL ) return false; //未找到第i-1个节点,返回false
else //找到第i-1个节点*p,在其后插入新节点*s
{
s=(DLinkList *)malloc(sizeof(DLinkList));
s->data=e; //创建新节点*s,其data域置为e
s->next=p->next; //将*s插入到*p之后
if(p->next!=NULL) //若存在后继节点,则修改其前趋指针
p->naxt->prior=s;
s->prior=p;
p->next=s;
return true;
}
}
(2)双链表的删除运算
bool ListDelete(DLinkList *&L, int i,ElemType e)
{
int j=0;
DLinkList *p=L,*s ; //p指向头节点,j设置为0
while(j<i-1 && p!=NULL ) //查找第i-1个节点
{
j++;
p=p->next;
}
if( p ==NULL ) return false; //未找到第i-1个节点,返回false
else //找到第i-1个节点*p,在其后插入新节点*s
{
q=p->next; //q指向第i个节点
if(q==NULL) //若不存在第i个节点时返回false
return false;
e=q->data;
p->next=q->next; //从双链表中删除*q节点
if(p->next!=NULL) //若存在后继节点,则修改其前趋指针
p->naxt->prior=p;
free(q); //释放*q节点
return true;
}
}