【数据结构】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

相关文章
|
1月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
33 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
1月前
|
存储
[数据结构] -- 单链表
[数据结构] -- 单链表
26 1
|
1月前
|
存储
【数据结构】——单链表实现
【数据结构】——单链表实现
|
1月前
|
存储
数据结构2——单链表
数据结构2——单链表
33 1
|
1月前
|
存储
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(一)
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)
|
1月前
|
存储
数据结构(单链表)
数据结构(单链表)
17 0
|
1月前
|
存储 机器学习/深度学习 算法
探索数据结构:入门及复杂度的解锁
探索数据结构:入门及复杂度的解锁
|
1月前
|
存储 缓存 应用服务中间件
Nginx入门 -- 基本数据结构中之ngx_hash_t
Nginx入门 -- 基本数据结构中之ngx_hash_t
36 0
|
1月前
|
存储 缓存 应用服务中间件
Nginx入门 -- 基本数据结构中之ngx_list_t,ngx_queue_t
Nginx入门 -- 基本数据结构中之ngx_list_t,ngx_queue_t
26 0
|
1月前
|
存储 应用服务中间件 nginx
Nginx入门 -- 基本数据结构中之ngx_str_t,ngx_array_t
Nginx入门 -- 基本数据结构中之ngx_str_t,ngx_array_t
70 0