链表的创建:头插法与尾插法详解(数据结构)

news2025/3/30 15:30:11

C++ 链表的创建:头插法与尾插法详解

在这里插入图片描述

链表(Linked List)是一种重要的数据结构,适用于插入和删除操作频繁的场景。本文介绍 两种常见的链表构建方法

  • 尾插法(Append / Tail Insertion):适合顺序存储,插入顺序与输入顺序一致。
  • 头插法(Prepend / Head Insertion):适合逆序存储,输入的元素会被倒序存入链表。

本文提供详细的代码实现、解析以及常见错误分析,帮助初学者理解链表的构建方式。


一、链表的基本结构

在 C++ 语言中,我们通常使用结构体(struct)定义链表节点:

#include <iostream>

typedef struct Node {
    int data;      // 数据域
    struct Node* next;  // 指针域,指向下一个节点
} Node, *LinkList;
  • data:存储节点数据。
  • next:存储指向下一个节点的指针。
  • LinkListNode* 的别名,表示指向链表头部的指针。

二、尾插法(顺序存储)

尾插法按照输入顺序 依次插入新节点,适用于按 自然顺序 存储数据。
核心思路

  1. 创建头节点 作为链表的起点。
  2. 维护一个尾指针 r,用于记录链表末尾,以便快速添加新节点。
  3. 每次创建一个新节点,将其链接到尾指针 r,然后更新 r 指向新节点。

✅ 尾插法代码实现

#include <iostream>
#include <cstdlib>  // malloc 需要包含此头文件

typedef struct Node {
    int data;
    struct Node* next;
} Node, *LinkList;

// 初始化链表(带头结点)
void Init(LinkList &L) {
    L = (Node*)malloc(sizeof(Node));
    L->next = NULL;
}

// 尾插法插入元素
void InsertTail(LinkList &L, int e) {
    Node* r = L; // 记录链表尾部
    Node* s;
    
    while (e != -1) {  // 以 -1 作为输入结束标志
        s = (Node*)malloc(sizeof(Node));
        s->data = e;
        s->next = NULL;
        
        r->next = s; // 连接新结点
        r = s; // 更新尾指针
        
        std::cin >> e; // 读取下一个数据
    }
}

// 打印链表
void PrintL(LinkList &L) {
    Node* p = L->next; // 跳过头结点
    if (!p) {
        std::cout << "Empty List\n";
        return;
    }
    while (p) {
        std::cout << p->data << " -> ";
        p = p->next;
    }
    std::cout << "NULL\n";
}

// 释放链表
void FreeList(LinkList &L) {
    Node* p = L;
    while (p) {
        Node* temp = p;
        p = p->next;
        free(temp);
    }
    L = NULL;
}

int main() {
    LinkList L;
    Init(L);

    int e;
    std::cin >> e;
    InsertTail(L, e);

    PrintL(L);
    FreeList(L);
    return 0;
}

📌 示例输入

1 2 3 4 -1

📌 示例输出

1 -> 2 -> 3 -> 4 -> NULL

三、头插法(逆序存储)

头插法逆序存储输入数据,新节点总是插入到链表头部,适用于从后往前访问数据的场景。
核心思路

  1. 创建头节点 作为链表的起点。
  2. 每次创建一个新节点,让其 next 指向头节点 Lnext,然后 L->next 指向新节点。
  3. 这样每次新插入的节点都位于链表头部,最终形成逆序链表

✅ 头插法代码实现

#include <iostream>
#include <cstdlib>

typedef struct Node {
    int data;
    struct Node* next;
} Node, *LinkList;

// 初始化链表(带头结点)
Node* InitL(LinkList &L) {
    L = (Node*)malloc(sizeof(Node));
    L->next = NULL;
    return L;
}

// 头插法插入元素
void InsertNext(LinkList &L, int e) {
    while (e != 9999) {  // 以 9999 作为输入结束标志
        Node* p = (Node*)malloc(sizeof(Node));
        p->data = e;
        p->next = L->next;  // 让新节点指向头结点的下一个节点
        L->next = p;        // 头结点指向新插入的节点
        
        std::cin >> e; // 读取下一个数据
    }
}

// 打印链表
void PrintL(LinkList &L) {
    Node* p = L->next;
    if (!p) {
        std::cout << "Empty List\n";
        return;
    }
    while (p) {
        std::cout << p->data << " -> ";
        p = p->next;
    }
    std::cout << "NULL\n";
}

// 释放链表
void FreeList(LinkList &L) {
    Node* p = L;
    while (p) {
        Node* temp = p;
        p = p->next;
        free(temp);
    }
    L = NULL;
}

