当前位置: 首页 > ai >正文

数据结构-单向链表

1.什么是数据结构

数据结构:用来组织和存储数据

程序设计 = 数据结构 + 算法

2. 数据与数据之间的关系

 1)逻辑结构 :数据元素与元素之间的关系

集合:元素与元素之间平等的集合关系
线性结构:数据元素与元素之间存在一对一的关系(顺序表、链表、队列、栈)
树形结构:数据元素与元素之间存在一对多的关系(二叉树)
图形结构:数据元素与元素之间存在多对多的关系 (网状结构)

  2)物理结构 :数据元素在计算机内存中的存储方式

        顺序结构:在内存中选用一段连续的内存空间进行存储

1.数据访问方便(O(1))
2.插入和删除数据时需要移动大量数据
3.需要预内存分配
4. 可能造成大量的内存碎片

                          

        链式结构:可以在内存中选用一段非连续的内存空间进行存储

1. 数据访问时必须要从头遍历(O(n))
2. 插入和删除元素方便
3. 不需要预内存分配,是一种动态存储的方式

        索引结构:将要存储的数据的关键字和存储位置之间构建一个索引表。

        散列结构(哈希结构):将数据的存储位置与数据元素之间的关键字建立起对应的关系(哈数函数),根据该关系进行数据存储和查找

 

3.单向链表

(1)一般形式

 

(2)操作

1. 创建链表对象
2. 插入数据(头插、尾插)
3. 删除数据(头删、尾删)
4. 查找数据
5. 修改数据
6. 销毁链表

(3)快慢指针 

  • 慢指针 (slow pointer):通常每次移动一个节点

  • 快指针 (fast pointer):通常每次移动两个节点(也可以是其他固定步长)

 (4)例题

①查找链表中间位置

Node_t *find_Mid_link(Link_t *plink)
{Node_t *pfast = plink->phead;Node_t *pslow = pfast;if(NULL == plink){return NULL;}while(pfast != NULL){pfast = pfast->pnext;if(NULL == pfast){break;}pfast = pfast->pnext;pslow = pslow->pnext;}return pslow;
}

算法思想:

  1. 初始化阶段

    • 创建两个指针pfast和pslow,初始都指向链表头节点

    • 检查链表是否为空(NULL == plink)

  2. 双指针遍历阶段

    • 快指针(pfast):每次移动两步(pfast = pfast->pnext->pnext)

    • 慢指针(pslow):每次移动一步(pslow = pslow->pnext)

    • 在快指针每次移动第二步前检查是否已到链表末尾(NULL == pfast)

  3. 终止条件

    • 当快指针pfast到达链表末尾(pfast == NULL)时停止

    • 此时慢指针pslow指向的就是链表的中间节点

  4. 返回结果

    • 直接返回慢指针pslow指向的节点

②找个链表中倒数第k个元素

Node_t *find_k_link(Link_t *plink, int k)
{Node_t *pfast = plink->phead;Node_t *pslow = pfast;if(NULL == plink){return NULL;}for(int i = 0;i < k;++i){if(NULL == pfast){return NULL;}pfast = pfast->pnext;}while(NULL != pfast){pfast = pfast->pnext;pslow = pslow->pnext;}return pslow;}

算法思想:

  1. 初始化阶段

    • 设置两个指针pfast和pslow,初始都指向链表头节点

    • 检查链表是否为空(NULL == plink)

  2. 快指针先行阶段

    • 快指针pfast先向前移动K步(for循环)

    • 在移动过程中检查是否超出链表长度(NULL == pfast)

    • 如果K大于链表长度,直接返回NULL

  3. 双指针同步移动阶段

    • 当快指针pfast移动K步后

    • 同时移动快指针pfast和慢指针pslow,每次各移动一步

    • 直到快指针pfast到达链表末尾(NULL != pfast)

  4. 结果返回

    • 当快指针pfast为NULL时,慢指针pslow正好指向倒数第K个节点

    • 返回pslow指针

③对链表进行倒序

void reverse_link(Link_t *plink)
{if(NULL == plink){return ;}Node_t *ptmp = plink->phead;Node_t *pinsert;plink->phead = NULL;while(ptmp != NULL){pinsert = ptmp;ptmp = ptmp->pnext;pinsert->pnext = plink->phead;plink->phead = pinsert;}
}

