双链表和循环链表都是单链表的扩展只用在单链表的基础上稍加修改就可以了。
如果对单链表还不是很了解可以去看一下我写的另一篇博文https://blog.csdn.net/weixin_43599057/article/details/95176560
1.双链表
双链表就是每个节点含有两个指针的链表,一个指针与单链表一样为next指针指向下一个,而另一个指针为prior指向前一个节点。因此也很容易理解双链表与单链表的不同之处就在于既可以从头访问到尾,也可以从尾访问到头。
因此很容易得到双链表的基本定义为
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinkList;
接下来就讨论以下几个操作(也是与单链表稍有不同的操作).
1.ListInsert
Status ListInsert(DLinkList &L,int i,int e){
if(i<=0||i>ListLength(L)) return FALSE;
DLinkList p,r;
p=GetElem(L,i-1);
r=GetElem(L,i);
DLinkList s=(DLinkList)malloc(sizeof(DNode));
s->data=e;
s->next=p->next;
p->next=s;
s->prior=r->prior;
r->prior=s;
return OK;
}
可见ListInsert操作中对后驱的操作与单链表完全相同,而对前驱的操作也基本与对后驱的操作完全一样,而值得注意的是r=GetElem(L,i)而不是GetElem(L,i+1)我当时就是这里搞错了。至于为什么,建议大家画一个图就很好理解了。
2.ListDelete操作
Status ListDelete(DLinkList &L,int i){
if(i<1||i>ListLength(L)) return FALSE;
DLinkList p,s,t;
t=GetElem(L,i);
p=t->prior;
s=t->next;
p->next=s;
s->prior=p;
free(t);
return OK;
}
方法不唯一,但我认为这是比较好理解的方法。相当于把中间一个跳过去了。
其他操作如ListTraverse,ListLength与单链表的操作都是完全相同的。
循环链表
循环链表与单链表的不同是就在于循环列表的尾节点的后继是指向链表的头节点从而达到循环的效果。其他操作与单链表完全相同。
下面就InitList为例
LinkList InitList(LinkList &L){
L=(LinkList)malloc(sizeof(LNode));
LinkList p;
p=L;
int num;
scanf("%d",&num);
while(num){
LinkList s=(LinkList)malloc(sizeof(LNode));
s->data=num;
p->next=s;
p=s;
scanf("%d",&num);
}
p->next=L;
return L;
}
可以看到关键一步就是p->next=L;
循环双链表
理解循环列表和双链表后,循环双链表自然不在话下,
以InitList为例
LinkList InitList(LinkList &L){
L=(LinkList)malloc(sizeof(LNode));
LinkList p;
p=L;
int num=1;
while(num){
LinkList s=(LinkList)malloc(sizeof(LNode));
s->data=num;
p->next=s;
s->prior=p;
p=s;
scanf("%d",&num);
}
p->next=L;
L->prior=p;
return L;
}
即多了对prior的一些操作,在这里就不赘述了。
希望对大家能有些帮助。