int main() {
    LinkList L;
    InitL(L);

    int e;
    std::cin >> e;
    InsertNext(L, e);

    PrintL(L);
    FreeList(L);
    return 0;
}

📌 示例输入

1 2 3 4 5 6 9999

📌 示例输出

6 -> 5 -> 4 -> 3 -> 2 -> 1 -> NULL

四、尾插法 vs. 头插法

方法适用场景特点代码复杂度
尾插法顺序存储 数据- 适用于队列、链表等结构。
- 插入顺序与输入顺序一致。
- 插入操作需要维护尾指针 r
适中
头插法逆序存储 数据- 适用于栈、回溯等结构。
- 输入数据被倒序存储。
- 插入操作比尾插法简单,始终修改 L->next
更简单

🔹 总结

  1. 尾插法:适合 顺序存储,需要维护 r 指针,但顺序符合直觉。
  2. 头插法:适合 逆序存储,插入操作更简单,但最终数据顺序颠倒。
  3. 二者的选择 取决于数据使用的需求,如:
    • 队列(FIFO) 适合尾插法
    • 栈(LIFO) 适合头插法

如果你是初学者,建议多尝试不同方法,以便深入理解链表的操作方式! 🎯

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2322535.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入解析 Java 类加载机制及双亲委派模型

&#x1f50d; Java的类加载机制是确保应用程序正确运行的基础&#xff0c;特别是双亲委派模型&#xff0c;它通过父类加载器逐层加载类&#xff0c;避免冲突和重复加载。但在某些特殊场景下&#xff0c;破坏双亲委派模型会带来意想不到的效果。本文将深入解析Java类加载机制、…

MySQL数据库精研之旅第四期:解锁库操作高阶技能

专栏&#xff1a;MySQL数据库成长记 个人主页&#xff1a;手握风云 目录 一、查看所有表 1.1. 语法 二、创建表 2.1. 语法 2.2. 示例 2.3. 表在磁盘上对应的⽂件 三、查看表结构 3.1. 语法 3.2. 示例 四、修改表 4.1. 语法 4.2. 示例 五、删除表 5.1. 语法 5.2.…

【DevOps】DevOps and CI/CD Pipelines

DevOps 是一种将开发与运维实践相结合的模式&#xff0c;旨在缩短软件开发周期并交付高质量软件。 DevOps 是什么&#xff1f; 开发团队与运维团队之间的协作 • 持续集成与持续交付&#xff08;CI/CD&#xff09; • 流程自动化 • 基础设施即代码&#xff08;IaC&#xff09;…

VS自定义静态库并在其他项目中使用

1、VS创建一个空项目或者静态库项目 2、右键项目 属性 修改生成文件类型 3、生成解决方案 4、复制.h文件和.lib文件作为静态库 5、创建一个新项目 测试使用新生成的静态库 在新项目UseStaticLib中加一个新文件夹lib&#xff0c;lib中放入上面的.h和.lib文件。 6、vs中右…

力扣32.最长有效括号(栈)

32. 最长有效括号 - 力扣&#xff08;LeetCode&#xff09; 代码区&#xff1a; #include<stack> #include<string> /*最长有效*/ class Solution { public:int longestValidParentheses(string s) {stack<int> st;int ans0;int ns.length();st.push(-1);fo…

vue3 项目中预览 word(.docx)文档方法

vue3 项目中预览 word&#xff08;.docx&#xff09;文档方法 通过 vue-office/docx 插件预览 docx 文档通过 vue-office/excel 插件预览 excel 文档通过 vue-office/pdf 插件预览 pdf 文档 安装插件 npm install vue-office/docx vue-demi示例代码 <template><Vu…

DHCP(Dynamic Host Configuration Protocol)原理深度解析

目录 一、DHCP 核心功能 二、DHCP 工作流程&#xff08;四阶段&#xff09; 三、关键技术机制 1. 中继代理&#xff08;Relay Agent&#xff09; 2. Option 82&#xff08;中继信息选项&#xff09; 3. 租期管理 4. 冲突检测 四、DHCP 与网络架构交互 1. MLAG 环境 2.…

创建login.api.js步骤和方法

依次创建 login.api.js、home.api.js...... login.api.js、home.api.js 差不多 导入到 main.js main.js 项目中使用

基于springboot二手交易平台(源码+lw+部署文档+讲解),源码可白嫖!

摘要 人类现已迈入二十一世纪&#xff0c;科学技术日新月异&#xff0c;经济、资讯等各方面都有了非常大的进步&#xff0c;尤其是资讯与网络技术的飞速发展&#xff0c;对政治、经济、军事、文化等各方面都有了极大的影响。 利用电脑网络的这些便利&#xff0c;发展一套二手交…

