大家好,又是我(小锋),今天给大家带了一个比较有挑战的章节(链表),但是不用担心,小锋会陪大家一起度过。
顺序表的思考与问题
链表
单链表打印
//链表输出void LBexport(LBbiao* att) {assert(att);LBbiao* ps = att;while (ps!= NULL) {printf("%d->", ps->SZ);ps = ps->next;}printf("NULL\n");}
这里大家可以画图一步一步的理一下理解会更加深刻主要注意循环的判断条件。
我们下面来实现一个插入函数
单链表头插数据
我们想一想在链表的头部插入数据我们只需要开辟一个链表空间mon然后另它的next指向当前链表的表头的地址,并将mon的地址交给表头的指针是不是就可以插入数据并且将链表连接起来了?
//链表头插数据void LBcutin(LBbiao** att,CMMlet n) {assert(att);LBbiao* pt = LBopen();if (*att == NULL) {*att = pt;}else {pt->next = *att;*att = pt;}pt->SZ = n;}
//开辟链表LBbiao* LBopen() {LBbiao* mon = (LBbiao*)malloc(sizeof(CMMlet) + sizeof(LBbiao*));if (mon == NULL) {printf("开辟失败:%s",strerror(errno));return NULL;}mon->next = NULL;mon->SZ = 0;return mon;}
单链表头删数据
还是我们用图来演示
//链表头删数据void LBdelete(LBbiao**att) {assert(*att != NULL);assert(att != NULL);//断言LBbiao* ps = *att;*att = ps->next;ps->next = NULL;free(ps);}
我们验证试试
单链表尾删数据
我们还是画图演示原理
我们可以看见尾删数据直接将倒数第二个节点的next为空就行了,当然我们还要断言一些情况
并且我们还要分情况当链表只有一个节点时该怎么删。
//链表尾删数据void LBweishan(LBbiao*att) {assert(att != NULL);//断言LBbiao* ps = att;while (ps->next->next != NULL) {ps = ps->next;}free(ps->next);ps->next = NULL;}
单链表尾插数据
老规矩画图理解
我们通过图可以看出尾插数据要开辟一个新的节点然后让原链表的最后一个节点的next指向新开辟出来的节点并将新开辟的节点的next为空。同样我们要分情况讨论
//链表尾插数据void LBweicha(LBbiao** att,CMMlet n) {LBbiao* ps = *att;LBbiao* pt = LBopen();if (ps == NULL) {*att = pt;}else {while (ps->next != NULL) {ps = ps->next;}ps->next = pt;}pt->SZ = n;}
单链表查找
我们可以直接遍历链表如果遇到我们就返回该数据的节点地址,如果没找到我们返回NULL。
//链表查找LBbiao* LBchazhao(LBbiao* att, CMMlet n) {assert(att);LBbiao* ps = att;while (ps != NULL) {if (ps->SZ == n) {return ps;break;}ps = ps->next;}return NULL;}
我们可以测试一下
单链表在pos位置之后插入x
与头插类似我们主要注意的是要不要分情况讨论,以及断言的内容,具体插入的过程我们大家可以自己画图试试
接下来我们来实现一下这个函数
//链表在pos位置后插入xvoid LBporcr(LBbiao* pos, CMMlet x) {assert(pos);LBbiao* ps = pos;LBbiao* pt = LBopen();if (pos->next == NULL) {//相当于尾插数据LBweicha(&pos, x);}else {//一般情况pt->next=ps->next;ps->next = pt;pt->SZ = x;}}
验证试试
单链表删除pos位置之后的值
我们还是用图说话
分析后我们发现我们只需要将pos位置的next指向pos->next->next就ok了,最后还要注意一下特殊情况以及断言
//链表在pos位置后删除xvoid LBpossc(LBbiao* pos) {assert(pos&&pos->next!=NULL);if (pos->next->next == NULL) {//相当于尾删free(pos->next);pos->next = NULL;}else {LBbiao* ps = pos->next;pos->next = pos->next->next;ps->next = NULL;free(ps->next);}}
我们可以测试一下
链表空间的释放
同学们,因为链表是环环相扣的我们如果将一个空间节点的空间释放那么我们就无法找到下一块空间了所有我们这里应该设置两个指针一个指向要释放空间的节点一个指向下一个节点,
//链表释放空间void LBshifang(LBbiao** att) {assert(att);assert(*att);LBbiao* ps = *att;LBbiao* pt = ps->next;while (ps) {ps->next = NULL;free(ps);ps = pt;if (pt!=NULL) {pt = pt->next;}}*att = NULL;}
我们测试一下
我们看是不是最后链表空间都被释放了?
同学们至此我们的单链表就讲解完了是不是畅快淋漓呢?
这是我们本节的所有代码大家可以自己试试
# define _CRT_SECURE_NO_WARNINGS 1
# include<stdio.h>
# include<assert.h>
# include<string.h>
# include<errno.h>
# include<stdlib.h>//类型重命名
//方便后期修改
typedef struct LBbiao LBbiao;
typedef int CMMlet;
//链表创建struct LBbiao{CMMlet SZ;//链表存储的数据struct LBbiao* next;//指向下一个节点};//开辟链表LBbiao* LBopen() {LBbiao* mon = (LBbiao*)malloc(sizeof(CMMlet) + sizeof(LBbiao*));if (mon == NULL) {printf("开辟失败:%s",strerror(errno));return NULL;}mon->next = NULL;mon->SZ = 0;return mon;}//链表输出void LBexport(LBbiao* att) {assert(att);LBbiao* ps = att;while (ps!= NULL) {printf("%d->", ps->SZ);ps = ps->next;}printf("NULL\n");}//链表头插数据void LBcutin(LBbiao** att,CMMlet n) {assert(att);LBbiao* pt = LBopen();if (*att == NULL) {*att = pt;}else {pt->next = *att;*att = pt;}pt->SZ = n;}//链表头删数据void LBdelete(LBbiao**att) {assert(*att != NULL);assert(att != NULL);//断言LBbiao* ps = *att;*att = ps->next;ps->next = NULL;free(ps);}//链表尾删数据void LBweishan(LBbiao**att) {assert(att != NULL);//断言assert(*att != NULL);LBbiao* ps = *att;if (ps->next == NULL) {*att = NULL;free(ps);}else {while (ps->next->next != NULL) {ps = ps->next;}free(ps->next);ps->next = NULL;}}//链表尾插数据void LBweicha(LBbiao** att,CMMlet n) {LBbiao* ps = *att;LBbiao* pt = LBopen();if (ps == NULL) {*att = pt;}else {while (ps->next != NULL) {ps = ps->next;}ps->next = pt;}pt->SZ = n;}//链表查找LBbiao* LBchazhao(LBbiao* att, CMMlet n) {assert(att);LBbiao* ps = att;while (ps != NULL) {if (ps->SZ == n) {return ps;break;}ps = ps->next;}return NULL;}//链表在pos位置后插入xvoid LBporcr(LBbiao* pos, CMMlet x) {assert(pos);LBbiao* ps = pos;LBbiao* pt = LBopen();if (pos->next == NULL) {//相当于尾插数据LBweicha(&pos, x);}else {//一般情况pt->next=ps->next;ps->next = pt;pt->SZ = x;}}//链表在pos位置后删除xvoid LBpossc(LBbiao* pos) {assert(pos&&pos->next!=NULL);if (pos->next->next == NULL) {//相当于尾删free(pos->next);pos->next = NULL;}else {LBbiao* ps = pos->next;pos->next = pos->next->next;ps->next = NULL;free(ps->next);}}//链表释放空间void LBshifang(LBbiao** att) {assert(att);assert(*att);LBbiao* ps = *att;LBbiao* pt = ps->next;while (ps) {ps->next = NULL;free(ps);ps = pt;if (pt!=NULL) {pt = pt->next;}}*att = NULL;}//测试链表1void ceshi1() {LBbiao* arr = NULL;LBweicha(&arr, 1);LBweicha(&arr, 2);LBweicha(&arr, 3);LBweicha(&arr, 4);LBshifang(&arr);}int main() {ceshi1();return 0;}
以上就是全部内容了,如果有错误或者不足的地方欢迎大家给予建议。