本人数据结构编写规则

① 在函数中判断结构体指针是否为空时采用assert函数,而不是用if语句判断。
② 函数的命名规则遵循:操作+结构类型名 的规则。例如 InitSqList 与DestroySqList。
③ 严蔚敏老师一书中很多运用了C++的语法,而我们是用C语言来实现,因此编写规则与书上会有很多不同,但是思路是一样的。例如用malloc代替new,free代替delete,引用与指针的区别等。
④ 本文没有采用bool变量以及自定义的Status作为返回值来判断是否操作成功。

正文

线性表的特点是可以随意存取表中任意元素,但是在插入和删除时需要移动大量的元素效率低下,而且因为数组的长度相对固定的静态特性,当表中数据元素个数多且变化大时操作过程相对复杂,必然导致空间的浪费。链表是线性表的链式表示,用于弥补线性表的缺陷。但是链表本身也有缺陷,我们后面再说。

线性链式表,简称链表,特点是用一组任意的存储单元存储线性表的数据元素。因此为了表示当前元素和逻辑上的下一个元素之间的关系,除了存储本身的数据之外,还要存储一个指示其直接后继的信息。由这两个信息组成的单元叫做结点

通俗地讲,链表需要定义一个数据域和一个指针域,指针域用于存放逻辑上下一个元素的地址,即指向下一个元素。

函数实现

结构体定义

typedef int LLDataType;
typedef struct LinkListNode
{LLDataType data;struct LinkListNode* next;//存储下一个结点的地址
}LLNode;

其中定义LLDataType便于后续修改元素类型。data是数据域,next是指针域。此处我们只定义了一个next指针,而没有pre,指向上一个结点的指针,因此是单向链表。链表最后的结点指向NULL。

函数声明

//单链表不需要初始化
void PrintLinkList(LLNode** phead);     遍历打印链表
LLNode* CreateLinkNode(LLDataType i);   创建新的结点void BackInsertLinkList(LLNode** pphead, LLDataType i);尾插
void BackDeleteLinkList(LLNode** pphead);尾删void FrontInsertLinkList(LLNode** pphead, LLDataType i);头插
void FrontDeleteLinkList(LLNode** pphead);头删LLNode* SearchLinkList_Address(LLNode** pphead, LLDataType i);
查找元素,返回的是该元素的地址
int SearchLinkList_Position(LLNode** pphead, LLDataType i);
查找元素,返回的是该元素的位置void ModifyLinkList(LLNode** pphead, int pos, LLDataType i);
修改pos位置的元素void InsertBeforeAddressLinkList(LLNode** pphead,
LLNode* pos, LLDataType i);
在pos地址前插入void InsertAfterAddressLinkList(LLNode* pos, LLDataType i);
在pos地址后插入void DeleteAtLinkList(LLNode** pphead, LLNode* pos);
删除pos地址处的结点void DeleteAfterLinkList(LLNode* pos);
删除pos地址处之后的一个结点void DestoryLinkList(LLNode** pphead); 摧毁链表

注意:
本文是带头结点(也叫根结点)的单向链表,因此每次需要定义一个头结点指向NULL,又传参的时候某些函数需要传二级指针,因为要修改头结点(头指针)的指向以便链接之后的结点。

新建结点

LLNode* CreateLinkNode(LLDataType i)
{LLNode* newnode = (LLNode*)malloc(sizeof(LLNode));if (newnode == NULL){printf("malloc失败!\n");exit(-1);}else{newnode->data = i;newnode->next = NULL;}return newnode;
}

在需要插入的时候定义一个newnode用于接收这个函数的返回值,之后用于插入操作。

打印链表

void PrintLinkList(LLNode** pphead)
{//不用assert,头结点可以没有下一个LLNode* cur = *pphead;while (cur != NULL){printf("%d->", cur->data);cur = cur->next;//下一个结点的地址在next}printf("NULL\n");
}

一般是定义一个cur指针保存pphead,再通过cur来遍历。

尾插

void BackInsertLinkList(LLNode** pphead, LLDataType i)
{assert(pphead);LLNode* newnode = CreateLinkNode(i);if (*pphead == NULL)//如果是空链表,直接插上去{*pphead = newnode;}else{//从头开始找尾结点LLNode* tail = *pphead;1 2 3 4 5while (tail->next != NULL)//这里区别于打印{tail = tail->next;}tail->next = newnode;}
}

pphead不能为空,因为pphead是目标结构体的地址,不能对一个空指针进行操作,因此要assert判断。定义一个尾指针来找最后一个结点。区别于打印,这里尾结点的下一个是空时就要停止之后插入,打印的判断条件是指针走到空便结束,要区分开来。

尾删