帕金森患者的生活重塑:从 “嘴” 开启康复之旅

当提到帕金森病&#xff0c;许多人会联想到震颤、僵硬和行动迟缓等症状。这种神经系统退行性疾病&#xff0c;给患者的生活带来了巨大的挑战。然而&#xff0c;你可知道&#xff0c;帕金森患者恢复正常生活&#xff0c;可以从 “嘴” 开始管理&#xff1f; 帕金森病在全球影响着…

JVM 为什么不使用引用计数算法?——深入解析 GC 策略

在 Java 中&#xff0c;垃圾回收&#xff08;Garbage Collection, GC&#xff09;是一个至关重要的功能&#xff0c;它能够自动管理内存&#xff0c;回收不再使用的对象&#xff0c;从而防止内存泄漏。然而&#xff0c;在垃圾回收的实现上&#xff0c;JVM 并未采用引用计数算法…

【HarmonyOS NEXT】EventHub和Emitter的使用场景与区别

一、EventHub是什么&#xff1f; 移动应用开发的同学应该比较了解EventHub&#xff0c;类似于EventBus。标准的事件广播通知&#xff0c;订阅&#xff0c;取消订阅的处理。EventHub模块提供了事件中心&#xff0c;提供订阅、取消订阅、触发事件的能力。 类似的框架工具有很多…

01-系统编程

一、程序和进程的区别&#xff1a; window系统&#xff1a; 1、程序存储在硬盘中&#xff0c;文件格式为.exe后缀&#xff0c;静态的 2、进程运行在内存中&#xff0c;动态的 Linux系统 1、程序存储在硬盘中&#xff0c;文件格式为.ELF&#xff08;可执行的链接文件&#…

Linux编译器gcc/g++使用完全指南:从编译原理到动静态链接

一、gcc/g基础认知 在Linux开发环境中&#xff0c;gcc和g是我们最常用的编译器工具&#xff1a; gcc&#xff1a;GNU C Compiler&#xff0c;专门用于编译C语言程序g&#xff1a;GNU C Compiler&#xff0c;用于编译C程序&#xff08;也可编译C语言&#xff09; &#x1f4cc…

26考研|数学分析:定积分及应用

这一部分作为数学分析的灵魂&#xff0c;在数学分析的计算中&#xff0c;绝大部分的问题都可以转换成定积分的计算问题&#xff0c;所以在这部分的学习中&#xff0c;一定要注意提升计算能力&#xff0c;除此之外&#xff0c;由积分引出的相关积分不等式也是分析的重点和难点&a…

扩展卡尔曼滤波

1.非线性系统的线性化 标准卡尔曼滤波 适用于线性化系统&#xff0c;扩展卡尔曼滤波 则扩展到了非线性系统&#xff0c;核心原理就是将非线性系统线性化&#xff0c;主要用的的知识点是 泰勒展开&#xff08;我另外一篇文章的链接&#xff09;&#xff0c;如下是泰勒展开的公式…

4.Matplotlib:基础绘图

一 直方图 1.如何构建直方图 将值的范围分段&#xff0c;将整个值的范围分成一系列间隔&#xff0c;然后计算每个间隔中有多少值。 2.直方图的适用场景 一般用横轴表示数据类型&#xff0c;纵轴表示分布情况。 直方图可以用于识别数据的分布模式和异常值&#xff0c;以及观察数…

VSCode 市场发现恶意扩展正在传播勒索软件!

在VSCode 市场中发现了两个隐藏着勒索软件的恶意扩展。其中一个于去年 10 月出现在微软商店&#xff0c;但很长时间没有引起注意。 这些是扩展ahban.shiba 和 ahban.cychelloworld&#xff0c;目前已从商店中删除。 此外&#xff0c;ahban.cychelloworld 扩展于 2024 年 10 月…

工作流引擎Flowable介绍及SpringBoot整合使用实例

Flowable简介 Flowable 是一个轻量级的业务流程管理&#xff08;BPM&#xff09;和工作流引擎&#xff0c;基于 Activiti 项目发展而来&#xff0c;专注于提供高性能、可扩展的工作流解决方案。它主要用于企业级应用中的流程自动化、任务管理和审批流等场景。 Flowable 的核心…

K8s证书--运维之最佳选择(K8s Certificate - the best Choice for Operation and Maintenance)

K8s证书--运维之最佳选择 No -Number- 01 一个月速通CKA 为了速通CKA&#xff0c;主要办了两件事情 1. 在官方的Killercoda上&#xff0c;练习CKA的题目。把命令敲熟悉。 // https://killercoda.com/killer-shell-ckad 2. 使用K3s在多台虚拟机上快速搭建了K8s集群&…