双向循环链表:
双向循环链表和双向链表的不同之处,是双向循环链表的尾部节点的next不指向NULL,而是指向第一个节点,而第一个节点的pre是指向尾部节点的。
双向循环链表的结构:
(以下示意图均摘自
来源:
http://blog.csdn.net/fisherwan/ar
)
双向循环链表的初始化:
链表中只有一个节点,它的前驱和后驱指针都指向它自己。
双向循环链表的创建:(图示为在中间插入的)
双向循环链表没有首尾的概念,相当于一个环。
p = head;
while(p->next != head)
p = p->next;
pnew->pre = p;
pnew->next = p->next;
p->next->pre = newnode;
p->next = pnew;
双向循环链表的插入:
这里仅介绍从中间插入节点的讲解,可分为两种情况,在
节点ptr的后面插入和在
节点ptr的前面插入
(1)在节点ptr的后面插入(修改4个指针)
①pnew->next = ptr->next;
②pnew->pre = ptr;
③ptr->next->pre = pnew;
④ptr->next = pnew
注意:①②③的顺序可以任意,单④必须在最后
(2)在节点ptr的前面插入
(修改4个指针)
①pnew->next = ptr;
②ptr->pre->next = pnew;
③pnew->pre = ptr->pre;
④ptr->pre = pnew;
注意:①②③的顺序可以任意,单④必须在最后
双向循环链表的删除:
仅介绍从中间删除的情况,先找到要删除的节点的前驱节点。(
修改2个指针)
pdelete = ptemp->next;
ptemp->next = pdelete->next;
pdelete->next->pre = ptemp;
双向循环链表的C语言实现:(codeblocks完美运行)
#include <stdio.h>
#include <stdlib.h>
typedef struct double_list
{
int date;
struct double_list *pre;
struct double_list *next;
}list;
//创建头结点
list* create_node()
{
list *node = (list*)malloc(sizeof(list));
if(node == NULL)
{
printf("创建头结点失败!\n");
return NULL;
}
node->pre = node;
node->next = node;
return node;
}
//插入元素
int insert_list(list *head)
{
if(head == NULL)
{
printf("链表为空!\n");
return 0;
}
list *p = head;
int val;
printf("请输入要插入的元素:");
scanf("%d",&val);
list *newnode = create_node();
newnode->date = val;
while(p->next != head)
p = p->next;
newnode->pre = p;
newnode->next = p->next;
p->next = newnode;
return 1;
}
//打印双向循环链表
int print_list(list *head)
{
if(head == NULL)
{
printf("链表为空!\n");
return 0;
}
list *ptr = head->next;
while(ptr != head)
{
printf("%d ",ptr->date);
ptr = ptr->next;
}
}
int delete_list(list *head)
{
if(head == NULL)
{
printf("链表为空!\n");
return ;
}
list *p = head;
list *q = head->next;
int val;
printf("请输入要删除的元素:");
scanf("%d",&val);
while(p->next != head)
{
if(q->date == val)
{
if(q->next == head)
{
p->next = head;
free(q);
return 1;
}
q->next->pre = p;
p->next = q->next;
free(q);
return 1;
}
p = p->next;
q = q->next;
}
printf("没有找到该元素%d\n",val);
return 0;
}
int update_list(list *head)
{
if(head == NULL)
{
printf("链表为空!\n");
return ;
}
list *temp = head;
int olddate,newdate;
printf("请输入要修改的值:");
scanf("%d",&olddate);
printf("修改为:");
scanf("%d",&newdate);
while(temp->next != head)
{
if(temp->next->date == olddate)
{
temp->next->date = newdate;
return 1;
}
temp = temp->next;
}
printf("没有找到要修改的元素!\n");
return 0;
}
int seek_list(list *head)
{
if(head == NULL)
{
printf("链表为空!\n");
return ;
}
int val,i=0;
list *p = head;
printf("请输入要查找的元素:");
scanf("%d",&val);
while(p->next != head)
{
i++;
if(p->next->date == val)
{
printf("查找到该元素%d,位置为%d\n",val,i);
return 1;
}
p = p->next;
}
printf("没有找到该元素!\n");
return 0;
}
void menu()
{
system("cls");//清屏+
printf("\t\t|===============================================|\t\t\n");
printf("\t\t|================双向循环链表操作===============|\t\t\n");
printf("\t\t|===================1.插入元素==================|\t\t\n");
printf("\t\t|===================2.打印链表==================|\t\t\n");
printf("\t\t|===================3.删除元素==================|\t\t\n");
printf("\t\t|===================4.修改链表==================|\t\t\n");
printf("\t\t|===================5.查找元素==================|\t\t\n");
printf("\t\t|==请输入对应的数字执行对应的功能!(输入0退出)==|\t\t\n");
printf("\t\t|====== 作者:RXX 时间:2017/07/06 ======|\t\t\n");
printf("\t\t|===============================================|\t\t\n");
}
int main()
{
list *head = create_node();
int num;
menu();
scanf("%d",&num);
while(num)
{
switch(num)
{
case 1:
printf("插入元素操作:\n");
if(insert_list(head))
printf("插入节点成功!\n");
else
printf("插入节点失败!\n");
break;
case 2:
printf("打印元素操作:\n");
printf("打印双向链表:\n");
print_list(head);
break;
case 3:
printf("删除元素操作:\n");
if(delete_list(head))
printf("删除节点成功!\n");
break;
case 4:
printf("修改元素操作:\n");
if(update_list(head))
printf("修改元素成功!\n");
break;
case 5:
printf("查找元素操作:\n");
if(seek_list(head))
printf("查找元素成功!\n");
break;
}
getch();
menu();
scanf("%d",&num);
}
printf("\t\t|================感谢使用!再见!===============|\t\t\n");
return 0;
}
运行界面: