学习建议:
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;
}