目录
2.3.3 双链表
在线性表的链式存储结构中,每个物理结点增加一个指向后继结点的指针域和一个指向前驱结点的指针域 ->双链表。
对于双链表,采用类似于单链表的类型定义,其结点类型DLinkNode声明如下:
typedef struct DNode //双链表结点类型
{ ElemType data;
struct DNode *prior; //指向前驱结点
struct DNode *next; //指向后继结点
} DLinkNode;
1、建立双链表
整体建立双链表也有两种方法:头插法和尾插法。与单链表的建表算法相似,主要是插入和删除的不同。
void CreateListF(DLinkNode *&L,ElemType a[],int n)
{ DLinkNode *s; int i;
L=(DLinkNode *)malloc(sizeof(DLinkNode)); //创建头结点
L->prior=L->next=NULL; //前后指针域置为NULL
for (i=0;i<n;i++) //循环建立数据结点
{ s=(DLinkNode *)malloc(sizeof(DLinkNode));
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;
}
}
尾插法建立双链表:由含有n个元素的数组a创建带头结点的双链表L。
void CreateListR(DLinkNode *&L,ElemType a[],int n)
{ DLinkNode *s,*r;
int i;
L=(DLinkNode *)malloc(sizeof(DLinkNode)); //创建头结点
r=L; //r始终指向尾结点,开始时指向头结点
for (i=0;i<n;i++) //循环建立数据结点
{ s=(DLinkNode *)malloc(sizeof(DLinkNode));
s->data=a[i]; //创建数据结点s
r->next=s;s->prir=r; //将s插入r之后
r=s; //r指向尾结点
}
r->next=NULL; //尾结点next域置为NULL
}
2、线性表基本运算在双链表中的实现
和单链表相比,双链表主要是插入和删除运算不同。
双链表的插入算法:
bool ListInsert(DLinkNode *&L,int i,ElemType e)
{ int j=0;
DLinkNode *p=L,*s; //p指向头结点,j设置为0
while (j<i-1 && p!=NULL) //查找第i-1个结点
{ j++;
p=p->next;
}
if (p==NULL) //未找到第i-1个结点,返回false
return false;
else //找到第i-1个结点p,在其后插入新结点s
{
s=(DLinkNode *)malloc(sizeof(DLinkNode));
s->data=e; //创建新结点s
s->next=p->next; //在p之后插入s结点
if (p->next!=NULL) //若存在后继结点,修改其前驱指针
p->next->prior=s;
s->prior=p;
p->next=s;
return true;
}
}
双链表的删除算法:
bool ListDelete(DLinkNode *&L,int i,ElemType &e)
{ int j=0; DLinkNode *p=L,*q; //p指向头结点,j设置为0
while (j<i-1 && p!=NULL) //查找第i-1个结点
{ j++;
p=p->next;
}
if (p==NULL) //未找到第i-1个结点
return false;
else //找到第i-1个结点p
{ q=p->next; //q指向第i个结点
if (q==NULL) //当不存在第i个结点时返回false
return false;
e=q->data;
p->next=q->next; //从双单链表中删除q结点
if (q->next!=NULL) //若q结点存在后继结点
q->next->prior=p; //修改q结点后继结点的前驱指针
free(q); //释放q结点
return true;
}
}
void reverse(DLinkNode *&L) //双链表结点逆置
{ DLinkNode *p=L->next,*q; //p指向开始结点
L->next=NULL; //构造只有头结点的双链表L
while (p!=NULL) //扫描L的数据结点
{ q=p->next; //用q保存其后继结点
p->next=L->next; //采用头插法将p结点插入
if (L->next!=NULL) //修改其前驱指针
L->next->prior=p;
L->next=p;
p->prior=L;
p=q; //让p重新指向其后继结点
}
}
2.3.4 循环链表
循环链表是另一种形式的链式存储结构形式。
某线性表最常用的操作是在尾元素之后插入一个元素和删除第一个元素,故采用( )存储方式最节省运算时间。
A.单链表 B.仅有头结点指针的循环单链表 C.双链表 D.仅有尾结点指针的循环单链表
如果对含有n(n>1)个元素的线性表的运算只有4种,即删除第一个元素、删除尾元素、在第一个元素前面插入新元素、在尾元素的后面插入新元素,则最好使用( )。
A.只有尾结点指针没有头结点的循环单链表 B.只有尾结点指针没有头结点的非循环双链表 C.只有首结点指针没有尾结点指针的循环双链表 D.既有头指针也有尾指针的循环单链表
本节完.