【数据结构】单链表(超全)(二)

简介: 【数据结构】单链表(超全)(二)

2.4 创建新节点

SLTNode* BuySLTNode(SLTDataType x)
{
  SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
  if (newnode == NULL)
  {
    perror("malloc");
    return NULL;
  }
  newnode->data = x;
  newnode->next = NULL;
  return newnode;
}

2.5 头插

 头插显然是要改变头指针存放的地址,因此形参也需要传递二级指针。头插无需单独考虑空链表的情况

代码实现:

void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
  assert(pphead);
  SLTNode* newnode = BuySLTNode(x);
  newnode->next = *pphead;
  *pphead = newnode;
}

2.6 尾删

尾删先要遍历一遍链表找到最后一个节点将其释放掉,还要找到倒数第二个节点将它的指针域中存的地址改为NULL。所以定义两个指针让他们同时去遍历链表,一个找尾,另一个找倒数第二个节点。需要注意的是空链表和只有一个节点的链表的情况,空链表无法进行尾删,而只有一个节点的链表在尾删后会变成一个空链表,这意味着要改变头指针里面存放的地址,所以尾删形参也要传递二级指针。

代码实现:

void SLTPopBack(SLTNode** pphead)
{
  assert(pphead);
  assert(*pphead);//暴力检查是否为空链表,空链表不能删数据
  //检查链表是否为空
  /*if (*pphead == NULL)//温柔的进行检查
  {
    return;
  }*/
  //只有一个节点
  if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }
  //有多个节点
  else
  {
    //找尾
    SLTNode* prev = *pphead;
    SLTNode* tail = *pphead;
    while (tail->next != NULL)
    {
      prev = tail;
      tail = tail->next;
    }
    free(tail);
    tail = NULL;
    prev->next = NULL;//假如只有一个节点这里就会非法访问
  } 
}

2.7 头删

 头删很明显需要改变头指针中存放的地址,所以形参仍然需要传递二级指针。头删只需要注意链表是否为空,空链表无法进行删除。此外在进行头删的时候记得将原来的头节点释放掉,因此在改变头节点之前需要先保留原来头结点的地址,否则在更换完新的头节点后就找不到原来的头节点了。

代码展示:

void SLTPopFront(SLTNode** pphead)
{
  if (*pphead == NULL)//这里也可以直接用assert来断言
  {
    return;
  }
  SLTNode* tail = *pphead;
  *pphead = (*pphead)->next;//假如链表为空,这里就会发生越界,因此要判断链表是否为空
  free(tail);
  tail = NULL;
}

2.8 单链表查找

 其实就是遍历一遍链表,但是只能返回第一次出现的地址。查找可以当修改来使用,我们查找到节点的地址后就可以通过地址去修改数据域中存储的数据。

SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
  SLTNode* ptr = phead;
  while (ptr != NULL)
  {
    if (ptr->data == x)
    {
      return ptr;
    }
    else
    {
      ptr = ptr->next;
    }
  }
  return NULL;
}

2.9 在pos位置之前插入

 和尾插类似,但此时只需要遍历链表找到pos位置的前一个节点即可,同样需要注意pos是头结点的情况,此时就成头插了,需要改变头指针中存的地址,因此函数的形参需要传二级指针。

//在pos之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
  assert(pphead);
  assert(pos);
  if (pos == *pphead)
  {
    SLTPushFront(pphead, x);
  }
  else
  {
    SLTNode* newnode = BuySLTNode(x);
    SLTNode* prev = *pphead;
    while (prev->next != pos)
    {
      prev = prev->next;
    }
    prev->next = newnode;
    newnode->next = pos;
  }
}

 上面这种在pos位置前面插入的方法,需要知道头节点的地址

2.10 删除pos位置数据

 pos可能是头结点的地址,因此形参要用二级指针。

//pos位置删除
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
  assert(pphead);
  assert(*pphead);//空链表不能删
  assert(pos);
  if (pos == *pphead)
  {
    SLTPopFront(pphead);
  }
  else
  {
    SLTNode* prev = *pphead;
    while (prev->next != pos)
    {
      prev = prev->next;
    }
    prev->next = pos->next;
    free(pos);
    pos = NULL;//其实没用,形参的改变不改变实参
  }
}

2.11 在pos位置的后面插入

这里需要特别注意地址的赋值顺序。有以下两种正确的赋值顺序供大家参考:

先让newnode的指针域存储pos后一个节点的地址,再让pos的指针域存newnode的地址

借助中间变量先把pos后面节点的地址保存起来,再让pos的指针域存newnode的地址,最后再让newnode的指针域存第一步中间变量中保存的地址。

void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
  assert(pos);
  SLTNode* newnode = BuySLTNode(x);
  SLTNode* tmp = pos->next;
  pos->next = newnode;
  newnode->next = tmp;
}

2.12 删除pos位置后面的数

注意不能写成后面这样:pos->next = pos->next->next。这样写虽然把pos位置后面的节点从链表中剔除出去了,但并没有真正意义上的实现删除,因为每一个节点都是通过malloc在堆上申请的,不使用的时候要主动的去释放掉,也就是free掉,把这块空间归还给操作系统,否则会导致内存泄漏。而上面那样写,就会导致pos后面的节点丢失,无法进行释放,正确的做法是在执行这条语句之前把pos后边节点的地址先保存起来。

void SLTEraseAfter(SLTNode* pos)
//只能删除pos位置后面的节点,不能删除pos节点
//因为pos节点的前一个节点无从得知
{
  assert(pos);
  assert(pos->next);
  SLTNode* tmp = pos->next->next;//这里先保存了pos后面的后面的节点的地址,也是可以的
  free(pos->next);
  pos->next = tmp;
}

 今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,您的支持就是春人前进的动力!

目录
相关文章
【数据结构】单链表(长期维护)(1)
【数据结构】单链表(长期维护)(1)
119 0
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
235 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
java数据结构,线性表链式存储(单链表)的实现
文章讲解了单链表的基本概念和Java实现,包括头指针、尾节点和节点结构。提供了实现代码,包括数据结构、接口定义和具体实现类。通过测试代码演示了单链表的基本操作,如添加、删除、更新和查找元素,并总结了操作的时间复杂度。
java数据结构,线性表链式存储(单链表)的实现
|
存储
[数据结构] -- 单链表
[数据结构] -- 单链表
119 1
【数据结构】——单链表实现
【数据结构】——单链表实现
|
存储
数据结构2——单链表
数据结构2——单链表
116 1
|
存储
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(一)
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)
171 1
|
存储 算法 C语言
数据结构基础详解(C语言):单链表_定义_初始化_插入_删除_查找_建立操作_纯c语言代码注释讲解
本文详细介绍了单链表的理论知识,涵盖单链表的定义、优点与缺点,并通过示例代码讲解了单链表的初始化、插入、删除、查找等核心操作。文中还具体分析了按位序插入、指定节点前后插入、按位序删除及按值查找等算法实现,并提供了尾插法和头插法建立单链表的方法,帮助读者深入理解单链表的基本原理与应用技巧。
2301 6
|
存储
数据结构(单链表)
数据结构(单链表)
114 0
|
存储
数据结构--单链表
数据结构--单链表

热门文章

最新文章