跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C算法

数据结构与算法:单链表综合运用(合并、分割与约瑟夫环)

单链表操作涵盖合并有序链表、分割链表及环形链表约瑟夫问题。合并利用哨兵位简化插入逻辑;分割通过双链表分类处理并防止死循环;约瑟夫问题结合循环计数实现元素出队。掌握哨兵位、指针移动及内存管理技巧,有助于夯实数据结构基础,提升面试竞争力。

孤勇者发布于 2026/2/4更新于 2026/6/15.6K 浏览
数据结构与算法:单链表综合运用(合并、分割与约瑟夫环)

数据结构与算法:单链表综合运用

链表是 C 语言数据结构的核心内容,也是算法面试的高频考点。本文聚焦链表经典实操题型,从合并有序链表、分割链表到环形链表约瑟夫问题,由浅入深拆解解题思路,结合哨兵位、循环计数等实用技巧,通过清晰的算法原理与完整代码实现,帮助读者吃透链表操作逻辑。

一、合并两个有序链表

1.1 题目

LeetCode 合并两个有序链表

1.2 算法原理

核心: 判断大小 + 链表插入 + 建立一个哨兵位

和合并两个有序数组的思路一样,定义四个指针:

  • newhead 和 newtail:新链表的头尾节点
  • pcur1 和 pcur2:分别指向两个要合并的链表的头节点

技巧: 可以 malloc 一块空间让 newhead 和 newtail 指向这块空间,使其成为首元节点(哨兵位),这样在插入时可以免去链表为空情况的判断,最后返回新链表的下一个节点即可。

哨兵位: 数值域不存储有效数据,指针域存储有效地址

1.3 代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    ListNode* newhead = (ListNode*)malloc(sizeof(ListNode));
    ListNode* pcur1 = list1;
    ListNode* pcur2 = list2;
    ListNode* newtail = newhead;
    newtail->next = NULL;

    while (pcur1 && pcur2) {
        if (pcur1->val <= pcur2->val) {
            newtail->next = pcur1;
            newtail = newtail->next;
            pcur1 = pcur1->next;
        } else {
            newtail->next = pcur2;
            newtail = newtail->next;
            pcur2 = pcur2->next;
        }
    }

    // 为遍历完的链表直接接上新链表尾部节点
    if (pcur1) newtail->next = pcur1;
    if (pcur2) newtail->next = pcur2;

    return newhead->next;
}

注:工程开发中应及时释放手动开辟的空间,养成良好的编程习惯。

二、分割链表

2.1 题目

LeetCode 分割链表

2.2 算法原理

创建两个新链表,list1 和 list2 分别存放小于 x 和大于或等于 x 的节点,最后让 list1 的尾指针指向 list2 的第一个元素即可。

注: list2 作为新链表的后半部分,最后一个节点的 next 要及时置 NULL,防止死循环。

技巧: 依旧可以使用哨兵位,并把哨兵位的 next 初始化为 NULL,可以避免合并时一条链表为空的特殊判断造成要写大量特判代码。

2.3 代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;

struct ListNode* partition(struct ListNode* head, int x) {
    if (head == NULL) return head;

    // 指向小于 x 链表的头节点
    ListNode* list1 = (ListNode*)malloc(sizeof(ListNode));
    ListNode* tail1 = list1;
    // 指向大于 x 链表的头节点
    ListNode* list2 = (ListNode*)malloc(sizeof(ListNode));
    ListNode* tail2 = list2;

    // 防止单个节点链表出现非法解引用
    list1->next = NULL;
    list2->next = NULL;

    ListNode* pcur = head;
    while (pcur) {
        if (pcur->val < x) {
            tail1->next = pcur;
            tail1 = tail1->next;
        } else {
            tail2->next = pcur;
            tail2 = tail2->next;
        }
        pcur = pcur->next;
    }

    tail1->next = list2->next; // 连接两部分
    tail2->next = NULL;        // 防止死循环
    return list1->next;
}

三、环形链表的约瑟夫问题

3.1 题目

牛客网 环形链表的约瑟夫问题

3.2 算法原理

核心: 利用循环链表 + 循环计数

定义一个指针 prev 指尾节点,一个指针 phead 指向头结点,利用一个变量 count 来循环计数,当 count == m 时让 phead 指向的当前元素出队即可。

3.3 代码

typedef struct ListNode ListNode;

// 创建节点
ListNode* BuyNode(int x) {
    ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
    newnode->val = x;
    newnode->next = NULL;
    return newnode;
}

// 创建环形链表
ListNode* CyclicList(int n) {
    ListNode* head = BuyNode(1);
    ListNode* tail = head;
    for (int i = 2; i <= n; i++) {
        tail->next = BuyNode(i);
        tail = tail->next;
    }
    tail->next = head;
    return tail;
}

int ysf(int n, int m) {
    ListNode* prev = CyclicList(n);
    ListNode* phead = prev->next;
    int count = 1;

    while (phead != prev) {
        if (count == m) {
            prev->next = phead->next;
            free(phead);
            phead = prev->next;
            count = 1;
        } else {
            prev = phead;
            phead = phead->next;
            count++;
        }
    }
    return phead->val;
}

总结

本文系统讲解了链表操作的三大经典题型:合并有序链表通过哨兵位简化插入逻辑,分割链表采用双链表分类处理,环形链表约瑟夫问题巧妙结合循环计数。每种解法均配有清晰的算法图解和完整代码实现,帮助读者深入理解链表操作的核心逻辑与实用技巧。掌握这些题型不仅能提升面试竞争力,更能培养扎实的数据结构思维。

目录

  1. 数据结构与算法:单链表综合运用
  2. 一、合并两个有序链表
  3. 1.1 题目
  4. 1.2 算法原理
  5. 1.3 代码
  6. 二、分割链表
  7. 2.1 题目
  8. 2.2 算法原理
  9. 2.3 代码
  10. 三、环形链表的约瑟夫问题
  11. 3.1 题目
  12. 3.2 算法原理
  13. 3.3 代码
  14. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 网络通讯核心协议详解:TCP、UDP 与 HTTP/HTTPS
  • OpenClaw 漏洞预警:如何为 AI 代理添加行为审计?
  • 网络安全学习路线与技能规划指南
  • GitHub 身份验证方式 PAT 和 SSH 详解
  • Python Django 鉴权方案全解析
  • 基于 Langchain-Chatchat 与 Qwen 搭建本地知识库
  • Webnovel Writer:基于 Claude Code 的长篇网文 AI 创作系统
  • Apache IoTDB 时序数据管理:写入、存储与查询优化
  • 使用 Dify 搭建合同审查法律文书机器人 Agent
  • Shannon:基于白盒分析的 AI 自动化渗透测试平台
  • Linux 进程替换详解:从 fork 到 exec 的完整链路
  • Flutter 三方库 anthropic_sdk_dart 在鸿蒙系统的适配指南
  • AI 辅助前端 UI 设计工具 UI UX Pro Max 实战指南
  • 博士求职复盘:华为、字节与 DeepSeek 的抉择与思考
  • OpenClaw 浏览器控制方案:利用 Chrome Debug 模式实现全自动控制
  • Flutter 三方库 discord_interactions 在 OpenHarmony 的适配指南
  • 数据结构:树、森林与二叉树的转换详解
  • 策略模式:接口与委托的两种实现方式
  • 华为 OD 机试双机位 C 卷 - 数组连续和
  • ASP.NET Core Web API 控制器及方法常用注解属性详解

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online