【数据结构】C--单链表(小白入门基础知识)(中)

简介: 【数据结构】C--单链表(小白入门基础知识)(中)

错误代码3:

画图:

91baa5762dde489b9ebf48708bc97815.png

void SLPushFront(SLTNode** pphead, SLTDataType x);

void SLPushBack(SLTNode* phead, SLTDataType x);


void TestSList2()

{

   SLTNode* plist = NULL;

   SLPushBack(plist, 1);

   SLPushBack(plist, 2);

   SLTPrint(plist);

}


void SLPushBack(SLTNode* phead, SLTDataType x)

{

   SLTNode* newnode = BuyLTNode(x);



   if (phead == NULL)

   {

       phead = newnode;

   }

   else

   {

       SLTNode* tail = phead;

       while (tail->next != NULL)

       {

           tail = tail->next;

       }


       tail->next = newnode;

   }

}

输出:

0e53694e1cd44067a9a75b3ec3dac17c.png

列举了这么多错误案例接下来到正确案例:

0cef5d8ccb2c44bebb06a1f9d164cea7.png

void SLPushBack(SLTNode** pphead, SLTDataType x)
void TestSList2()
{
  SLTNode* plist = NULL;
  SLPushBack(&plist, 1);
  SLPushBack(&plist, 2);
  SLPushBack(&plist, 3);
  SLPushBack(&plist, 4);
  SLTPrint(plist);
}
//要让新节点和tail链接起来,一定要去改tail的next
void SLPushBack(SLTNode** pphead, SLTDataType x)//尾插的本质是让上一个结点链接下一个结点
{
  SLTNode* newnode = BuyLTNode(x);
  // 1、空链表
  // 2、非空链表
  if (*pphead == NULL)
  {
    *pphead = newnode;
  }
  else
  {
    SLTNode* tail = *pphead;
    while (tail->next != NULL)
    {
      tail = tail->next;
    }
    tail->next = newnode;
  }
}

代码执行:

0c8ac213dfcf45bfb27e113fc5ffae80.png


2.5单链表头插

头插思路:

0ce7197dee404196855c4ac42c4c2af6.png

头插第二个节点思路:

85a1dc09672042a2b4625b88f8996cd6.png

头插的代码可以写成这样

void SLPushFront(SLTNode** pphead, SLTDataType x)
{
  SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//使用malloc函数动态分配了一个大小为SLTNode的内存块,
  //并将其强制转换为 SLTNode 指针类型,即创建了一个新的节点。
  if (newnode == NULL)
  {
    perror("malloc fail");
    return NULL;
  }
  //需要注意的是,在使用 malloc 函数动态分配内存时,需要手动释放内存,否则会导致内存泄漏
  //因此,在创建单链表节点后,我们应该在适当的时候使用 free 函数释放节点所占用的内存
  newnode->data = x;
  newnode->next = NULL;
  //return newnode;//返回的是一个结点的地址
  newnode->next = *pphead;
  *pphead = newnode;//将头节点*pphead 更新为新节点的地址,以使新节点成为新的头节点。
}


但是为了避免创建新节点的程序重复编写,可以利用上面的BuyLTNode(x)函数定义新节点达成简写的目的,也可以头插的函数也可以写成这样:

void SLPushFront(SLTNode** pphead, SLTDataType x)
{
  SLTNode* newnode = BuyLTNode(x);
  newnode->next = *pphead;
  *pphead = newnode;
}


SLPushFront 函数中,我们首先调用 BuyLTNode(x) 函数创建一个新的节点,然后将新节点的 next 指针指向当前链表头节点,接着将链表头指针指向新节点,从而完成了在链表头部插入新节点的操作。

代码执行:

44e497a8d4e14cd0a865680a65bae99a.png


2.6单链表尾删

错误案例:

ef59a119349845548b3dae6a29dd5d57.png

方法1:

f0181332d8b449f7aa0d5335d6dcb84a.png

方法2:

3109a0df67624d2aa392039bdc114d34.png

代码实例:

void SLPopBack(SLTNode** pphead)
{
  //没有节点(空链表)
  //暴力检查
  assert(*pphead);
  //温柔检查
  if (*pphead == NULL)
  {
    return;
  }
  //一个节点
  if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }//多个节点
  else
  {
    SLTNode* prev = NULL;
    SLTNode* tail = *pphead;
    //找尾
    //方法一
    /*while (tail->next)
    {
      prev = tail;
      tail = tail->next;
    }
    free(tail);
    prev->next = NULL;*/
    //方法二
    SLTNode* tail = *pphead;
    while (tail->next->next)
    {
      tail = tail->next;
    }
    free(tail->next);
    tail->next = NULL;
  }
}


执行:

a3ae5843ac244c1e86fedd91ac641289.png


2.7单链表头删

思路:

d26c492911084a75bf94c848bfdf6118.png

void SPopFront(SLTNode** pphead)
{
  //没有节点
  //暴力检查
  assert(*pphead);
  //温柔检查
  if (*pphead == NULL)
    return;// 一个节点
  if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }
  //多个节点
  else
  {
    SLTNode* del = *pphead;//相当于一个标记,删掉的标记
    //写法一
    //*pphead = del->next;
    //写法二 
    *pphead = (*pphead)->next;
    free(del);
  }
}

执行:

650e763119eb46868ac4781e534f46f6.png


2.8单链表查找/修改某个值

使用尾插将1,2,3,4按先后顺序分别插入链表中,接着找到链表中值为3的元素,并把其改为30(可以通过定义结构体类型的指针访问data为3的结点,并直接通过pos->next=30修改)

注意:直接在main函数内定义一个test函数修改值即可,不必另定义新函数。

SLTNode* STFind(SLTNode* phead, SLTDataType x)
{
  //assert(phead);
  SLTNode* cur = phead;
  while (cur)
  {
    if (cur->data == x)
    {
      return cur;
    }
    cur = cur->next;
  }
  return NULL;
}


执行:

26c6f8c8461c4f029e6abbcd42d1f64b.png

相关文章
|
2月前
【数据结构】单链表(长期维护)(1)
【数据结构】单链表(长期维护)(1)
|
6天前
|
存储 Java
java数据结构,线性表链式存储(单链表)的实现
文章讲解了单链表的基本概念和Java实现,包括头指针、尾节点和节点结构。提供了实现代码,包括数据结构、接口定义和具体实现类。通过测试代码演示了单链表的基本操作,如添加、删除、更新和查找元素,并总结了操作的时间复杂度。
java数据结构,线性表链式存储(单链表)的实现
|
24天前
|
存储 算法 C语言
数据结构基础详解(C语言):单链表_定义_初始化_插入_删除_查找_建立操作_纯c语言代码注释讲解
本文详细介绍了单链表的理论知识,涵盖单链表的定义、优点与缺点,并通过示例代码讲解了单链表的初始化、插入、删除、查找等核心操作。文中还具体分析了按位序插入、指定节点前后插入、按位序删除及按值查找等算法实现,并提供了尾插法和头插法建立单链表的方法,帮助读者深入理解单链表的基本原理与应用技巧。
|
2月前
|
应用服务中间件 nginx C语言
Nginx入门 -- 基本数据结构中之ngx_str_t,ngx_array_t
这两种数据结构是Nginx自定义数据类型的例子,它们证明了Nginx设计者在构建一个为高并发和高性能优化的web服务器时的精确和高效。理解这些数据结构是深入学习Nginx内部机制的基础,同时也是扩展和开发Nginx模块不可或缺的一部分知识。
28 1
|
2月前
|
存储
【数据结构】单链表-->详细讲解,后赋源码
【数据结构】单链表-->详细讲解,后赋源码
24 4
|
2月前
|
算法 索引
【初阶数据结构篇】单链表算法题进阶
深拷贝应该正好由 n 个全新节点组成,其中每个新节点的值都设为其对应的原节点的值。
|
2月前
【数据结构】单链表(长期维护)(2)
【数据结构】单链表(长期维护)(2)
|
3月前
|
算法 数据挖掘 计算机视觉
Python并查集实战宝典:从入门到精通,让你的数据结构技能无懈可击!
【7月更文挑战第17天】并查集,如同瑞士军刀,是解决元素分组问题的利器,应用于好友关系、像素聚类、碰撞检测和连通性分析等场景。本文从基础到实战,介绍并查集的初始化、查找与路径压缩、按秩合并,以及在Kruskal算法中的应用。通过并查集,实现高效动态集合操作,对比哈希表和平衡树,其在合并与查找上的性能尤为突出。学习并查集,提升算法解决复杂问题的能力。
66 5
|
2月前
|
存储 算法 调度
10种 Python数据结构,从入门到精通
10种 Python数据结构,从入门到精通
31 0
|
3月前
|
存储 DataX C语言
【数据结构】单链表
数据结构中的单链表
23 0
【数据结构】单链表