学习建议:
1、看完一节视频,立即去实践,随学随练。
2、优秀的视频比自己去看书,更能消化理解
3、学习效果的检验方法是独立实现功能,实现后对比视频中的教学代码,查漏补缺。
4、独立编写过程中记录。
教学视频:https://www.bilibili.com/video/BV1yv411y7AW?p=5&vd_source=da60f9e1bc3321cae28c29fe80e9b078
REAME 如下:
2024/04/30
-目标:独立实现动态单向链表的增删改查
-编译方式:gcc -g link_list.c
迭代如下:
版本1:link_list.c-v0.1:
step1.[链表初始化],也就是创建链表,也就是创建一个头节点,并且使 next = NULL;
注意:初始化函数不需要形参(和大多数初始化函数一样),只需要返回值是一个指针即可。
step2.链表节点的增加,也就是链表节点的插入。
-[尾插法]:借助尾指针prear 该指针始终指向尾节点。
存在问题:函数设计的参数列表设计有问题。
-头插法:待增加。
step3.[链表的遍历]。借助辅助指针 current。
-存在的问题:尾节点的数据未打印出来。解决:正确的循环条件是 while(current != NULL)
版本2:
link_list.c-v0.2:
step1.继续完成使用[头插法完成在某个节点前面插入新节点]。
-使用两个辅助指针pre、current, 同时移动两个指针。
-初始时,pre指向头节点, current 指向头节点的下一个节点。
存在的问题:1、注意while 循环的条件; 查找到数据后应退出循环
2、需要考虑没有找到带查找节点。
step2.[清空链表],只保留头节点。记录释放节点的下一个节点。
-存在问题: 别忘了最后要把头节点指向NULL。
step3.[删除某节点] 修改指向; 释放空间
注意: 释放空间后,需要将该指针变量指向NULL。
step4.[销毁链表],头节点都释放了。
存在的问题: 销毁链表后进行遍历链表,遍历出来的头节点的数据是随机值,不正常,因此将销毁链表函数的形参修改为了二级指针。
存在的问题:
-1、看教学视频中老师是先在.h 文件中先声明函数,然后再在.c 文件中编写函数。
而我只在.h 文件中声明了一个结构体,然后只顾着在.c 文件中写函数了。
参考连接:
https://www.bilibili.com/video/BV1yv411y7AW?p=5&vd_source=da60f9e1bc3321cae28c29fe80e9b078
头文件:link_list.h
typedef struct _link_node{
int value;
struct _link_node* next;
}link_node;
源文件:版本1:link_list.c-v0.1
#include <stdio.h>
#include <stdlib.h>
#include "link_list.h"
/*链表的遍历*/
void traverse_link_list(link_node* phead)
{
link_node* current = phead;
if(phead->next == NULL)
printf("link list is null!\n");
while(current != NULL)
{
printf("%d\n", current->value);
current = current -> next;
}
}
/*链表的插入-尾插法*/
void tail_insert_link_list(link_node* current, link_node** rear, int value)
{
link_node* new = NULL;
new = (link_node*)malloc(sizeof(link_node));
new->value = value;
new->next = NULL;
current->next = new;
rear = &new;
}
/*链表初始化*/
link_node* init_link_list()
{
link_node* node = (link_node*)malloc(sizeof(link_node));
node -> next = NULL;
node -> value = -1;
return node;
}
int main()
{
link_node* phead;
link_node* rear = NULL;
link_node* current;
/*链表初始化*/
phead = init_link_list();
int i = 0;
current = phead;
/*使用尾插法填充链表*/
for(i = 1; i < 6; i++)
{
tail_insert_link_list(current, &rear, i);
current = current -> next;
}
/*遍历链表*/
traverse_link_list(phead);
return 0;
}
版本2:link_list.c-v0.2
#include <stdio.h>
#include <stdlib.h>
#include "link_list.h"
/*销毁链表*/
void destory_link_list(link_node** phead)
{
if(*phead == NULL)
return;
link_node* current = *phead;
link_node* pnext;
while(current != NULL)
{
pnext = current->next;
free(current);
current = pnext;
}
*phead = NULL;
}
/*删除某节点*/
void remove_node(link_node* phead, int value)
{
if(phead == NULL)
return;
link_node* pre = phead;
link_node* current = pre->next;
while(current != NULL)
{
if(current->value == value)
break;
pre = current;
current = current->next;
}
/*没找到*/
if(current == NULL)
return;
pre->next = current->next;
free(current);
current = NULL;/*释放后仍要让该指针变量指向NULL*/
}
/*清空链表*/
void clean_link_list(link_node* phead)
{
if(phead == NULL)
return;
link_node* current = phead->next;
link_node* pnext;
while(current != NULL)
{
pnext = current->next; /*先记录当前节点的下一个节点*/
printf("%d ", current->value);
free(current); /*释放当前节点*/
current = pnext; /*让current指向下一节点*/
}
/*别忘了最后要将头节点指向NULL*/
phead->next = NULL;
printf("节点已被删除\n");
}
/*插入节点-在某节点前插入新节点*/
void head_insert_link_list(link_node* phead, int cur_value, int new_value)
{
if(phead == NULL)
{
return;
}
link_node* pre = phead;
link_node* current = pre->next;
link_node* new = NULL;
/*1.查找某节点*/
while(current != NULL)
{
/*查找到节点后应立即退出循环*/
if(current->value == cur_value)
break;
pre = current; /*记录节点*/
current = current->next;
}
#if 0
/*注释掉该代码块,没找到节点,会将新节点追加在尾节点的后面*/
/*没有查找到节点立即退出*/
if(current == NULL)
return;
#endif
/*2.插入新节点*/
new = (link_node*)malloc(sizeof(link_node));
new->value = new_value;
/*特别注意:下面的顺序不能颠倒*/
new->next = current;
pre->next = new;
}
/*链表的遍历*/
void traverse_link_list(link_node* phead)
{
if(phead == NULL)
{
printf("该链表可能已经被销毁!\n");
return;
}
link_node* current = phead;
if(phead->next == NULL)
printf("link list is null!\n");
while(current != NULL)
{
printf("%d\n", current->value);
current = current -> next;
}
}
/*链表的插入-尾插法*/
void tail_insert_link_list(link_node* current, link_node** rear, int value)
{
link_node* new = NULL;
new = (link_node*)malloc(sizeof(link_node));
new->value = value;
new->next = NULL;
current->next = new;
rear = &new;
}
/*链表初始化*/
link_node* init_link_list()
{
link_node* node = (link_node*)malloc(sizeof(link_node));
node -> next = NULL;
node -> value = -1;
return node;
}
int main()
{
link_node* phead;
link_node* rear = NULL;
link_node* current;
/*链表初始化*/
phead = init_link_list();
int i = 0;
current = phead;
/*使用尾插法填充链表*/
for(i = 1; i < 6; i++)
{
tail_insert_link_list(current, &rear, i);
current = current -> next;
}
/*遍历链表*/
traverse_link_list(phead);
printf("链表填充完毕!\n");
/*在某节点前插入新节点*/
head_insert_link_list(phead, 10, 0);
traverse_link_list(phead);
/*删除某节点*/
remove_node(phead, 3);
printf("已删除节点!\n");
traverse_link_list(phead);
/*清空链表*/
clean_link_list(phead);
printf("已清空链表!\n");
traverse_link_list(phead);
/*销毁链表*/
destory_link_list(&phead);
traverse_link_list(phead);
return 0;
}