利用双向链表可以避免单链表的缺点,单链表的缺点就是查找指针p指向的节点,必须从指针p开始遍历整个链表一遍,时间复杂度为O(n)。
双向链表的每个节点有两个指针一个指针指向前驱节点,另一个指向后继节点
在双向循环链表中每个节点包括3个域,data域,prior域,next域。双向链表也分为带头节点和不带头节点
带头结点使某些操作更加方便,另外双向链表也有循环结构,成为双向循环链表,带头节点的双向循环链表,双向
循环链表为空的情况,判断带头节点的双向循环链表为空的条件是:head->prior == head 或者head->next == head.
在双向循环链表中,因为每个节点既有前驱节点的指针域又有后继节点的指针域,所以查找节点非常方便。
双向链表的插入和删除跟单链表跟单链表不同,其他没有什么差异,所以在这里就直接讲一下插入和删除。
插入操作:就是要在带头的节点的双向循环链表中的第i个位置插入一个元素的值为E的节点
,插入成功返回1,否则返回0。
算法思想:首先找到第i个节点,用p指向该节点,再申请一个新节点由s指向该节点将e放入到数据域然后开始修改
p和s指向节点指针域,修改s的prior,使其指向p的直接前驱结点。s->prior = p->prior;
将p的直接前驱结点的next域指向s指向的结点即p->prior->next = s;修改s的next指针域使其指向p指向的结点即s->next = p;
修改p的prior域,使其指向s 的指向的结点,即p->prior = s;
代码一下:
int InsertDList(DListLink head,int i,DataType e)
{
DListLink *p,*s;
int j;
p = head->next;
j=0;
while(p != head && j<i)
{
p=p->next;
j++;
}
if(j != i)
{
printf("插入位置不正确");
return 0;
}
s = (DListNode *)malloc(sizeof(DListNode));
if(!s)
return -1;
s->data = e;
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
return 1;
}
双向循环链表的删除的操作--就是将带头节点的双向循环链表中的第i节点删除。删除成功返回1,否则返回0.
思路:
1:首先找到第i个结点,用p指向该结点,然后开始修改p指向的结果的直接前驱和直接后继结点的指针域,从而
将p链表断开,断开分为2步:
一:p->prior-next = p->next;
二:p->next->prior = p->prior;
代码如下:
int DeletDList(DListLink head,int i,DataType *e)
{
DListLink *p;
int j;
p = head->next;
j=0;
while(p != head && j<i)
{
p=p->next;
j++;
}
if(j != i)
{
printf("删除位置不正确");
return 0;
}
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
return -1;
}