Data Structure--单链表大部分基本接口的实现(详细讲解)

爱被打了一巴掌 2022-10-29 09:10 244阅读 0赞

单链表

单链表,不是挨个顺序存储的数据,是互相相连的数据,按照逻辑顺序存放地数据
在这里插入图片描述
这里重点要明白的是其中的逻辑规律,会有点绕口.

单链表

  1. typedef int LDataType; //别名声明
  2. typedef struct listNode{ //结构体用来存放数据和下一个地址
  3. LDataType _data;
  4. struct listNode* _next; //下一个存放地址
  5. }listNode;
  6. typedef struct list{ //存储头结点的位置,也就是图中的第一个方框
  7. //存放第一个节点的位置
  8. listNode* _head;
  9. }list;

他就是按照这种连线形式进行存放的,注意理解

接口声明

从接口这里我开始详细的讲:

  1. //1.接口初始化
  2. void listInit(list* lst);
  3. //2.创建空间
  4. listNode* creatNode(LDataType val);
  5. //3.尾插
  6. void listPushBack(list* lst,LDataType val);
  7. //4.尾删
  8. void listPopBack(list* lst);
  9. //5.头插
  10. void listPushFront(list* lst,LDataType val);
  11. //6.头删
  12. void listPopFront(list* lst);
  13. //7.中间插入
  14. void listInsertAfter(listNode* cur, LDataType val);
  15. //8.删除节点
  16. void listEraseAfter(listNode* cur);
  17. //9.查找
  18. listNode* listFind(list* lst, LDataType val);
  19. //10.销毁
  20. void listDestory(list* lst);

接口实现

1.接口初始化

对于这里的接口初始化没有太多要说的,就是将头结点创建出来,等于空就可以了

  1. void listInit(list* lst){
  2. if (lst == NULL) //如果为空指针,直接返回
  3. return;
  4. //初始化为空的链表
  5. lst->_head = NULL;
  6. }
2.创建空间

因为单链表这个东西,我们需要一个一个的进行创建比较麻烦,所以我们直接把他封装成一个接口,每次需要的时候直接调用就可以了,比较方便,也容易操作.

  1. listNode* creatNode(LDataType val){
  2. listNode* node = (listNode*)malloc(sizeof(listNode)); //动态开辟一块空间
  3. node->_data = val; //将开辟的值进行赋予
  4. node->_next = NULL; //next为空,表示为最后一个元素
  5. return node; //返回
  6. }
3.尾插

在这里插入图片描述

  1. void listPushBack(list* lst,LDataType val){
  2. if (lst == NULL) //为空判断
  3. return;
  4. if (lst->_head == NULL){ //如果为空
  5. lst->_head=creatNode(val); //直接将这个元素创建在头结点后面
  6. }
  7. else{ //不为空
  8. listNode* tail = lst->_head; //创建一个tail指向头结点
  9. while (tail->_next != NULL){ //从头进行遍历,直到找到为NULL的最后一个元素
  10. tail = tail->_next; //遍历
  11. }
  12. tail->_next = creatNode(val); //寻找到最后一个后,将其进行元素插入,这里是调用了2的操作
  13. }
  14. }
4.尾删

在这里插入图片描述

  1. void listPopBack(list* lst){
  2. if (lst== NULL||lst->_head==NULL) //判断是否为空
  3. return;
  4. struct listNode* tail = lst->_head; //让tail指向头结点
  5. struct listNode* prev = NULL;
  6. while (tail->_next != NULL){ //进行遍历
  7. prev = tail; //tail值赋予,也就是找到了倒数第二的位置
  8. tail = tail->_next; //循环
  9. }
  10. free(tail); //释放空间
  11. if (prev == NULL) //如果为空,就说明只存在一个数据,将数据删除,就只剩下头结点
  12. lst->_head = NULL; //只能让存在的头结点为空
  13. else //如果不为空,则存在元素倒数第二的next指向NULL即可
  14. prev->_next = NULL;
  15. }
5.头插

在这里插入图片描述

  1. void listPushFront(list* lst,LDataType val){
  2. if (lst == NULL) //判空
  3. return;
  4. if (lst->_head == NULL) //如果只有一个头节点
  5. lst->_head = creatNode(val); //则直接创建一个新的即可
  6. else{ //如果有其他元素
  7. listNode* node = creatNode(val); //先创建
  8. listNode* next = lst->_head; //让next指向头结点,也就是原来第一个元素的头
  9. lst->_head = node; //头结点指向新创建的元素
  10. node->_next = next; //新创建元素的next指向原来第一个元素的头
  11. }
  12. }

要点:!!!

这里主要理解的是你要理解,最开始头结点和指向了原来的第一个元素,这两个地址可以理解成是一样的,所以最后一句node->_next = next;这里的后面的next就是红色三角形这里的地址!!!

6.头删

在这里插入图片描述

  1. void listPopFront(list* lst){
  2. if (lst == NULL||lst->_head==NULL) //判空
  3. return;
  4. struct listNode* next = lst->_head->_next; //创建一个next指向原来头结点指向的第一个元素
  5. //的next,也就是第二个元素的首地址,连线的地址可以类似于一样
  6. free(lst->_head); //释放头结点
  7. lst->_head = next; //头结点指向我们上面整理好的第二个元素的头
  8. }

多理解我的话,多画图思考

7.中间插入

在这里插入图片描述

  1. void listInsertAfter(listNode* cur, LDataType val){
  2. listNode* node = creatNode(val); //创建新元素
  3. listNode* next = cur->_next; //创建next指向原来位置的next也就是下一个元素的头(连线地址相等)
  4. cur->_next = node; //上一个元素的next指向新创建的元素
  5. node->_next = next; //创建元素的next指向下一个元素
  6. }
8.删除节点(删除要删除的下一个元素)

在这里插入图片描述

  1. void listEraseAfter(listNode* cur){
  2. listNode* next = cur->_next; //创建next指向要cur的next
  3. if (next == NULL) //判空
  4. return;
  5. struct listNode* nextnext = next->_next; //创建cur的下一个元素的next,也就是最后一个元素的头
  6. free(next); //释放空间
  7. cur->_next = nextnext; //连接
  8. }
9.查找
  1. listNode* listFind(list* lst, LDataType val){
  2. if (lst == NULL||lst->_head==NULL) //判空
  3. return NULL;
  4. //从头开始遍历
  5. struct listNode* cur = lst->_head; //cur指向头结点
  6. while (cur){ //循环
  7. if (cur->_data == val) //当寻找到相等的,直接返回其位置
  8. return cur;
  9. cur = cur->_next; //循环进行
  10. }
  11. return NULL; //找不到返回空
  12. }

简单,理解就可以

10.销毁

因为释放单链表需要地址,先将下一个地址找到,再将这个进行释放,循环进行.

  1. void listDestory(list* lst){
  2. if (lst->_head == NULL||lst==NULL) //判空
  3. return;
  4. else{ //不为空向下执行
  5. listNode* cur = lst->_head; //cur指向头结点
  6. while (cur){ //循环
  7. listNode* next = cur->_next; //指向下一个头结点
  8. free(cur); //释放这个空间
  9. cur = next; //向后移一个,继续释放
  10. }
  11. }
  12. lst->_head = NULL; //最后将头结点为空操作
  13. }

对于这一部分的代码主要是理解,看起来很难是你没有理解到位,我总结出来的(连线两端的地址可以看成是相等的)剩下的就好考虑多了,多敲代码,细心一点,一起加油!!!

发表评论

表情:
评论列表 (有 0 条评论,244人围观)

还没有评论,来说两句吧...

相关阅读