一、双向循环链表的节点设计
图解:
示例代码:
// 双向循环链表的节点设计
typedef struct node
{
// 数据域
int data;
// 指针域
struct node *prev_p;
struct node *next_p;
}node_t, *node_p;
二、初始化空链表(头节点)
图解:
示例代码:
/**
* @brief 初始化空链表(头节点)
* @note None
* @param None
* @retval 成功:返回指向这个头节点的指针
* 失败:返回NULL
*/
node_p DOUBLYLINK_LIST_InitHeadNode(void)
{
// 1、给头节点申请一个堆内存空间
node_p p = malloc(sizeof(struct node));
bzero(p, sizeof(struct node));
// 2、将头节点的指针域的变量prev_p、next_p指向自己
if ( p != NULL)
{
p->prev_p = p;
p->next_p = p;
}
else
return NULL;
// 3、成功返回头节点
return p;
}
三、初始化数据节点
图解:
示例代码:
/**
* @brief 初始化数据节点
* @note None
* @param data:数据
* @retval 成功:返回指向这个数据节点的指针
* 失败:返回NULL
*/
node_p DOUBLYLINK_LIST_InitDataNode(int data)
{
// 1、给头节点申请一个堆内存空间
node_p p = malloc(sizeof(struct node));
bzero(p, sizeof(struct node));
// 2、将头节点的指针域的变量prev_p、next_p指向自己,以及对数据域的变量data进行传参赋值
if ( p != NULL)
{
// 数据域
p->data = data;
// 指针域
p->prev_p = p;
p->next_p = p;
}
else
return NULL;
// 3、成功返回数据节点
return p;
}
四、判断链表是否为空
图解:
示例代码:
/**
* @brief 判断链表是否为空
* @note None
* @param head_node:头节点
* @retval 链表为空,返回true
* 链表为非空,返回false
*/
bool DOUBLYLINK_LIST_IfEmpty(node_p head_node)
{
return ((head_node->prev_p == head_node) && (head_node->next_p == head_node));
}
五、插入数据(头插法)
图解:
示例代码:
/**
* @brief 插入数据(头插法)
* @note None
* @param head_node:头节点
* new_node: 要插入的数据节点
* @retval None
*/
void DOUBLYLINK_LIST_InsertHeadData(node_p head_node, node_p new_node)
{
node_p prev_node = head_node;
node_p next_node = head_node->next_p;
// 1、
new_node->prev_p = prev_node;
// 2、
new_node->next_p = next_node;
// 3、
prev_node->next_p = new_node;
// 4、
next_node->prev_p = new_node;
}
六、插入数据(尾插法)
图解:
示例代码:
/**
* @brief 插入数据(尾插法)
* @note None
* @param head_node:头节点
* new_node: 要插入的数据节点
* @retval None
*/
void DOUBLYLINK_LIST_InsertTailData(node_p head_node, node_p new_node)
{
// 1、设置一个中间指针,将指针指向链表的末尾
node_p tmp_p = head_node->prev_p;
// 2、让new_node的prev_p指向tmp_p
new_node->prev_p = tmp_p;
// 3、让new_node的next_p指向head_node
new_node->next_p = head_node;
// 4、再让tmp_p的next_p指向new_node
tmp_p->next_p = new_node;
// 5、再让head_node的prev_p指向new_node
head_node->prev_p = new_node;
}
七、遍历整个链表
图解:
示例代码:
/**
* @brief 遍历整个链表
* @note 从左到右遍历
* @param head_node:头节点
* @retval 成功:返回0
* 失败:返回非0
*/
int DOUBLYLINK_LIST_ShowList(node_p head_node)
{
// 1、判断链表是否为空,是的话,返回-1
if (DOUBLYLINK_LIST_IfEmpty(head_node))
return -1;
// 2、遍历整个链表,并打印里面的节点的数据
node_p tmp_p = NULL;
int i = 0;
printf("================双向链表中的数据====================\n\n");
for (tmp_p = head_node->next_p, i=0; tmp_p != head_node; tmp_p = tmp_p->next_p,i++)
{
printf("双向链表中的第%d的节点,数据为:%d\n", i, tmp_p->data);
}
printf("===================================================\n");
// 3、成功返回0
return 0;
}
八、删除链表中的某个数据
图解:
示例代码:
/**
* @brief 删除某个数据
* @note 从左到右遍历,通过数据找到要删除的数据节点,将其删除
* @param head_node:头节点
* del_data: 要删除的数据
* @retval 成功:返回0
* 失败:返回非0
*/
int DOUBLYLINK_LIST_DelData(node_p head_node, int del_data)
{
// 1、判断链表是否为空,是的话,返回-1
if (DOUBLYLINK_LIST_IfEmpty(head_node))
free(head_node);
// 2、从左到右开始遍历链表,找到其要删除的节点,并将各个数据节点进行保存
node_p tmp_p = head_node;
node_p del_node = NULL;
node_p prev_node = NULL;
node_p next_node = NULL;
int flag = 0;
if (tmp_p->next_p->data != del_data)
{
for (tmp_p = head_node->next_p ; tmp_p->next_p != head_node ; tmp_p = tmp_p->next_p)
{
// 判断要删除的数据
if (tmp_p->next_p->data == del_data)
{
flag = 1;
// 将要删除的数据节点、和其上一个节点、下一个节点进行保存
prev_node = tmp_p;
del_node = prev_node->next_p;
next_node = del_node->next_p;
}
}
}
else
{
flag = 1;
// 将要删除的数据节点删除(将其从逻辑关系中删除)
prev_node->next_p = next_node;
if(next_node != NULL)
next_node->prev_p = prev_node;
}
else
{
// 将要删除的数据节点、和其上一个节点、下一个节点进行保存
prev_node = tmp_p;
del_node = prev_node->next_p;
next_node = del_node->next_p;
// 3、将要删除的数据节点删除(将其从逻辑关系中删除)
prev_node->next_p = next_node;
if(next_node != NULL)
next_node->prev_p = prev_node;
}
// 4、释放掉要删除的数据节点
free(del_node);
// 5、成功返回0
return 0;
}
九、查找链表中的某个数据
图解:
示例代码:
/**
* @brief 删除数据
* @note 从左到右遍历,通过数据找到要删除的数据节点,将其删除
* @param head_node:头节点
* del_data: 要删除的数据
* @retval 成功:返回0
* 失败:返回非0
*/
int DOUBLYLINK_LIST_DelData(node_p head_node, int del_data)
{
// 1、判断链表是否为空,是的话,返回-1
if (DOUBLYLINK_LIST_IfEmpty(head_node))
return -1;
// 2、从左到右开始遍历链表,找到其要删除的节点,并将各个数据节点进行保存
node_p tmp_p = head_node;
node_p del_node = NULL;
node_p prev_node = NULL;
node_p next_node = NULL;
int flag = 0;
if (tmp_p->next_p->data != del_data)
{
for (tmp_p = head_node->next_p ; tmp_p->next_p!=head_node ; tmp_p=tmp_p->next_p)
{
// 判断要删除的数据
if (tmp_p->next_p->data == del_data)
{
flag = 1;
// 将要删除的数据节点、和其上一个节点、下一个节点进行保存
prev_node = tmp_p;
del_node = prev_node->next_p;
next_node = del_node->next_p;
}
}
}
else
{
flag = 1;
// 将要删除的数据节点、和其上一个节点、下一个节点进行保存
prev_node = tmp_p;
del_node = prev_node->next_p;
next_node = del_node->next_p;
}
if (flag == 0)
return -2;
// 3、将要删除的数据节点删除(将其从逻辑关系中删除)
prev_node->next_p = next_node;
if(next_node != NULL)
next_node->prev_p = prev_node;
// 4、释放掉要删除的数据节点
free(del_node);
// 5、成功返回0
return 0;
}
十、修改链表中的某个数据
图解:
示例代码:
/**
* @brief 修改某个数据
* @note None
* @param head_node: 头节点
* find_data: 要修改的数据
* change_data: 修改的数据
*
* @retval 成功:返回0
* 失败:返回非0
*/
int DOUBLYLINK_LIST_ChangeData(node_p head_node, int find_data, int change_data)
{
// 1、判断单向链表是否为空,是的话,返回-1;
if (DOUBLYLINK_LIST_IfEmpty(head_node))
return -1;
// 2、遍历整个链表,找到数据,并打印里面的数据和位置
node_p change_node = DOUBLYLINK_LIST_FindDataPos(head_node, find_data);
if ((change_node != ((node_p)-1)) && (change_node != ((node_p)-2)))
{
change_node->data = change_data;
return 0;
}
else
{
printf("链表中没有这个数据\n");
return -2;
}
}
十一、销毁链表
图解:
示例代码:
/**
* @brief 销毁链表
* @note None
* @param head_node: 头节点
* @retval None
*/
void DOUBLYLINK_LIST_DelList(node_p head_node)
{
// 1、如果链表为空,那么直接释放头节点空间即可
if (DOUBLYLINK_LIST_IfEmpty(head_node))
{
free(head_node);
return;
}
// 2、
node_p tmp_p = NULL; // 是用来遍历的
node_p prev_node = head_node;
node_p del_node = head_node->next_p;
node_p next_node = del_node->next_p;
for (tmp_p= head_node->next_p; tmp_p->next_p!=head_node; tmp_p=tmp_p->next_p)
{
// a、删除节点并释放其内存
prev_node->next_p = next_node;
if (next_node != NULL)
next_node->prev_p = prev_node;
free(del_node);
// b、轮回继续
del_node = next_node;
next_node = next_node->next_p;
}
// 3、释放头节点
free(head_node);
return;
}
以上的内容属于我的课后笔记。