单向链表的操作
实现功能:创建链表、头插、尾插、头删除、尾删除、遍历打印、删除预设值相同的节点、重设值、去重、翻转、排序、清空、释放。
测试代码在文章末尾。
#include "linklist.h" #include <stdio.h> #include <stdlib.h> #include <string.h> /*typedef struct _node{ int data; struct _node* next; }LinkList_t; #define LinkList_t List_t */ /************************************ * @b 创建链表的头 * ***********************************/ List_t* list_creat(void) { List_t* list = NULL; if((list = (List_t*)malloc(sizeof(List_t))) == NULL) { printf("Failed malloc to creat list"); return NULL; } list->data = 0; list->next = NULL; return list; } /************************************ * @b 创建链表的一个节点 * ***********************************/ List_t* list_creat_node(data_t _data) { List_t* node = (List_t*)malloc(sizeof(List_t)); if(node == NULL) { printf("Failed malloc to creat node\n"); return NULL; } node->data = _data; /*给新结点的数据赋值*/ node->next = NULL; /*把新节点的下一个,指向NULL*/ return node; } /************************************ * @b 判断链表是否为空 * ***********************************/ int list_empty(List_t* head) { return head->next == NULL ? -1:0; } /************************************ * @b 头插法 * ***********************************/ int list_insert_head(List_t* head,data_t val) { List_t* node = list_creat_node(val); /*创建一个新节点并判断是否成功*/ if(node == NULL) { printf("Failed insert head\n"); return -1; } node->next = head->next; /*把新节点的下一个,指向头所指的下一个*/ head->next = node; /*把头所指的下一个,指向新节点*/ return 0; } /************************************ * @b 尾插法 * ***********************************/ int list_insert_tail(List_t* head,data_t val) { List_t* node = list_creat_node(val); /*创建一个新节点并判断是否成功*/ if(node == NULL) { printf("Fail insert tail\n"); return -1; } while (head->next != NULL) /*遍历链表找到结尾*/ { head = head->next; } head->next = node; /*把结尾所指的下一个,指向新节点*/ return 0; } /************************************ * @b 头删 * ***********************************/ int list_delete_head(List_t* head) { List_t* p = NULL; if(list_empty(head)) /*判断节点是否为空*/ { printf("Failed delete ,list is empty\n"); return -1; } p = head->next; head->next = head->next->next; /*把头所指的下一个,指向新节点*/ free(p); p = NULL; return 0; } /************************************ * @b 尾删 * ***********************************/ int list_delete_tail(List_t* head) { List_t* p = NULL; if(list_empty(head)) /*判断节点是否为空*/ { printf("Failed delete tail,list is empty\n"); return -1; } while (head->next != NULL) /*遍历链表找到结尾*/ { p = head; /*当head是结尾时,p是倒数第二个*/ head = head->next; } free(head); head = NULL; p->next = NULL; return 0; } /*********************************** *@b 删除链表当中所有和用户值相同的节点 **********************************/ int list_delete_data(List_t* head,data_t val) { List_t* p = NULL; int res = 0; if(list_empty(head)) /*判断节点是否为空*/ { printf("Failed delete data,list is empty\n"); return -1; } while (head->next != NULL) /*遍历链表到结尾*/ { p = head->next; /*复制下一个节点地址*/ if((p->data) == val) /*如果节点的值和用户预设值一样*/ { head->next = p->next; /*把之前的节点链接到这个要删除的节点之后*/ free(p); /*删除这个节点*/ p = NULL; res++; /*删除计数+1*/ } else /*否则节点的值和用户预设不一样*/ { head = head->next; /*指向下一个结点*/ } } return res; /*返回删除节点的个数*/ } /********************************** *@b 重设节点 * ********************************/ int list_reset_data(List_t* head,int old,int new) { int res = 0; if(list_empty(head)) /*判断节点是否为空*/ { printf("Failed reset data,list is empty\n"); return -1; } while (head->next != NULL) /*遍历链表找到结尾*/ { if(((head->next)->data) == old) /*找出所有和用户预设值一样的节点并更改数据值*/ { ((head->next)->data) = new; res++; } else { head = head->next; /*把头指向新节点*/ } } return res; /*返回更改节点的个数*/ } /***************************************************************** * * p q * head head->next dest->next q->next (NULL) * _________ _________ _________ * |\\\\\\\| |____1____| |____1____| |____2____| * ^^^ same ^^^ * |||--------------||| * (delete this) * ******************************************************************/ /********************************** *@b 单向链表去重 * ********************************/ int list_delete_duplicate(List_t* head) { List_t* p = NULL; List_t* q = NULL; int cnt = 0; if(list_empty(head)) /*判断节点是否为空*/ { printf("Failed delete duplicate,list is empty\n"); return -1; } for(;head->next != NULL;head = head->next) { p = head->next; while(p->next != NULL) { q = p->next; if(q->data == head->next->data) { p->next = q->next; free(q); q = NULL; cnt++; } else { p = p->next; } } } return cnt; } #if 0 int list_delete_duplicate(List_t* head) { List_t* dest = NULL; List_t* src = NULL; int cnt = 0; while (head->next != NULL) { dest = head->next; while (dest->next != NULL) { src = dest->next; if(head->next->data == src->data)//不要移动dest,防止跳过后面相同的节点 { dest->next = src->next; //删除中间相同的节点 free(src); src = NULL; cnt++; } else { dest = dest->next; //跳过不相同的节点 } } head = head->next; } return cnt; /*返回删除节点的个数*/ } #endif /*********************************** *@b 翻转链表 **********************************/ int list_reverse(List_t** head) /*为什么要用到二级指针*/ { /*因为我们需要更传参的值,所以要用到传参的地址*/ List_t* new = NULL; List_t* p = NULL; if(list_empty(*head)) /*判断链表是否为空*/ { printf("Failed reverse,list is empty\n"); return -1; } if((new = list_creat()) == NULL) { printf("Failed reverse,can not creat new list\n"); return -1; } while ((*head)->next != NULL) { p = (*head)->next; (*head)->next = (*head)->next->next; p->next = new->next; new->next = p; } free(*head); *head = new; return 0; } /*********************************** *@b 链表排序 **********************************/ int list_sort(List_t* head) { List_t* p = NULL; List_t* q = NULL; if(list_empty(head)) /*判断链表是否为空*/ { printf("Failed sort,list is empty\n"); return -1; } for(;head->next->next != NULL;head = head->next) { p = head->next; while (p->next != NULL) { q = p->next; if(q->data < head->next->data) { p->next = p->next->next; q->next = head->next; head->next = q; } else { p = p->next; } } } return 0; } /*********************************** *@b 遍历打印 **********************************/ int list_print(List_t* head) { if(list_empty(head)) /*判断节点是否为空*/ { printf("Failed print,list is empty\n"); return -1; } while (head->next != NULL) /*遍历链表找到结尾*/ { head = head->next; /*打印之前先跳过头(头不存放数据)*/ printf("%-3d",head->data); } putchar('\n'); return 0; } /*********************************** *@b 清空链表 **********************************/ void list_clean(List_t* head) { List_t* p = NULL; while (head->next != NULL) /*遍历链表找到结尾*/ { p = head->next; /*复制头所指的节点地址*/ head->next = head->next->next; /*把头指向新节点*/ free(p); p = NULL; } } /*********************************** *@b 释放链表 **********************************/ void list_free(List_t* head) { if(head != NULL) { list_clean(head); free(head); head = NULL; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」