深圳网站开发平台星速浏览器
深圳网站开发平台,星速浏览器,四川住房建设厅网站首页,亚马逊雨林有多恐怖❀❀❀ 文章由不准备秃的大伟原创 ❀❀❀ ♪♪♪ 若有转载#xff0c;请联系博主哦~ ♪♪♪ ❤❤❤ 致力学好编程的宝藏博主#xff0c;代码兴国#xff01;❤❤❤ 哈咯各位铁汁们#xff0c;大家新年过得快乐吗#xff1f;反正大伟是过得很快乐#xff0c;天天就是玩玩玩… ❀❀❀ 文章由不准备秃的大伟原创 ❀❀❀ ♪♪♪ 若有转载请联系博主哦~ ♪♪♪ ❤❤❤ 致力学好编程的宝藏博主代码兴国❤❤❤ 哈咯各位铁汁们大家新年过得快乐吗反正大伟是过得很快乐天天就是玩玩玩吃吃吃 (^▽^ )。不过堕落的生活不能持续太久所以从今天开始大伟又要继续更新我们的数据结构啦啪叽啪叽o(ε*)。 OK那么今天要学的就是我们数据结构中很重要的一环单链表。 那首先我们需要知道链表是什么东西 概念链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 形象一点就是链表就是一列火车链表中的每一个节点就是火车的每一节车厢每一个车厢都是单独存在的而每两个车厢都是有前后联系的为了进入中间的某节车厢就需要从这节车厢的上一节或下一节进入。 那在链表中这些车厢是什么样子的呢 与顺序表不同的是链表⾥的每节⻋厢都是独⽴申请下来的空间我们称之为“结点/节点” 节点的组成主要有两个部分当前节点要保存的数据和保存下⼀个节点的地址指针变量。 图中指针变量plist保存的是第⼀个节点的地址我们称plist此时“指向”第⼀个节点如果我们希望plist“指向”第⼆个节点时就需要指针变量来保存下⼀个节点的位置。那该如何做呢 结合前⾯学到的结构体知识我们可以给出每个节点对应的结构体代码
struct SListNode
{int data; //节点数据 struct SListNode* next; //指针变量⽤保存下⼀个节点的地址
};当我们想要保存⼀个整型数据时实际是向操作系统申请了⼀块内存这个内存不仅要保存整型数 据也需要保存下⼀个节点的地址当下⼀个节点为空时保存的地址为空。 而当我们想要从第⼀个节点⾛到最后⼀个节点时只需要在前⼀个节点拿上下⼀个节点的地址下⼀个 节点的钥匙就可以了。 和循序表类似我们的单链表也有增删查改的功能那接下来就开码把 当然了首先我们还是开三个文件SL.h SL.c test.c 。功能的话不需要多说了吧~ SL.h
#includestdio.h
#includestring.h
#includeassert.h
#includestdlib.h
#includemalloc.h
typedef int SLDataTpye;
typedef struct SListNode
{SLDataTpye data;struct SListNode* next;
}SLNode;void SLPrint(SLNode* phead);
//打印链表
SLNode* SLBuyNode(SLDataTpye x);
//创建链表节点
void SLPushFront(SLNode** pphead, SLDataTpye x);
//头插
void SLPushBack(SLNode** pphead, SLDataTpye x);
//尾插
void SLPopFront(SLNode** pphead);
//头删
void SLPopBack(SLNode** pphead);
//尾删
SLNode* SLFind(SLNode* phead, SLDataTpye x);
//查找链表元素
void SLInsertFront(SLNode** pphead, SLNode* pos, SLDataTpye x);
//在链表某位置前插入
void SLInsertAfter(SLNode** pphead, SLNode* pos, SLDataTpye x);
//在链表某位置后插入
void SLErase(SLNode** pphead, SLNode* pos);
//删除某位置下标元素
void SLEraseAfter(SLNode* pos);
//删除某位置元素下标后面一个位置的元素
void SLDestroy(SLNode* phead);
//摧毁链表 SL.c SLPrint
void SLPrint(SLNode* phead)
{SLNode* cur phead;
//cur指向头结点然后依次往下走while (cur){printf(%d-, cur-data);cur cur-next;}printf(NULL);
} SLBuyNode
SLNode* SLBuyNode(SLDataTpye x)
{SLNode* newnode (SLNode*)malloc(sizeof(SLNode));
//每次开辟一个空间if (newnode NULL){perror(malloc);return;}
//若开辟失败newnode-data x;newnode-next NULL;return newnode;
} SLPushFront
void SLPushFront(SLNode** pphead, SLDataTpye x)
{assert(pphead);SLNode* newnode SLBuyNode(x);
//在链表头结点前插入然后将头结点设置为新插入的节点newnode-next *pphead;*pphead newnode;
} SLPushBack
void SLPushBack(SLNode** pphead, SLDataTpye x)
{assert(pphead);SLNode* newnode SLBuyNode(x);
//若链表为空则直接将新的节点设置为头结点if (*pphead NULL){*pphead newnode;}
//若链表不为空则循环找到最后一个节点再将新创建的节点接到尾节点后面else{SLNode* tail *pphead;while (tail-next){tail tail-next;}tail-next newnode;}
} SLPopFront
void SLPopFront(SLNode** pphead)
{assert(pphead);assert(*pphead);
//让cur保存当前头结点然后直接让头结点往后走一个再释放刚刚保存的cur的空间因为释放了空间且当前空间不再使用所以里面的值也不需要关心了SLNode* cur *pphead;*pphead (*pphead)-next;free(cur);
} SLPopBack
void SLPopBack(SLNode** pphead)
{assert(pphead);assert(*pphead);
//若链表只有一个元素则将链表置空if ((*pphead)-next NULL){free(*pphead);*pphead NULL;}
//若链表有多余一个元素找尾节点的前一个节点再释放掉尾节点else{SLNode* tail *pphead;while (tail-next-next){tail tail-next;}free(tail-next);tail-next NULL;}
} SLFind
SLNode* SLFind(SLNode* phead, SLDataTpye x)
{SLNode* cur phead;
//直接while循环找若找到则返回此节点若找不到则返回空while (cur){if (cur-data x){return cur;}cur cur-next;}return NULL;
}SLInsertFront
void SLInsertFront(SLNode** pphead, SLNode* pos, SLDataTpye x)
{assert(pphead);assert(pos);
//若插入的位置正好是头结点则直接头插if (pos *pphead){SLPushFront(pphead, x);}
//若不是则找到需要插入节点的前一个节点然后将值为x的节点插入中间else{SLNode* prev *pphead;while (prev-next ! pos){prev prev-next;}SLNode*newnode SLBuyNode(x);newnode-next pos;prev-next newnode;}
} SLInsertAfter
void SLInsertAfter(SLNode** pphead, SLNode* pos, SLDataTpye x)
{assert(pphead);assert(pos);SLNode* newnode SLBuyNode(x);
//注意顺序要先将newnode的next指向pos的next不然会找不到pos的next节点大家可以想一想为什么newnode-next pos-next;pos-next newnode;
} SLErase
oid SLErase(SLNode** pphead, SLNode* pos)
{assert(pphead);assert(pos);
//若要删除的位置为头结点则直接头删if (pos *pphead){SLPopFront(pphead);}
//否则则找到此节点的前一个节点然后让前一个节点的next指向当前节点的next再释放当前节点的空间else{SLNode* prev *pphead;while (prev-next ! pos){prev prev-next;}prev-next pos-next;free(pos);}
} SLEraseAfter
void SLEraseAfter(SLNode* pos)
{assert(pos);assert(pos-next);
//直接改变当前节点的next指向但是要保存当前节点的next否则不好释放空间SLNode* next pos-next;pos-next pos-next-next;free(next);
} SLDestroy
void SLDestroy(SLNode* phead)
{SLNode* cur phead;
//全部空间释放while (cur){SLNode* next cur-next;free(cur);cur next;}
} OKOK以上就是我们的整体代码的主逻辑的实现那我们再来测试一下吧 test.c
#include SL.h
void test1()
{SLNode* plist NULL;SLPushFront(plist, 5);//5-NULLSLPushFront(plist, 2);//2-5-NULLSLPushBack(plist, 7);//2-5-7-NULLSLPushBack(plist, 9);//2-5-7-9-NULLSLPopBack(plist);//2-5-7-NULLSLPopFront(plist);//5-7-NULLSLNode* pos SLFind(plist, 7);SLInsertFront(plist, pos, 40);//5-40-7-NULLSLInsertAfter(plist, pos, 40);5-40-7-40-NULLSLPrint(plist);printf(\n);SLPrint(pos);//SLErase(plist, pos);//printf(\n);//SLPrint(plist);SLEraseAfter(pos);//5-40-7-NULLprintf(\n);SLPrint(plist);
}
int main()
{test1();return 0;
} 那我们来看看我们输出的结果是不是和我们的预期一样的呢: 可以看到啊答案是完全对得上的所以此刻我们的单链表就完美实现啦大家私下可以自己试试 在最后我给大家提前预支一下其实单链表一共有八种 分别画图示意 那铁汁们来分析一下我们今天写的单链表是属于哪一种的呢(σд′)σ 对咯就是单向不带头不循环链表而这种链表我们通常把它称为单链表既然我们有八种链表各位铁汁们我们私下自己来想一想其他几种链表该怎么实现呢 大伟将在下一篇博客里给大家介绍单链表的死对头双向带头循环链表 。请敬请期待哦~ Genius only means hard-working all ones life. 天才只意味着终身不懈地努力 本篇博客也就到此为止了送大家一碗鸡汤勉励自己以及这世界上所有追逐梦想的赤子趁年华尚好努力提升自己莫欺少年穷
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/87781.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!