算法思想:

  1. 初始化阶段

    • 保存原链表头节点指针(ptmp)

    • 将链表头指针(plink->phead)置为NULL,准备构建新链表

  2. 逆置过程

    • 遍历原链表:使用ptmp指针逐个访问原链表节点

    • 处理每个节点(pinsert)
      a. 保存当前节点(pinsert = ptmp)
      b. 移动ptmp到下一个节点(ptmp = ptmp->pnext)
      c. 将当前节点插入到新链表头部:

      • 当前节点的next指向新链表头(pinsert->pnext = plink->phead)

      • 更新链表头为当前节点(plink->phead = pinsert)

  3. 终止条件

    • 当ptmp为NULL时,表示原链表已全部处理完毕

 

④用插入排序的算法对链表进行排序

void sort_link(Link_t *plink)
{if(NULL == plink){return ;}Node_t *ptmp = plink->phead->pnext;Node_t *pinsert = NULL;plink->phead->pnext = NULL;while(ptmp != NULL){pinsert = ptmp;ptmp = ptmp->pnext;if(plink->phead->data >= pinsert->data){pinsert->pnext = plink->phead;plink->phead = pinsert;}else{Node_t *p = plink->phead;while(p->pnext != NULL && p->pnext->data < pinsert->data){p = p->pnext;}pinsert->pnext = p->pnext;p->pnext = pinsert;}}
}

算法思想:

  1. 初始化阶段

    • 将原链表头节点之后的节点(ptmp)逐个取出进行排序

    • 初始化一个"已排序链表",开始时只包含原头节点

  2. 排序过程

    • 外层循环:遍历原链表的每个未排序节点(ptmp)

    • 处理每个节点(pinsert)
      a. 若节点值 ≤ 已排序链表头节点值:

      • 直接插入到链表头部
        b. 否则:

      • 在已排序链表中顺序查找插入位置

      • 找到第一个大于当前节点值的节点的前驱位置

      • 将当前节点插入到该位置

  3. 终止条件

    • 当所有未排序节点(ptmp)都处理完毕时结束

4.网络配置

5.检查内存泄漏

valgrind : gnu提供的内存探测工具,可以用来监测内存错误和内存泄露。

内存泄露:申请的空间使用完时没有及时释放,造成内存泄露。

valgrind  ./a.out         来检验是否有内存泄漏

http://www.xdnf.cn/news/16972.html

相关文章:

  • NDK-参数加密和签名校验
  • Linux(centos)安全狗
  • 线程互斥锁:守护临界区的关键
  • Mybatis 简单练习,自定义sql关联查询
  • 2025年信创政策解读:如何应对国产化替代挑战?(附禅道/飞书多维表格/华为云DevCloud实战指南)
  • 【C#】操作Execl和Word文件-1
  • 白杨SEO:百度搜索开放平台发布AI计划是什么?MCP网站红利来了?顺带说说其它
  • AWS Lambda Function 全解:无服务器计算
  • 如何使用 DBeaver 连接 MySQL 数据库
  • script标签放在header里和放在body底部里有什么区别?
  • Spring之【Bean的实例化方式】
  • Azure DevOps - 使用 Ansible 轻松配置 Azure DevOps 代理 - 第6部分
  • 设计模式(一)——抽象工厂模式
  • 机器学习实战:逻辑回归深度解析与欺诈检测评估指标详解(二)
  • 16.8 华为昇腾CANN架构深度实战:3大核心引擎解析与性能优化216%秘籍
  • 机器学习【六】readom forest
  • Dubbo 3.x源码(32)—Dubbo Provider处理服务调用请求源码
  • Ribbon 核心原理与架构详解:服务负载均衡的隐形支柱
  • 解决MySQL删除/var/lib/mysql下的所有文件后无法启动的问题
  • Flink从Kafka读取数据的完整指南
  • 段落注入(Passage Injection):让RAG系统在噪声中保持清醒的推理能力
  • 【动态规划 | 回文字串问题】动态规划解回文问题的核心套路
  • 基于落霞归雁思维框架的自动化测试实践与探索
  • 项目一:Python实现PDF增删改查编辑保存功能的全栈解决方案
  • 使用 SecureCRT 连接华为 eNSP 模拟器的方法
  • 浅谈 Python 中的 next() 函数 —— 迭代器的驱动引擎
  • 嵌入式开发学习———Linux环境下IO进程线程学习(三)
  • 【五大联赛】 2025-2026赛季基本信息
  • android TextView lineHeight 是什么 ?
  • Android GPU测试