C语言 - 基础数据结构和算法 - 单向链表
听黑马程序员教程《基础数据结构和算法 (C版本)》,照着老师所讲抄的,
视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1
喜欢的朋友可以去看看。
02 单向链表
#include<stdio.h > #include<stdlib.h> #include<string.h> // 用户自定义数据 typedef struct Student{ int id; // 学号 char name[32]; // 姓名 char classs[32]; // 班级 int ch,ma,en; // 语、数、外、总分 }st; // 链表结点 typedef struct LINKNODE{ //int i_data; // 这样写就写死了,只能放int数据了, void* data; // void* 是无类型指针,可以指向任何类型的数据。 struct LINKNODE* next; }LinkNode; // 链表结构体 typedef struct LINKLIST{ LinkNode* head; // 头结点 int size; // 链表节点数 // 要像动态数组一样需要内存容量吗?不需要, 没有容量概念。 }LinkList; // 打印函数指针 typedef void(*PRINTLINKNODE)(void*); // ----------------------------------------------------------------------------- // 下面函数,就是针对上面链表结构体和结点的操作。 // ----------------------------------------------------------------------------- // 初始化链表 ,返回一个链表结构体 LinkList* Init_LinkList(); // 指定位置插入。参数:所插入的链表,位置,值 void Insert_LinkList(LinkList* list,int pos,void* data); // 删除指定位置的值。 参数:链表,位置 void RemoveByPos_LinkLIst(LinkList* list,int pos); // 获得链表的长度(结点数量) int Size_LinkList(LinkList* list); // 根据值,查找位置 int Find_LinkList(LinkList* list,void* data); // 返回第一个节点 void* Front_LinkList(LinkList* list); // 打印链表结点 void Print_LinkList(LinkList* list,PRINTLINKNODE print); // 释放内存 void FreeSpace_LinkList(LinkList* list); // ----------------------------------- main() -------------------- // 打印函数 void MyPrint(void* data){ st* p = (st*)data; printf("学号:%d\t姓名:%s\t班级:%s\t语文%d\t数学%d\t英语%d\t总分%d\n", p->id,p->name,p->classs,p->ch,p->ma,p->en,p->ch+p->ma+p->en); } int main(){ printf("好好学习,天天向上~!(单向链表20220603)\n\n"); // 创建链表 LinkList* stList = Init_LinkList(); // 创建数据 st st1 = {2001,"宗宗","364班",100,100,100}; st st2 = {2002,"艳艳","364班",99,88,59}; st st3 = {2003,"发发","364班",88,77,66}; st st4 = {2004,"小小","364班",58,57,55}; st st5 = {2005,"小五","364班",58,57,55}; // 插入数据 Insert_LinkList(stList,0,&st1); Insert_LinkList(stList,0,&st2); Insert_LinkList(stList,0,&st3); Insert_LinkList(stList,0,&st4); Insert_LinkList(stList,0,&st5); // 打印 Print_LinkList(stList,MyPrint); printf("\n删除第3个节点\n"); RemoveByPos_LinkLIst(stList,3); // 打印 Print_LinkList(stList,MyPrint); printf("\n返回第一个节点\n"); // 返回的是void* 类型,要转换成st*类型 st* ret = (st*)Front_LinkList(stList); printf("学号:%d\t姓名:%s\t班级:%s\t语文%d\t数学%d\t英语%d\t总分%d\n", ret->id,ret->name,ret->classs,ret->ch,ret->ma,ret->en,ret->ch+ret->ma+ret->en); // 销毁释放 FreeSpace_LinkList(stList); return 0; } // ----------------------------------------------------------------------------- // 下面函数,就是针对上面链表结构体和结点的操作。 // ----------------------------------------------------------------------------- // 初始化链表 ,返回一个链表结构体 LinkList* Init_LinkList(){ LinkList* list = (LinkList*)malloc(sizeof(LinkList)); list->size = 0; // 添加头节点,头节点不保存数据 list->head = (LinkNode*)malloc(sizeof(LinkNode)); list->head->next = NULL; // 头结点初始化一下 return list; } // 指定位置插入。参数:所插入的链表,位置,值(是数据指针) void Insert_LinkList(LinkList* list,int pos,void* data){ // 判断检查参数 if(list==NULL){ return; } if(data==NULL){ return; } if(pos<0 || pos > list->size){ // 友好判断,如果位置pos越界,由插入到尾部 pos = list->size; } // 创建新的节点 LinkNode* newNode = (LinkNode*)malloc(sizeof(LinkNode)); newNode->data = data; // 新节点赋值 // 找结点 LinkNode* pCurrent = list->head; // 辅助指针,用于找当前节点(插入位置的前一个节点) int i; for(i=0;i<pos;i++){ // 通过循环找到插入位置的前一个节点 pCurrent = pCurrent->next; } // 插入 newNode->next = pCurrent->next; pCurrent->next = newNode; list->size++; // 更新节点数量的记录。 } // 删除指定位置的值。 参数:链表,位置 void RemoveByPos_LinkLIst(LinkList* list,int pos){ // 判断检查参数 if(list==NULL){ return; } if(pos<0 || pos >= list->size){ //pos = list->size; // 这里就不能友好判断了, return; // 指定位置不存在,直接返回。 } // 删除 // 找结点 LinkNode* pCurrent = list->head; // 辅助指针,用于找当前节点(删除节点的前一个节点) int i; for(i=0;i<pos;i++){ // 通过循环找到要删除结点的前一个节点 pCurrent = pCurrent->next; } // 删除(先缓存要删除的节点) //pCurrent->next = pCurrent->next->next; //free(pCurrent->next); LinkNode* pDel = pCurrent->next; pCurrent->next = pDel->next; free(pDel); list->size--; // 更新链表节点数量 } // 获得链表的长度(结点数量) int Size_LinkList(LinkList* list){ return -1; } // 根据地址,查找位置,void* data 是地址(指针),不是值。 int Find_LinkList(LinkList* list,void* data){ // 判断检查参数 if(list==NULL){ return -1; } if(data==NULL){ return -1; } // 遍列查找节点,从头节点的下一个节点开始找 LinkNode* pCurrent = list->head->next; int i = 0; while(pCurrent){ if(pCurrent->data==data){ break; } pCurrent = pCurrent->next; i++; } return i; } // 返回第一个节点 void* Front_LinkList(LinkList* list){ return list->head->next->data; } // 打印链表结点 void Print_LinkList(LinkList* list,PRINTLINKNODE print){ if(list==NULL){ return; } // 辅助指针变量 LinkNode* pCurrent = list->head->next; while(pCurrent){ print(pCurrent->data); // 调用用户函数,传入数据参数 pCurrent = pCurrent->next; } } // 释放内存 void FreeSpace_LinkList(LinkList* list){ if(list==NULL){ return; } // 辅助指针变量 LinkNode* pCurrent = list->head; while(pCurrent){ // 循环释放节点内存。 LinkNode* pNext = pCurrent->next; // 用指针先记录下一个节点,如果不记录的话,释放内存后就没有了, free(pCurrent); pCurrent = pNext; } free(list); // 节点内存释放完毕后,再释放链表内存 }
本文来自博客园,作者:油腻老张,转载请注明原文链接:https://www.cnblogs.com/stou/p/16343729.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具