说明
上一篇文章我讲了如何编写单链表的代码,这次讲双向链表。
1.确定节点成员
struct dclinklist
{
int data;
struct dclinklist *prev;
struct dclinklist *next;
};
双向循环链表的成员就比单链表多了个指向前驱节点的指针。啊,那有的读者就要问了,多了这个指针有什么用啊。是这样的,我画个图就好理解了。
那是不是单链表就没办法删除节点了呀,肯定不是的,单链表只能删除当前遍历位置的下一个节点,而无法删除自己而已,但是双向链表可以。
2.创建节点
创建节点跟单链表的大同小异了,就是初始化不同。
struct dclinklist *request_node(int data)
{
struct dclinklist *new_node = (struct dclinklist *)malloc(sizeof(new_node));
if(new_node == NULL)
{
printf("申请节点失败\n");
return NULL;
}
new_node->data = data;
new_node->next = new_node;
new_node->prev = new_node;
return new_node;
}
3.插入节点
头插:
void insert_data_to_head(struct dclinklist *head,struct dclinklist *new_node)
{
head->next->prev = new_node;
new_node->next = head->next;
new_node->prev = head;
head->next = new_node;
}
尾插:
void insert_data_to_tail(struct dclinklist *head,struct dclinklist *new_node)
{
head->prev->next = new_node;
new_node->prev = head->prev;
new_node->next = head;
head->prev = new_node;
}
双向链表的尾插还是比较简单的,并且在数据的获取中,很多时候都是用尾插。
4.遍历双向循环链表
void display_linklist(struct dclinklist *head)
{
struct dclinklist *pos = head->next;
while(pos != head)
{
printf("%d ",pos->data);
pos = pos->next;
}
printf("\n");
}
5.创建链表
struct dclinklist *head;
head = request_node(-1);
6.查找链表数据
struct dclinklist *find_data_in_list(struct dclinklist *head, int data)
{
struct dclinklist *pos = head->next;
struct dclinklist *temp = NULL;
while(pos != head)
{
if(pos->data == data)
{
return pos;
}
pos = pos->next;
}
return NULL;
}
7.修改链表数据
void modify_data_in_list(struct dclinklist *head, int data, int modify_data)
{
struct dclinklist *pos = head->next;
struct dclinklist *temp = NULL;
while(pos != head)
{
if(pos->data == data)
{
pos->data = modify_data;
return ;
}
pos = pos->next;
}
}
8.删除链表数据
下面代码是删除所有值为data的节点
void delete_data_in_list(struct dclinklist *head,int data)
{
struct dclinklist *pos = head->next;
struct dclinklist *temp = NULL;
while(pos != head)
{
if(pos->data == data)
{
temp = pos;
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
free(temp);
}
pos = pos->next;
}
}
9.主函数
int main(void)
{
struct dclinklist *head, *new_node, *insert_node, *basic_node, *mv_node, *find_node;
int data;
int cmd;
char ch;
int ret;
int find_data = 0;
int modify_data;
int insert_data,basic_data;
head = request_node(-1);
while(1)
{
printf("请输入你的选择: 1.头插数据 2.删除数据 3.显示数据 4.尾插数据 5.查找数据 6.修改数据 7.移动数据\n");
scanf("%d",&cmd);
switch(cmd)
{
case 1:
printf("请输入数据\n");
scanf("%d",&data);
new_node = request_node(data);
insert_data_to_head(head,new_node);
break;
case 2:
printf("请输入要删除的数据\n");
scanf("%d",&data);
delete_data_in_list(head,data);
break;
case 3:
display_linklist(head);
break;
case 4:
printf("请输入数据\n");
scanf("%d",&data);
new_node = request_node(data);
insert_data_to_tail(head,new_node);
break;
case 5:
printf("请输入要查找的数据\n");
scanf("%d",&data);
find_node = find_data_in_list(head,data);
if(find_node == NULL)
{
printf("该数据不存在!\n");
}
else
{
printf("该数据存在!\n");
}
break;
case 6:
printf("请输入要修改的数据\n");
scanf("%d",&data);
find_node = find_data_in_list(head,data);
if(find_node == NULL)
{
printf("该数据不存在!\n");
break;
}
else
{
printf("该数据存在!\n");
}
printf("请输入修改后的数据\n");
scanf("%d",&modify_data);
modify_data_in_list(head, data, modify_data);
break;
case 7:
printf("请输入要移动的数据:");
scanf("%d", &insert_data);
insert_node = find_data_in_list(head, insert_data);
if(insert_node == NULL)
{
printf("该数据节点不存在,无法执行数据移动操作\n");
break;
}
mv_node = delete_node_in_list(head,insert_data);
printf("请输入要移动到的位置的数据基准点:");
scanf("%d", &basic_data);
basic_node = find_data_in_list(head, basic_data);
if(basic_node == NULL)
{
printf("该数据节点不存在,无法执行数据移动操作\n");
break;
}
printf("请输入选择:a:数据插入到数据基准点前面, b:数据插入到数据基准点后面\n");
getchar(); //取走缓冲区的'\n'
scanf("%c", &ch);
if(ch == 'a')
{
insert_data_to_tail(basic_node,mv_node);
}
if(ch == 'b')
{
insert_data_to_head(basic_node,mv_node);
}
default:
break;
}
}
return 0;
}
10.运行结果
结束语
双向链表到此结束了,多加练习,并且自己尝试写一个完成的程序出来,更能事半功倍。下一篇文章我将会介绍一下内核链表的代码怎么写。