C语言中数据结构——单链表
🐶博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++
🔥座右铭:“不要等到什么都没有了,才下定决心去做”
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀
目录
🐰单链表
🏡单链表的定义
🏡单链表的打印
🏡单链表的创建节点
🏡单链表的头插
🏡单链表的尾插
🏡单链表的尾删
🏡单链表的头删
🏡单链表的查找
🏡单链表的改动
🏡单链表的元素个数
🏡单链表的任意位置插入元素
单链表的任意位置删除元素
🏡单链表的销毁
🏡单链表中的源码
🌸main文件
🌸头文件test.h
🌸test.c文件
🐰单链表
🏡单链表的定义
typedef int SLTDataType; typedef struct SListNode {SLTDataType data;struct SListNode* next;//next存放的下一个节点的地址 }SLT;
🏡单链表的打印
依次打印链表中的数据
void SLTprintf(SLT* phead) {SLT* cur=phead;while(cur!=NULL){printf("%d ",cur->data);cur=cur->next;}printf("\\n"); }
🏡单链表的创建节点
动态开辟一个空间,然后返回这个空间的地址,即动态开辟的节点
SLT* Buylistnode(int x) {SLT* newnode=(SLT*)malloc(sizeof(SLT));if(newnode==NULL){perror("malloc fail");return 0;}newnode->data=x;newnode->next=NULL;return newnode; }
🏡单链表的头插
复用了动态创建节点
void SLTPushFront(SLT** pphead,SLTDataType x) {SLT* newnode= Buylistnode(x);newnode->next=*pphead;*pphead=newnode; }
🏡单链表的尾插
注意一个节点和多个节点时
void SLTPushBack(SLT** pphead,SLTDataType x) {SLT* newnode=Buylistnode(x);if(*pphead==NULL)//当为空链表时{*pphead=newnode;}else{SLT* tail=*pphead;while(tail->next){tail=tail->next;}tail->next=newnode;} }
🏡单链表的尾删
这两种方法的本质都是找到倒数第二个节点
第一种尾删的方法
注意一个节点和多个节点时
void SLTPopBack(SLT** pphead) {assert(*pphead);SLT* prev=NULL;SLT* tail=*pphead;if(tail->next==NULL){free(tail);*pphead=NULL;}else{while(tail->next){prev=tail;tail=tail->next;}free(tail);prev->next=NULL;} }
第二种尾删的方法
注意一个节点和多个节点时
void SLTPopBack(SLT** pphead) {assert(*pphead);SLT* tail=*pphead;if(tail->next==NULL)//只有一个节点{free(tail);*pphead=NULL;}else//有多个节点{while(tail->next->next)//这也是找到倒数第二个节点{tail=tail->next;}free(tail->next);tail->next=NULL;} }
🏡单链表的头删
注意一个节点和多个节点时
void SLTPopFront(SLT** pphead) {assert(*pphead);SLT* tail=*pphead;if(tail->next==NULL)//一个节点{free(tail);*pphead=NULL;}else//多个节点{tail=tail->next;free(*pphead);*pphead=tail;} }
🏡单链表的查找
(找到了,就返回所在的位置,没找到返回-1)
int SLTFind(SLT** pphead,SLTDataType x) {assert(*pphead);SLT* try_b=*pphead;int Count=1;while(try_b->next){if(try_b->data==x){return Count;}Count++;try_b=try_b->next;}return -1; }
🏡单链表的改动
需要给出改动的位置以及要改动的值
void SLTChange(SLT** pphead,int pos,SLTDataType x) {assert(*pphead);int Count=Totalsize(pphead);assert(pos<=Count);SLT* tail=*pphead;while(pos--){tail=tail->next;}tail->data=x; }
🏡单链表的元素个数
计算链表的元素个数,然后返回个数
int Totalsize(SLT** pphead) {SLT* tail=*pphead;int Count=0;while(tail){tail=tail->next;Count++;}return Count; }
🏡单链表的任意位置插入元素
需要给出插入的位置以及要插入的值(说明一下,这里是插入元素的位置的后面),插入的位置一定要合法
void SLTInsertAfter(SLT** pphead,int pos, SLTDataType x) {assert(pos<=Count);if((*pphead)==NULL){SLTPushFront(pphead, x);}else{SLT* prev=NULL;SLT* tail=*pphead;while(pos--){prev=tail;tail=tail->next;}SLT* newnode=Buylistnode(x);prev->next=newnode;newnode->next=tail;} }
单链表的任意位置删除元素
删除的位置一定要合法
void SLTEraseAfter(SLT** pphead,int pos) {assert(*pphead);assert(pos<=Count-1);if((*pphead)->next==NULL){SLTPopFront(pphead);}else{SLT* prev=NULL;SLT* taillater=NULL;SLT* tail=*pphead;while(pos--){prev=tail;tail=tail->next;}taillater=tail->next;free(tail);tail=NULL;prev->next=taillater;} }
🏡单链表的销毁
void SLTDestroy(SLT** pphead) {free(*pphead);*pphead=NULL; }
🏡单链表中的源码
为方便调试单链表,这里没有使用了菜单
🌸main文件
#include"test.h" void test1(void) {SLT* plist=NULL;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTprintf(plist);printf("\\n");SLTPushBack(&plist, 4);SLTPushBack(&plist, 3);SLTPushBack(&plist, 2);SLTPushBack(&plist, 1);SLTprintf(plist); } void test2(void) {SLT* plist=NULL;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPushBack(&plist, 4);SLTPushBack(&plist, 3);SLTPushBack(&plist, 2);SLTPushBack(&plist, 1);SLTprintf(plist); // SLTPopBack(&plist); // SLTPopBack(&plist); // SLTPopBack(&plist); // SLTPopBack(&plist); // SLTPopBack(&plist); // SLTPopBack(&plist); // SLTPopBack(&plist); // SLTprintf(plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTprintf(plist); } void test3(void) {SLT* plist=NULL;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPushBack(&plist, 4);SLTPushBack(&plist, 3);SLTPushBack(&plist, 2);SLTPushBack(&plist, 1);SLTprintf(plist);int ret=SLTFind(&plist,4);printf("position is('-1'is not find):%d\\n",ret); } void test4(void) {SLT* plist=NULL;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPushBack(&plist, 4);SLTPushBack(&plist, 3);SLTPushBack(&plist, 2);SLTPushBack(&plist, 1);SLTprintf(plist);SLTChange(&plist, 23, 100);SLTprintf(plist); } void test5(void) {SLT* plist=NULL;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPushBack(&plist, 4);SLTPushBack(&plist, 3);SLTPushBack(&plist, 2);SLTPushBack(&plist, 1);SLTprintf(plist);int ret=Totalsize(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTprintf(plist);ret=Totalsize(&plist);printf("total is :%d\\n",ret); } void test6(void) {SLT* plist=NULL;// SLTPushFront(&plist, 1); // SLTPushFront(&plist, 2); // SLTPushFront(&plist, 3); // SLTPushFront(&plist, 4); // SLTPushBack(&plist, 4); // SLTPushBack(&plist, 3); // SLTPushBack(&plist, 2); // SLTPushBack(&plist, 1);SLTprintf(plist);SLTInsertAfter(&plist, 1, 100);SLTprintf(plist); } void test7(void) {SLT* plist=NULL;SLTPushFront(&plist, 1); // SLTPushFront(&plist, 2); // SLTPushFront(&plist, 3); // SLTPushFront(&plist, 4); // SLTPushBack(&plist, 4); // SLTPushBack(&plist, 3); // SLTPushBack(&plist, 2); // SLTPushBack(&plist, 1);SLTprintf(plist);SLTEraseAfter(&plist, 1);SLTprintf(plist); } void test8(void) {SLT* plist=NULL;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPushBack(&plist, 4);SLTPushBack(&plist, 3);SLTPushBack(&plist, 2);SLTPushBack(&plist, 1);SLTprintf(plist);SLTDestroy(&plist);SLTprintf(plist); } int main() {//test1();//完成头插尾插//test2();//完成尾删//test3();//查找//test4();//改动//test5();//判断链表有多少个元素// test6();//任意插入元素//test7();//任意删除元素test8();//销毁链表 }
🌸头文件test.h
#ifndef test_h #define test_h #include <stdio.h> #endif /* test_h */ #include<stdlib.h> #include<assert.h>typedef int SLTDataType; typedef struct SListNode {SLTDataType data;struct SListNode* next;//next存放的下一个节点的地址 }SLT;//单链表的打印 void SLTprintf(SLT* phead); //单链表的头插 void SLTPushFront(SLT** pphead,SLTDataType x); //单链表的尾插 void SLTPushBack(SLT** pphead,SLTDataType x); //单链表的尾删 void SLTPopBack(SLT** pphead); //单链表的头删 void SLTPopFront(SLT** pphead); //单链表的查找(找到了,就返回所在的位置,没找到返回-1) int SLTFind(SLT** pphead,SLTDataType x); //单链表的改动(改变给出位置的值) void SLTChange(SLT** pphead,int pos,SLTDataType x); //单链表的元素个数 int Totalsize(SLT** pphead); //单链表的任意位置插入元素 void SLTInsertAfter(SLT** pphead,int pos, SLTDataType x); //单链表的任意位置删除元素 void SLTEraseAfter(SLT** pphead,int pos); //单链表的销毁 void SLTDestroy(SLT** pphead);
🌸test.c文件
#include "test.h"void SLTprintf(SLT* phead) {SLT* cur=phead;while(cur!=NULL){printf("%d ",cur->data);cur=cur->next;}printf("\\n"); } SLT* Buylistnode(int x) {SLT* newnode=(SLT*)malloc(sizeof(SLT));if(newnode==NULL){perror("malloc fail");return 0;}newnode->data=x;newnode->next=NULL;return newnode; } void SLTPushFront(SLT** pphead,SLTDataType x) {SLT* newnode= Buylistnode(x);newnode->next=*pphead;*pphead=newnode; } void SLTPushBack(SLT** pphead,SLTDataType x) {SLT* newnode=Buylistnode(x);if(*pphead==NULL){*pphead=newnode;}else{SLT* tail=*pphead;while(tail->next){tail=tail->next;}tail->next=newnode;} } //这两种方法的本质都是找到倒数第二个节点 //第一种尾删的方法 void SLTPopBack(SLT** pphead) {assert(*pphead);SLT* prev=NULL;SLT* tail=*pphead;if(tail->next==NULL){free(tail);*pphead=NULL;}else{while(tail->next){prev=tail;tail=tail->next;}free(tail);prev->next=NULL;} } //第二种尾删的方法 //void SLTPopBack(SLT** pphead) //{ // assert(*pphead); // SLT* tail=*pphead; // if(tail->next==NULL)//只有一个节点 // { // free(tail); // *pphead=NULL; // } // else//有多个节点 // { // while(tail->next->next)//这也是找到倒数第二个节点 // { // tail=tail->next; // } // free(tail->next); // tail->next=NULL; // } //}void SLTPopFront(SLT** pphead) {assert(*pphead);SLT* tail=*pphead;if(tail->next==NULL)//一个节点{free(tail);*pphead=NULL;}else//多个节点{tail=tail->next;free(*pphead);*pphead=tail;} }int SLTFind(SLT** pphead,SLTDataType x) {assert(*pphead);SLT* try_b=*pphead;int Count=1;while(try_b->next){if(try_b->data==x){return Count;}Count++;try_b=try_b->next;}return -1; } int Totalsize(SLT** pphead) {SLT* tail=*pphead;int Count=0;while(tail){tail=tail->next;Count++;}return Count; } void SLTChange(SLT** pphead,int pos,SLTDataType x) {assert(*pphead);int Count=Totalsize(pphead);assert(pos<=Count);SLT* tail=*pphead;while(pos--){tail=tail->next;}tail->data=x; }void SLTInsertAfter(SLT** pphead,int pos, SLTDataType x) {if((*pphead)==NULL){SLTPushFront(pphead, x);}else{SLT* prev=NULL;SLT* tail=*pphead;while(pos--){prev=tail;tail=tail->next;}SLT* newnode=Buylistnode(x);prev->next=newnode;newnode->next=tail;} }void SLTEraseAfter(SLT** pphead,int pos) {assert(*pphead);if((*pphead)->next==NULL){SLTPopFront(pphead);}else{SLT* prev=NULL;SLT* taillater=NULL;SLT* tail=*pphead;while(pos--){prev=tail;tail=tail->next;}taillater=tail->next;free(tail);tail=NULL;prev->next=taillater;} }void SLTDestroy(SLT** pphead) {free(*pphead);*pphead=NULL; }
🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