void BackDeleteLinkList(LLNode** pphead)
{assert(pphead);LLNode* tail = *pphead; 尾指针if (*pphead != NULL) 先判断链表是否为空{if ((*pphead)->next == NULL) 再判断是只有一个结点还是多个{free(*pphead);*pphead = NULL;return;}while (tail->next->next != NULL){tail = tail->next;}free(tail->next);tail->next = NULL;return;}else{printf("链表为空,删除失败\n");return;}
}

头插

void FrontInsertLinkList(LLNode** pphead, LLDataType i)
{LLNode* newnode = CreateLinkNode(i);//if (*pphead == NULL)//{// *pphead = newnode;//}//else        不用这一步{newnode->next = *pphead;*pphead = newnode;}
}

这里不用判断链表是否为空,空链表照样插入。

头删

void FrontDeleteLinkList(LLNode** pphead)
{assert(pphead);LLNode* aim = *pphead;if (aim == NULL){printf("表为空,删除失败\n");return;}else {//if (aim->next == NULL) 一个结点//{//   free(aim);//    aim = NULL;//  *pphead = NULL;//}*pphead = aim->next;free(aim);}
}

这里同样不用判断是否只有一个结点,因为aim指向空的时候也能free aim。free(NULL)是合理的。

查找元素(返回地址)

LLNode* SearchLinkList_Address(LLNode** pphead, LLDataType i)
{assert(pphead);LLNode* cur = *pphead;while (cur != NULL){if (cur->data == i){return cur;}cur = cur->next;}return NULL;
}

返回的是结点的地址,如果没找到就返回NULL。

查找元素(返回位置)不常用

int SearchLinkList_Position(LLNode** pphead, LLDataType i)
{assert(pphead);int pos = 0;LLNode* cur = *pphead;while (cur != NULL){pos++; 进来先++一下if (cur->data == i){return pos;}cur = cur->next;}pos = 0;      置零return pos;
}

找到了就返回在第几个位置,没找到就返回0

修改元素(通过地址)

void ModifyLinkList_Add(LLNode* pos, LLDataType i)
{assert(pos);pos->data = i;
}

这太简单了

修改元素(指定位置)不常用

void ModifyLinkList_Pos(LLNode** pphead, int pos, LLDataType i)
{assert(pphead);LLNode* cur = *pphead;if (pos > 0){for (int i = 1; i < pos; i++){if (cur == NULL){printf("位置溢出,修改失败\n");return;}cur = cur->next;}cur->data = i;}else{printf("位置输入不合法\n");return;}
}

这也没啥好说的

在结点前插入(通过地址)

void InsertBeforeAddressLinkList(LLNode** pphead, LLNode* pos,
LLDataType i)
{assert(pphead && pos);if ((*pphead) == pos) 先判断是否头插 是的话直接复用头插函数{FrontInsertLinkList(pphead, i);}else{LLNode* pre = *pphead;while (pre->next != pos){pre = pre->next;}LLNode* newnode = CreateLinkNode(i);newnode->next = pos;pre->next = newnode;}
}

在结点后插入(通过地址)

void InsertAfterAddressLinkList(LLNode* pos, LLDataType i)
{assert(pos);LLNode* aim = (pos)->next;LLNode* newnode = CreateLinkNode(i);newnode->next = aim;pos->next = newnode;
}

删除结点(通过地址)

void DeleteAtLinkList(LLNode** pphead, LLNode* pos)
{assert(pphead && pos);if ((*pphead) == pos) 如果是第一个结点,同样复用头删函数{FrontDeleteLinkList(pphead);}else{LLNode* pre = *pphead;while (pre->next != pos){pre = pre->next;}pre->next = (pos)->next;free(pos);pos = NULL;}
}

删除pos结点之后的一个结点(通过地址)

void DeleteAfterLinkList(LLNode* pos)
{assert(pos);LLNode* aim = pos->next;if (aim != NULL){pos->next = aim->next;free(aim);aim = NULL;}
}

摧毁链表

void DestoryLinkList(LLNode** pphead)
{assert(pphead);LLNode* cur = *pphead;while (cur != NULL){LLNode* aim = cur->next;free(cur);cur = aim;}*pphead = NULL;
}

效果展示


结语
单链表是一种使用指针来存储值的数据结构,其改善了线性表的缺点,但是也存在不足。单链表只能以一个方向进行遍历。为了把一个值插入链表中,首先需要找到插入的位置,之后进行断链勾链
在使用单链表时,通过指定下标或位置插入值的情况比较少见,使用结点地址更多一些。且链表的应用场景一般是作为复杂数据结构的子结构,因此单链表是今后学习复杂数据结构的基础。

单链表是链式数据结构的开端。

(本篇完)

C语言实现数据结构——单链表相关推荐

  1. 数据结构-单链表基本操作(C语言实现)

    参考书:王道考研数据结构 (此贴为博主学习408的笔记,因博主也是学习者,个人总结如有错误欢迎指正.如有侵权请告知,马上删除致歉)​​ 单链表定义 单链表是线性表的链式存储,通过一组任意的存储单元来存 ...

  2. C语言数据结构单链表链表

    数据结构–单链表 学习了顺序表,我们发现顺序表在向里面存放数据的时候很麻烦,比如我们要使用头插法存放一个数据到顺序表的时候,我们要将整个表都向后挪一位,这个操作就让人很难受.那么有没有一种结构可以让我 ...

  3. php链表和联表的区别,PHP_浅谈PHP链表数据结构(单链表),链表:是一个有序的列表,但 - phpStudy...

    浅谈PHP链表数据结构(单链表) 链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个 ...

  4. 20175330 数据结构-单链表(选做)

    要求 参见附件,补充MyList.java的内容,提交运行结果截图(全屏) 课下推送代码到码云 ``` public class MyList {     public static void mai ...

  5. c语言链表查找的代码与题目,链表的C语言实现之单链表的查找运算_c语言

    建立了一个单链表之后,如果要进行一些如插入.删除等操作该怎么办?所以还须掌握一些单链表的基本算法,来实现这些操作.单链表的基本运算包括:查找.插入和删除.下面我们就一一介绍这三种基本运算的算法,并结合 ...

  6. 数据结构——单链表的C++实现

    数据结构--单链表的C++实现 \qquad单链表的创建.求长度.查找.插入和删除的C++实现. #include<iostream> using namespace std;//1.定义 ...

  7. php mysql 链表_浅谈PHP链表数据结构(单链表)

    链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个程序运行时,内存分成五个区(堆区, ...

  8. python 单链表是否有回路_(Python3)数据结构--单链表之判断链表是否有环

    前言 有Python基础 有数据结构单链表基础,没接触过的可以看下面链接 https://blog.csdn.net/sf9898/article/details/104946291 原理和实现 有一 ...

  9. 数据结构 —— 单链表(超详细图解 接口函数实现)

    系列文章目录 数据结构 -- 顺序表 数据结构 -- 单链表 数据结构 -- 双向链表 数据结构 -- 队列 数据结构 -- 栈 数据结构 -- 堆 数据结构 -- 二叉树 数据结构 -- 八大排序 ...

  10. 数据结构——单链表(小白入门第二天)

    一.什么是单链表? 定义:每个结点 除了存放数据元素外,还要存储指向下一个节点的指针: 优点:不要求大片连续空间,改变容量方便: 缺点:不可随机存取,要耗费一定空间存放指针 局限性:无法逆向检索 二. ...

最新文章

  1. cesium 经纬度绘制点_cesium结合geoserver利用WFS服务实现图层新增(附源码下载)
  2. 树莓派 Ubuntu mate 18.04 下开启vncserver
  3. spring boot+jpa+MySQL格式化返回数据中实体对象对应的日期格式
  4. いちがつ(2017/1)
  5. 从安全到镜像流水线,Docker 最佳实践与反模式一览
  6. 50-10-010-配置-整体配置
  7. js获取el表达式的值_Vue.js
  8. java.lang.NoClassDefFoundError: org/jdom/input/SAXBuilder
  9. 获取ACCESS_TOKEN接口
  10. 孙鑫VC学习笔记:第十二讲 (二) 用C语言函数读写文件
  11. 华为路由与交换 eSight基本概述学习笔记
  12. 【Unity3D插件】“我敢说,这是你见过最多的插件合集”Unity插件分享不断更新中。。。
  13. python之Srcapy框架浅谈
  14. Ubuntu下初装QT出现错误cannot find -lGL解决办法
  15. Python3遇到问题unicodeescape codec cant decode bytes in position 2 3 truncated UXXXXXXXX escape解决办法
  16. 用什么软件测试硬盘使用过多少次,硬盘能查看使用次数吗
  17. 【Android】底部导航栏【BottomNavigationView】+【ViewPage2】
  18. Linux中延时/暂停函数(sleep/usleep/nanosleep/select)的比较、底层实现说明
  19. JavaWeb是什么?如何学习JavaWeb的体系
  20. 类图,类与类之间的关系

热门文章

  1. 列表ListBox、ListView、GridView 排序
  2. 【net core】VSCode调试NetCore Web项目问题集锦
  3. c语言回顾之指针数组和数组指针
  4. C# HttpWebRequest 绝技 【转】
  5. (转)Extjs4 展示图片与图片的更新
  6. mysql中事务开启语法_MySQL执行事务的语法和流程
  7. Qt QScrollArea 用法 QScrollArea不显示 QScrollArea没铺满
  8. 解决dropbear在busybox中使用无法使用本地用户登录问题
  9. MyBatis官方文档——Java API部分
  10. mongodb java 不等于_mongoDB在java上面的应用