0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

链表的基本操作

玩转单片机 来源:玩转单片机 作者:玩转单片机 2022-12-13 10:11 次阅读

回看了一下以前写的链表操作,确实有点复杂不利于初学,这篇文章就换个写法,简单明了的介绍链表的操作;

第一步:定义节点结构体,可以把它看成一个模板:

// 定义节点
typedef struct node
{
    unsigned char data;
    struct node *next;
}node_t;

第二步:初始化节点,目的就是获取到头节点,后续的操作都是判断节点的同名结构体指针是否为空,所有头节点的head->next必须等于NULL:

// 初始化节点
node_t* node_init(unsigned char data)
{
  node_t* head=(node_t*)malloc(sizeof(node_t));
  head->data = data;
  head->next = NULL;
  return head;
}

第三步:打印节点数据,用于查看节点的最新数据:

// 打印链表
void node_printf(node_t *node)
{
  node_t *head = node;
  while(1){
    printf("data:%d
",head->data);
    if(head->next==NULL){
      return;
    }else{
      head = head->next;
    }
  };
}

第四步:尾插方式把新的节点接入链表,核心就是判断节点的指针是否为空,找到最尾巴的节点,然后把新的节点接到它的后面,然后再把新的节点指针赋值为空:

// 尾插
node_t* node_end_add(node_t *node, unsigned char data)
{
  node_t *head = node;
  node_t *end = node;
  while(1){
    if(end->next!=NULL){
      end = end->next;
    }else{
      node_t* temp_node=(node_t*)malloc(sizeof(node_t));
      temp_node->data = data;
      temp_node->next = NULL;
      end->next = temp_node;
      return head;
    }
  }
}

第五步:通过尾删的方式,把节点指针为空的节点删除,再把它上一个节点赋值为空:

// 尾删
node_t* node_end_del(node_t *node)
{
  node_t *head = node;
  node_t *end = node;
  node_t *temp = NULL;
  while(1){
    if(end->next!=NULL){
      temp = end;
      end = end->next;
    }else{
      free(end);
      temp->next = NULL;
      return head;
    }
  }
}

第六步:通过头插方式,把新的节点接入到链表,头插的方式并不需要赋值为空,因为它插入的下一节点,就是上一次插入的节点指针,所以只需要把上一个节点指针赋值给新加入的指针即可,注意头插一定要返回头节点指针,因为头插的头节点会随着插入而改变:

// 头插
node_t* node_head_add(node_t *node, unsigned char data)
{
  node_t* temp_node=(node_t*)malloc(sizeof(node_t));
  temp_node->data = data;
  temp_node->next = node;
  return temp_node;
}

第七步:通过头删的方式,把头部的节点删除,因为头部的节点是已知的,所以只要改表一下头节点,然后把头部节点释放就可以:

// 头删
node_t* node_head_del(node_t *node)
{
  node_t* head = node->next;
  free(node);
  return head;
}

总结:尾节点操作是通过判断节点指针是否为NULL,找到节点指针为NULL的指针,然后进行相关操作,而头节点直接就通过头节点进行相关操作,头插和尾插最大的不同就是数据是反的,这点要注意不要搞错;

完整代码如下:

#include "stdio.h"
#include "stdlib.h"


// 定义节点
typedef struct node
{
    unsigned char data;
    struct node *next;
}node_t;


// 初始化节点
node_t* node_init(unsigned char data)
{
  node_t* head=(node_t*)malloc(sizeof(node_t));
  head->data = data;
  head->next = NULL;
  return head;
}


// 打印链表
void node_printf(node_t *node)
{
  node_t *head = node;
  while(1){
    printf("data:%d
",head->data);
    if(head->next==NULL){
      return;
    }else{
      head = head->next;
    }
  };
}


// 尾插
node_t* node_end_add(node_t *node, unsigned char data)
{
  node_t *head = node;
  node_t *end = node;
  while(1){
    if(end->next!=NULL){
      end = end->next;
    }else{
      node_t* temp_node=(node_t*)malloc(sizeof(node_t));
      temp_node->data = data;
      temp_node->next = NULL;
      end->next = temp_node;
      return head;
    }
  }
}


// 尾删
node_t* node_end_del(node_t *node)
{
  node_t *head = node;
  node_t *end = node;
  node_t *temp = NULL;
  while(1){
    if(end->next!=NULL){
      temp = end;
      end = end->next;
    }else{
      free(end);
      temp->next = NULL;
      return head;
    }
  }
}


// 头插
node_t* node_head_add(node_t *node, unsigned char data)
{
  node_t* temp_node=(node_t*)malloc(sizeof(node_t));
  temp_node->data = data;
  temp_node->next = node;
  return temp_node;
}


// 头删
node_t* node_head_del(node_t *node)
{
  node_t* head = node->next;
  free(node);
  return head;
}


int main()
{
  node_t* user_node = node_init(1);
  // 尾
  // user_node = node_end_add(user_node, 2);
  // user_node = node_end_add(user_node, 3);
  // user_node = node_end_add(user_node, 4);
  // node_printf(user_node);
  // printf("------
");
  // user_node = node_end_del(user_node);
  // user_node = node_end_del(user_node);
  // node_printf(user_node);
  // printf("------
");
  // user_node = node_end_add(user_node, 3);
  // user_node = node_end_add(user_node, 4);
  // node_printf(user_node);
  // printf("------
");
  // 头
  user_node = node_head_add(user_node, 2);
  user_node = node_head_add(user_node, 3);
  user_node = node_head_add(user_node, 4);
  node_printf(user_node);
  printf("------
");
  user_node = node_head_del(user_node);
  user_node = node_head_del(user_node);
  node_printf(user_node);
  printf("------
");
  user_node = node_head_add(user_node, 3);
  user_node = node_head_add(user_node, 4);
  node_printf(user_node);
  printf("------
");
}

代码写得不是很严谨,主要用于入门学习,把主要思路讲清楚;觉得有收获的同学动动小手指点个赞吧,我是Noah,我们下篇推文再见!

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 代码
    +关注

    关注

    30

    文章

    4555

    浏览量

    66769
  • 结构体
    +关注

    关注

    1

    文章

    125

    浏览量

    10750
  • 链表
    +关注

    关注

    0

    文章

    80

    浏览量

    10464

原文标题:通俗|操作链表

文章出处:【微信号:玩转单片机,微信公众号:玩转单片机】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    结构数据:链表删除及静态链表操作(1)#结构数据

    数据结构与算法
    学习硬声知识
    发布于 :2022年12月17日 20:31:07

    结构数据:链表删除及静态链表操作(2)#结构数据

    数据结构与算法
    学习硬声知识
    发布于 :2022年12月17日 20:31:42

    [2.6.1]--2.6单链表的基本操作1

    数据结构
    jf_60701476
    发布于 :2023年01月23日 22:08:21

    [2.7.1]--2.7单链表的基本操作2

    数据结构
    jf_60701476
    发布于 :2023年01月23日 22:09:17

    [2.3.2]--2.3.2单链表基本操作的实现

    算法数据结构
    jf_60701476
    发布于 :2023年01月24日 20:37:11

    Linux内核的链表操作

    Linux内核的链表操作本文详细分析了 2.6.x 内核中链表结构的实现,并通过实例对每个链表操作接口进行了详尽的讲解。一、
    发表于 08-29 11:13

    Linux链表操作心得体会

    在研究linux内核自带的dmatest.c驱动程序过程中发现有部分的链接操作,非常迷惑,故在此记录下来一些查阅资料后的心得体会。
    发表于 07-26 08:15

    回调函数的相关资料推荐

    前言上文分享了一个专用的双链表的基本操作示例:双链表操作示例(附代码)这里提到了一个关键词:专用。与专用对应的词是通用。我们从字面上可以很容易理解这两个词,专用就是针对特定情况的,特
    发表于 12-15 06:45

    数据结构链表的基本操作

    嵌入式学习基础-数据结构链表的基本操作链表节点采用结构体的方式进行定义,下面是最基础的定义只有一个数据data,*pNext用于指向下一个节点(若为尾节点则指向NULL)。//链表节点
    发表于 12-22 08:05

    浅析RT-Thread中对象容器与双链表操作

    操作RT-Thread的对象容器是依赖于双链表(双向循环链表)的,其双链表的相关操作在文件rtservice.h中:其节点结构体为:str
    发表于 05-18 14:23

    小编科普一下rtthread链表操作的几个API与实用的几个宏

    rtthread 链表操作的的几个 API /* 将节点 n 插入到节点 l 的后面,如果 l 为头节点,则插入到链表头部 */rt_inline void rt_list_insert_after
    发表于 05-18 14:26

    链表的基本操作(含源代码)

    发表于 11-09 16:01 34次下载

    链表学习的超详细说明(二)

    昨天跟大家分享了单链表的一些基本用法,今天接着继续和大家分享单链表的用法,今天分享完,单链表操作就暂告一段落了,后面接着分享双链表的学习和
    的头像 发表于 12-24 17:33 618次阅读

    链表学习的总结(一)

    想必大多数人和我一样,刚开始学数据结构中的单链表还是蛮吃力的,特别是后面的双链表操作更是如此。还有就是在实践代码操作时,你又会感到无从下手,没有思路。
    的头像 发表于 12-24 17:35 3069次阅读

    说说Go里面的链表操作

    按照逻辑结构来说,他们应该是一个挨着一个的,但是在实际存储当中并没有像这样连续,可能会散落在各个内存区里面。
    的头像 发表于 08-17 11:07 1560次阅读
    说说Go里面的<b class='flag-5'>链表</b><b class='flag-5'>操作</b>