双向循环链表与单向循环链表的区别在于,每个节点的指针域中除了有指向下一结点的next指针外,还有指向前一结点的prev指针:
在链表中,中间部分结点的next指针指向其直接后继结点,prev指针指向其直接前继结点。与单向循环链表相同,末结点的next指针不再指向NULL,而是指向头结点Head,而头结点的prev则指向末结点。
将新结点new插入到p所指向的结点之后:
① new->prev = p;
② new->next = p->next;
③ p->next = new;
④ new->next->prve = new;
删除p结点:
① p->prev->next = p->next;
② p->next->prev = p->prev;
③ free(p);
双向循环链表的实现:
功能:在链表的结点中分别存放1、2、3、4、5、6、7、8、9、10,并进行相关操作,实现奇数升序偶数降序,即1、3、5、7、9、10、8、6、4、2。
基本思路:
从末结点向前遍历,从遍历到的第二个偶数结点开始,将偶数结点移动至末结点。
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node
{
datatype data;
struct node *prev;
struct node *next;
}dlistnode, *dlinklist;
//初始化
dlinklist init_list(void)
{
dlinklist head = (dlinklist)malloc(sizeof(dlistnode));
head->prev = head;
head->next = head;
return head;
}
//插入新结点
void insert(dlinklist head, datatype i)
{
dlinklist newnode = (dlinklist)malloc(sizeof(dlistnode));
//直接改指针,不需要遍历,不需要中间结点。
newnode->data = i;
newnode->prev = head->prev;
newnode->next = head;
newnode->prev->next = newnode;
head->prev = newnode;
}
void show(dlinklist head)
{
dlinklist p = head->next;
while(p != head)
{
printf("%d\t", p->data);
p = p->next;
}
printf("\n");
}
//升降序操作:
void rearrange(dlinklist head)
{
dlinklist p, q;
int i = 0;
for(p=head->prev; p != head; p=p->prev)
{
//从末结点往前遍历,从第二个偶数开始,将偶数结点搬移到末结点
if(p->data % 2 == 0 && i != 0)
{
p->prev->next = p->next;
p->next->prev = p->prev;
p->prev = head->prev;
p->next = head;
head->prev->next = p;
head->prev = p;
//由于p所指的结点已成为末结点,为避免历遍出错,将p指向最近历遍的奇结点。
p = q;
}
//记录最近历遍奇数结点位置
q = p;
i++;
}
}
int main(void)
{
dlinklist head;
int n;
int i;
head = init_list();
scanf("%d", &n);
for(i=1; i<=n; i++)
{
insert(head, i);
}
show(head);
rearrange(head);
show(head);
return 0;
}