双向链表的使用
1.双链表节点设计
c
复制代码
typedef struct double_list{
int data;
struct double_list *next;
struct double_list *prev;
}double_list_t;
2.初始化双链表头节点,返回头节点指针
c
复制代码
double_list_t *double_list_init()
{
double_list_t *head_node = malloc(sizeof(double_list_t));
if (head_node != NULL)
{
head_node->next = NULL;
head_node->prev = NULL;
}
else
{
printf("[double_list_init]申请头节点失败\n");
}
return head_node;
}
3.双链表头插节点
(1) 示例代码:
c
复制代码
int insert_list_head(int newdata, double_list_t *list)
{
// 申请一个节点 -堆空间
double_list_t *new_node = malloc(sizeof(double_list_t));
if (new_node == NULL)
{
printf("[insert_list_head]申请新的节点失败\n");
return -1; // 申请内存失败
}
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
new_node->prev = NULL;
// 当链表为空时
if (list->next == NULL)
{
list->next = new_node;
new_node->prev = list;
}
// 链表不为空时
else
{
// 插入节点
new_node->next = list->next;
list->next = new_node;
new_node->next->prev = new_node;
new_node->prev = list;
}
return 0;
}
(2) 画图解析:
4.双链表尾插节点
(1) 示例代码:
c
复制代码
int insert_list_tail(int newdata, double_list_t *list)
{
// 申请一个节点 -堆空间
double_list_t *new_node = malloc(sizeof(double_list_t));
if (new_node == NULL)
{
printf("[insert_list_tail]申请新的节点失败\n");
return -1; // 申请内存失败
}
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
new_node->prev = NULL;
// 定义指针p去找到链表的尾部
double_list_t *p = list;
while (p->next != NULL)
{
p = p->next;
}
// 此时p已经到最后一个节点的位置
new_node->next = p->next;
p->next = new_node;
new_node->prev = p;
return 0;
}
(2) 画图解析:
4.双链表中间插入节点
(1) 示例代码:
c
复制代码
int insert_list_mid(int olddata, int newdata, double_list_t *list)
{
// 找到要插入的节点
double_list_t *p = list;
while (p->next != NULL)
{
p = p->next;
if (p->data == olddata)
{
break;
}
}
// 申请一个新的节点 -堆空间
double_list_t *new_node = malloc(sizeof(double_list_t));
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
new_node->prev = NULL;
// p指向最后一个节点
if (p->next == NULL)
{
// 如果最后一个节点是要插入的数据
if (p->data == olddata)
{
new_node->next = p->next;
p->next = new_node;
new_node->prev = p;
}
else
{
printf("[insert_list_mid]要插入的数据不存在\n");
return -1;
}
}
else // 遍历到中间找到需要插入的节点
{
new_node->next = p->next;
p->next = new_node;
new_node->prev = p;
new_node->next->prev = new_node;
}
return 0;
}
(2) 画图解析:
5.双链表删除节点
(1) 示例代码:
c
复制代码
int list_delnode(int deldata, double_list_t *list)
{
// p指向链表的头节点
double_list_t *p = list;
while (p->next != NULL)
{
// 找到要删除的节点并进行删除
if (p->data == deldata)
{
p->prev->next = p->next;
p->next->prev = p->prev;
double_list_t *temp = p->next; // 将temp指针指向p的下一个节点
p->next = NULL;
p->prev = NULL;
free(p); // 释放p后此时p是野指针
p = temp; // p往后移动
}
else
{
// p往后遍历
p = p->next;
}
}
// 遍历到最后一个节点
if (p->next == NULL)
{
// 若最后一个节点是要删除的节点,则删除
if (p->data == deldata)
{
p->prev->next = p->next;
p->prev = NULL;
free(p);
}
else
{
printf("[list_delnode]最后一个节点不是要删除的节点\n");
return 0;
}
}
}
(2) 画图解析:
6.双链表修改节点
c
复制代码
int list_update_node(int old_data, int new_data, double_list_t *list)
{
double_list_t *p = list;
while (p->next != NULL)
{
p = p->next; // p往后移动
if (p->data == old_data)
{
p->data = new_data;
}
}
return 0;
}
7.双链表遍历,打印节点数据
c
复制代码
int list_show(double_list_t *list)
{
double_list_t *p = list; //p指向头结点
while (p->next != NULL)
{
p = p->next;
printf("[list_show]当前p指向的节点数据:%d\n", p->data);
}
}
8.完整代码
c
复制代码
#include <stdio.h>
#include <stdlib.h>
// 1.封装一个结构体来表示双链表
typedef struct double_list{
int data;
struct double_list *next;
struct double_list *prev;
}double_list_t;
// 2.初始化双链表-->定义结构体变量 创建头节点
double_list_t *double_list_init()
{
double_list_t *head_node = malloc(sizeof(double_list_t));
if (head_node != NULL)
{
head_node->next = NULL;
head_node->prev = NULL;
}
else
{
printf("[double_list_init]申请头节点失败\n");
}
return head_node;
}
// 头插
int insert_list_head(int newdata, double_list_t *list)
{
// 申请一个节点 -堆空间
double_list_t *new_node = malloc(sizeof(double_list_t));
if (new_node == NULL)
{
printf("[insert_list_head]申请新的节点失败\n");
return -1; // 申请内存失败
}
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
new_node->prev = NULL;
// 当链表为空时
if (list->next == NULL)
{
list->next = new_node;
new_node->prev = list;
}
// 链表不为空时
else
{
// 插入节点
new_node->next = list->next;
list->next = new_node;
new_node->next->prev = new_node;
new_node->prev = list;
}
return 0;
}
/*@brief:3.插入数据-->尾插(在最后一个有效成员的后面插入数据)
*@param(in): newdata :待插入的数据
list:链表头节点
*@param(out):
*@retval:
*/
int insert_list_tail(int newdata, double_list_t *list)
{
// 申请一个节点 -堆空间
double_list_t *new_node = malloc(sizeof(double_list_t));
if (new_node == NULL)
{
printf("[insert_list_tail]申请新的节点失败\n");
return -1; // 申请内存失败
}
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
new_node->prev = NULL;
// 定义指针p去找到链表的尾部
double_list_t *p = list;
while (p->next != NULL)
{
p = p->next;
}
// 此时p已经到最后一个节点的位置
new_node->next = p->next;
p->next = new_node;
new_node->prev = p;
return 0;
}
// 节点中间插入链表
int insert_list_mid(int olddata, int newdata, double_list_t *list)
{
// 找到要插入的节点
double_list_t *p = list;
while (p->next != NULL)
{
p = p->next;
if (p->data == olddata)
{
break;
}
}
// 申请一个新的节点 -堆空间
double_list_t *new_node = malloc(sizeof(double_list_t));
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
new_node->prev = NULL;
// p指向最后一个节点
if (p->next == NULL)
{
// 如果最后一个节点是要插入的数据
if (p->data == olddata)
{
new_node->next = p->next;
p->next = new_node;
new_node->prev = p;
}
else
{
printf("[insert_list_mid]要插入的数据不存在\n");
return -1;
}
}
else // 遍历到中间找到需要插入的节点
{
new_node->next = p->next;
p->next = new_node;
new_node->prev = p;
new_node->next->prev = new_node;
}
return 0;
}
// 删除节点
int list_delnode(int deldata, double_list_t *list)
{
// p指向链表的头节点
double_list_t *p = list;
while (p->next != NULL)
{
// 找到要删除的节点并进行删除
if (p->data == deldata)
{
p->prev->next = p->next;
p->next->prev = p->prev;
double_list_t *temp = p->next; // 将temp指针指向p的下一个节点
p->next = NULL;
p->prev = NULL;
free(p); // 释放p后此时p是野指针
p = temp; // p往后移动
}
else
{
p = p->next;
}
}
// 遍历到最后一个节点
if (p->next == NULL)
{
// 若最后一个节点是要删除的节点,则删除
if (p->data == deldata)
{
p->prev->next = p->next;
p->prev = NULL;
free(p);
}
else
{
printf("[list_delnode]最后一个节点不是要删除的节点\n");
return 0;
}
}
}
// 修改节点
int list_update_node(int old_data, int new_data, double_list_t *list)
{
double_list_t *p = list;
while (p->next != NULL)
{
p = p->next; // p往后移动
if (p->data == old_data)
{
p->data = new_data;
}
}
return 0;
}
// 4.遍历链表,打印节点数据
int list_show(double_list_t *list)
{
double_list_t *p = list; //p指向头结点
while (p->next != NULL)
{
p = p->next;
printf("[list_show]当前p指向的节点数据:%d\n", p->data);
}
}
int main(int argc, char const *argv[])
{
// 初始化单链表 ,指向链表的头节点
double_list_t *my_list_head = double_list_init();
// 往链表插入数据
insert_list_tail(15, my_list_head);
insert_list_tail(16, my_list_head);
insert_list_tail(17, my_list_head);
insert_list_head(2, my_list_head);
insert_list_tail(15, my_list_head);
insert_list_tail(15, my_list_head);
insert_list_tail(15, my_list_head);
insert_list_mid(5, 6, my_list_head);
insert_list_mid(2, 88, my_list_head);
insert_list_mid(17, 15, my_list_head);
printf("============插入的节点============\n");
list_show(my_list_head);
printf("============插入的节点============\n");
// 删除节点
list_delnode(25, my_list_head);
// list_delnode(15, my_list_head);
list_delnode(2, my_list_head);
printf("============删除后的节点============\n");
list_show(my_list_head); // 打印数据
printf("============删除后的节点============\n");
// 修改数据
list_update_node(15, 115, my_list_head);
printf("============修改后的节点============\n");
list_show(my_list_head); // 打印数据
printf("============修改后的节点============\n");
return 0;
}
/*
执行结果:
[insert_list_mid]要插入的数据不存在
============插入的节点============
[list_show]当前p指向的节点数据:2
[list_show]当前p指向的节点数据:88
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:16
[list_show]当前p指向的节点数据:17
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
============插入的节点============
[list_delnode]最后一个节点不是要删除的节点
[list_delnode]最后一个节点不是要删除的节点
============删除后的节点============
[list_show]当前p指向的节点数据:88
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:16
[list_show]当前p指向的节点数据:17
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
============删除后的节点============
============修改后的节点============
[list_show]当前p指向的节点数据:88
[list_show]当前p指向的节点数据:115
[list_show]当前p指向的节点数据:16
[list_show]当前p指向的节点数据:17
[list_show]当前p指向的节点数据:115
[list_show]当前p指向的节点数据:115
[list_show]当前p指向的节点数据:115
[list_show]当前p指向的节点数据:115
============修改后的节点============
*/