【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(二)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)

【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(一)https://developer.aliyun.com/article/1617260

6.4 查找单链表中数据

SLNode* SLTFind(SLNode* pphead, SLNDataType x)
{
  SLNode* cur = pphead;
  while (cur!=NULL)
  {
    if (cur->val == x)
      return cur;
    else
      cur = cur->next;
  }
  return NULL;
}

这里需要注意的是:遍历链表,找到返回当前节点,没有找到继续向下遍历

6.5 关于单链表的任意位置插入和删除

6.5.1 单链表的pos指定前插入

void SLTInsert(SLNode** pphead,SLNode *pos,SLNDataType x)//pos指定之前插入
{
  assert(pphead);
  assert(*pphead);
  if (pos == NULL)//没有节点
  {
    SLTPushFront(pphead, x);
  }
  if (*pphead == pos)//一个节点
  {
    SLTPushFront(pphead, x);
  }
  else//多个节点
  {
    SLNode* newnode = CreateNode(x);
    SLNode* cur = *pphead;
    while (cur->next != pos)//上面避免了pos等于cur
    {
      cur = cur->next;
    }
    cur->next = newnode;
    newnode->next = pos;
  }
}

这里需要注意的是:需要分为三种情况,空节点,一个节点,多个节点就行处理。空节点调用尾插或者头插都可以,一个节点(在pos前插入)那么可以调用头插

6.5.2 单链表的删除pos当前结点

void SLTEeara(SLNode** pphead, SLNode* pos)
{
  assert(pphead);//防止用户传个空指针
  assert(*pphead);
  assert(pos);
  SLNode* next = pos->next;
  SLNode* cur = *pphead;
  if (cur==pos)
  *pphead = NULL;
        free(cur);
    cur = NULL;
  else
  {
    while (cur->next != pos)
    {
      cur = cur->next;
    }
    cur->next = next;
    free(pos);
    pos = NULL;
  }
}

这里需要注意的是:分为两种情况,存在一个节点和多个节点的处理。如果使用三个变量,需要使用到的地址不会丢失,就不需要担心先后顺序问题。结点是一块块的独立空间,其链接方式也是较灵活的,这里跟上面方法是类似的。

如果不想在pos之前插入\删除,可以改动逻辑在pos之后进行插入、删除。

6.5.3 单链表的pos之后插入

void SLTInsertAfter(SLNode **pphead,SLNode* pos, SLNDataType x)
{
  assert(pphead);
  assert(*pphead);
  if (pos == NULL)//没有节点
  {
    SLTPushFront(pphead, x);
  }
  if (*pphead == pos)//一个节点
  {
    SLTPushBack(pphead, x);
  }
  else//多个节点
  {
    SLNode* newnode = CreateNode(x);
    SLNode* back = pos->next;
    newnode->next = back;
    pos->next = newnode;
  }
}

6.5.4 单链表的pos之后删除

void SLTEearaAfter(SLNode **pphead,SLNode* pos)
{
  assert(pphead);
  assert(*pphead);
  assert(pos);
  SLNode* cur = *pphead;
  SLNode* back = pos->next;
  if (cur == pos)//只有一个结点
    SLTPopBack(pphead);
  if(back->next==NULL)
  {
    free(back);
    back = NULL;
    pos->next = NULL;
  }
  else
  {
    pos->next = back->next;
    free(back);
    back = NULL;
  }
}

上面的两个接口实现过程跟SLTInsertSLTEeara实现类似的,看看代码就能理解

在完成了单链表的核心接口,我们需要继续完善剩下的接口,使实现的单链表功能更加丰富起来。

6.6 单链表的打印

void SLTPrint(SLNode** pphead)//二级指针改变外的结构体指针类型
{
  assert(pphead);
  SLNode* cur = *pphead;
  while (cur!= NULL)
  {
    printf("%d->", cur->val);
    cur = cur->next;
  }
  printf("NULL\n");
}

这里需要注意的是:当cur==NULL时,没有进去循环,需要额外打印NULL,最后不要忘记单链表的销毁

void SLTDestroy(SLNode** pphead)
{
  assert(pphead);
  SLNode* cur = *pphead;
  while (cur)
  {
    SLNode* next = cur->next;
    free(cur);
    //这里cur不要赋空,还需要使用的
    cur = next;
}
  *pphead = NULL;
}

这里需要注意的是:链表是通过多个节点链接而成的,同时也是一块块独立空间,通过cur去访问每一个空间和释放每一块空间。其中free指针跟指针变身是没有关系的,释放的是指针所指向的那一块动态空间

七、顺序表和链表的区别

不同点 顺序表 链表
存储空间上 物理上一定连续 逻辑上连续,但物理上不一定 连续
随机访问 支持O(1) 不支持:O(N)
任意位置插入或者删除 元素 可能需要搬移元素,效率低 O(N) 只需修改指针指向
插入 动态顺序表,空间不够时需要 扩容 没有容量的概念
应用场景 元素高效存储+频繁访问 任意位置插入和删除频繁
缓存利用率

不管是哪一种数据结构都有他的优点和缺点,对此在使用数据结构中应该知道它的优缺点是什么,加以合理地利用解决实际中的问题。



相关文章
|
1天前
|
搜索推荐 C++
【初阶数据结构】深度解析七大常见排序|掌握底层逻辑与原理(一)
【初阶数据结构】深度解析七大常见排序|掌握底层逻辑与原理
|
1天前
|
搜索推荐 索引
【初阶数据结构】深度解析七大常见排序|掌握底层逻辑与原理(二)
【初阶数据结构】深度解析七大常见排序|掌握底层逻辑与原理
|
1天前
|
存储 编译器 C++
【初阶数据结构】掌握二叉树遍历技巧与信息求解:深入解析四种遍历方法及树的结构与统计分析
【初阶数据结构】掌握二叉树遍历技巧与信息求解:深入解析四种遍历方法及树的结构与统计分析
|
1天前
【初阶数据结构】深入解析队列:探索底层逻辑
【初阶数据结构】深入解析队列:探索底层逻辑
|
1天前
|
人工智能 搜索推荐 算法
【初阶数据结构】深度解析七大常见排序|掌握底层逻辑与原理(三)
【初阶数据结构】深度解析七大常见排序|掌握底层逻辑与原理
|
1天前
|
存储
【初阶数据结构】深入解析循环队列:探索底层逻辑
【初阶数据结构】深入解析循环队列:探索底层逻辑
|
1天前
|
存储
【初阶数据结构】深入解析栈:探索底层逻辑
【初阶数据结构】深入解析栈:探索底层逻辑
|
9天前
|
算法 安全 测试技术
golang 栈数据结构的实现和应用
本文详细介绍了“栈”这一数据结构的特点,并用Golang实现栈。栈是一种FILO(First In Last Out,即先进后出或后进先出)的数据结构。文章展示了如何用slice和链表来实现栈,并通过golang benchmark测试了二者的性能差异。此外,还提供了几个使用栈结构解决的实际算法问题示例,如有效的括号匹配等。
golang 栈数据结构的实现和应用
|
10天前
01_设计一个有getMin功能的栈
01_设计一个有getMin功能的栈
|
10天前
|
前端开发
07_用队列实现栈
07_用队列实现栈

热门文章

最新文章