如何在 C 语言中实现链表?

news2024/9/30 17:32:15

C语言

🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
📙C 语言百万年薪修炼课程 通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。

分割线

文章目录

  • C 语言中链表的实现
  • 一、链表的基本概念
  • 二、单向链表的节点结构
  • 三、创建链表节点
  • 四、向链表中插入节点
    • 4.1 头插法
    • 4.2 尾插法
  • 五、遍历链表
  • 六、删除链表节点
    • 6.1 删除头节点
    • 6.2 删除指定节点
  • 七、查找链表节点
  • 八、完整的示例代码

分割线


C 语言中链表的实现

链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。在 C 语言中实现链表可以让我们更灵活地管理数据。

一、链表的基本概念

链表中的节点通常由两部分组成:数据部分和指针部分。数据部分用于存储实际的数据,而指针部分用于指向下一个节点。

链表分为单向链表、双向链表和循环链表等类型。在本教程中,我们将重点介绍单向链表。

二、单向链表的节点结构

在 C 语言中,我们可以使用结构体来定义链表节点的结构:

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

在上述代码中,data 字段用于存储节点的数据,next 指针用于指向下一个节点。

三、创建链表节点

要创建一个新的链表节点,可以使用以下函数:

Node* createNode(int data) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL) {
        printf("内存分配失败\n");
        return NULL;
    }

    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

这个函数首先使用 malloc 函数在内存中分配一个新节点所需的空间。如果内存分配失败,返回 NULL 。然后,将传入的数据赋值给节点的数据字段,并将 next 指针初始化为 NULL

四、向链表中插入节点

4.1 头插法

头插法是将新节点插入到链表的头部。

void insertAtHead(Node** head, int data) {
    Node* newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}

在这个函数中,首先创建一个新节点,然后让新节点的 next 指针指向当前的头节点,最后更新头节点指针,使其指向新节点。

4.2 尾插法

尾插法是将新节点插入到链表的尾部。

void insertAtTail(Node** head, int data) {
    Node* newNode = createNode(data);
    if (*head == NULL) {
        *head = newNode;
        return;
    }

    Node* curr = *head;
    while (curr->next!= NULL) {
        curr = curr->next;
    }
    curr->next = newNode;
}

这个函数首先创建一个新节点。如果链表为空,直接将新节点作为头节点。否则,遍历链表找到尾节点,然后将新节点连接到尾节点的后面。

五、遍历链表

遍历链表用于访问链表中的每个节点并处理其数据。

void traverseList(Node* head) {
    Node* curr = head;
    while (curr!= NULL) {
        printf("%d ", curr->data);
        curr = curr->next;
    }
    printf("\n");
}

在这个函数中,从链表的头节点开始,依次访问每个节点并打印其数据,直到遇到 NULL 指针,表示链表结束。

六、删除链表节点

6.1 删除头节点

void deleteHead(Node** head) {
    if (*head == NULL) {
        printf("链表为空,无法删除头节点\n");
        return;
    }

    Node* temp = *head;
    *head = (*head)->next;
    free(temp);
}

这个函数首先检查链表是否为空。如果不为空,保存头节点的指针,更新头节点指针指向下一个节点,然后释放原来头节点所占用的内存。

6.2 删除指定节点

void deleteNode(Node** head, int data) {
    Node* curr = *head;
    Node* prev = NULL;

    if (curr!= NULL && curr->data == data) {
        *head = curr->next;
        free(curr);
        return;
    }

    while (curr!= NULL && curr->data!= data) {
        prev = curr;
        curr = curr->next;
    }

    if (curr == NULL) {
        printf("未找到要删除的节点\n");
        return;
    }

    prev->next = curr->next;
    free(curr);
}

这个函数用于删除指定数据的节点。首先处理头节点,如果头节点的数据就是要删除的数据,更新头节点指针并释放头节点内存。然后遍历链表,找到要删除的节点,更新前一个节点的 next 指针,使其跳过要删除的节点,最后释放要删除节点的内存。

七、查找链表节点

Node* searchNode(Node* head, int data) {
    Node* curr = head;
    while (curr!= NULL) {
        if (curr->data == data) {
            return curr;
        }
        curr = curr->next;
    }
    return NULL;
}

这个函数从链表的头节点开始遍历,直到找到数据匹配的节点并返回其指针,如果未找到则返回 NULL

八、完整的示例代码

#include <stdio.h>
#include <stdlib.h>

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

// 创建节点
Node* createNode(int data) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL) {
        printf("内存分配失败\n");
        return NULL;
    }

    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

// 头插法
void insertAtHead(Node** head, int data) {
    Node* newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}

// 尾插法
void insertAtTail(Node** head, int data) {
    Node* newNode = createNode(data);
    if (*head == NULL) {
        *head = newNode;
        return;
    }

    Node* curr = *head;
    while (curr->next!= NULL) {
        curr = curr->next;
    }
    curr->next = newNode;
}

// 遍历链表
void traverseList(Node* head) {
    Node* curr = head;
    while (curr!= NULL) {
        printf("%d ", curr->data);
        curr = curr->next;
    }
    printf("\n");
}

// 删除头节点
void deleteHead(Node** head) {
    if (*head == NULL) {
        printf("链表为空,无法删除头节点\n");
        return;
    }

    Node* temp = *head;
    *head = (*head)->next;
    free(temp);
}

// 删除指定节点
void deleteNode(Node** head, int data) {
    Node* curr = *head;
    Node* prev = NULL;

    if (curr!= NULL && curr->data == data) {
        *head = curr->next;
        free(curr);
        return;
    }

    while (curr!= NULL && curr->data!= data) {
        prev = curr;
        curr = curr->next;
    }

    if (curr == NULL) {
        printf("未找到要删除的节点\n");
        return;
    }

    prev->next = curr->next;
    free(curr);
}

// 查找节点
Node* searchNode(Node* head, int data) {
    Node* curr = head;
    while (curr!= NULL) {
        if (curr->data == data) {
            return curr;
        }
        curr = curr->next;
    }
    return NULL;
}

int main() {
    Node* head = NULL;

    insertAtTail(&head, 10);
    insertAtTail(&head, 20);
    insertAtTail(&head, 30);
    insertAtHead(&head, 5);

    printf("链表元素: ");
    traverseList(head);

    Node* foundNode = searchNode(head, 20);
    if (foundNode!= NULL) {
        printf("找到节点: %d\n", foundNode->data);
    } else {
        printf("未找到节点\n");
    }

    deleteNode(&head, 20);

    printf("删除节点 20 后链表元素: ");
    traverseList(head);

    deleteHead(&head);

    printf("删除头节点后链表元素: ");
    traverseList(head);

    return 0;
}

在上述示例中,我们首先创建了一个空链表,然后通过头插法和尾插法向链表中插入节点。接着遍历链表,查找特定节点,删除指定节点和头节点,并再次遍历链表以验证操作结果。

希望这个详细的解释和示例能帮助您理解如何在 C 语言中实现链表。链表是一种基础但重要的数据结构,掌握它对于进一步学习更复杂的数据结构和算法非常有帮助。


分割线

🎉相关推荐

  • 📙C 语言百万年薪修炼课程 通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。
  • 🍅博客首页-关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
  • 📙CSDN专栏-C语言修炼
  • 📙技术社区-墨松科技

分割线



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

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

相关文章

【安全设备】Web应用防火墙

一、什么是Web应用防火墙 Web应用程序防火墙&#xff08;Web Application Firewall&#xff09;的缩写是WAF&#xff0c;用于保护Web应用程序免受各种恶意攻击和漏洞利用。WAF通过监控和过滤进出Web应用程序的HTTP/HTTPS流量来工作。它位于Web应用程序和用户之间&#xff0c;分…

【android 9】【input】【10.发送按键事件4——View的分发流程】

系列文章目录 可跳转到下面链接查看下表所有内容https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5501 目录…

LabVIEW平台从离散光子到连续光子的光子计数技术

光子计数技术用于将输入光子数转换为离散脉冲。常见的光子计数器假设光子是离散到达的&#xff0c;记录到来的每一个光子。但是&#xff0c;当两个或多个光子同时到达时&#xff0c;计数器会将其记录为单个脉冲&#xff0c;从而只计数一次。当连续光子到达时&#xff0c;离散光…

基于YOLOv8深度学习的CT扫描图像肾结石智能检测系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战、目标检测

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

使用八股搭建神经网络

神经网络搭建八股 使用tf.keras 六步法搭建模型 1.import 2.train, test 指定输入特征/标签 3.model tf.keras.model.Sequential 在Squential,搭建神经网络 4.model.compile 配置训练方法&#xff0c;选择哪种优化器、损失函数、评测指标 5.model.fit 执行训练过程&a…

移动互联安全

什么是移动互联 从狭义的角度来说&#xff0c;移动互联网是一个以宽带IP为技术核心&#xff0c;可同时提供语音、传真、图像、多媒体等高品质电信服务的新一代开放的电信基础网络。 从广义的角度来说&#xff0c;移动互联网是指将互联网提供的技术、平台、应用以及商业模式&…

拖动事件 dragEnterEvent、放置事件 dropEvent、resize事件resizeEvent的实现

拖动事件 dragEnterEvent、放置事件 dropEvent、resize事件resizeEvent的实现 拖动事件 dragEnterEvent 放置事件 dropEvent resize事件resizeEvent DragFileExample.h #ifndef DRAGFILEEXAMPLE_H #define DRAGFILEEXAMPLE_H#include <QWidget> #include <QDragEnterE…

【Python大语言模型系列】Windows环境下部署Chatglm2-6B-int4大语言模型(完整教程)

这是我的第319篇原创文章。 一、引言 电脑配置 &#xff1a; python版本要求&#xff1a;3.8torch版本&#xff1a;2.0.1cuda&#xff1a;11.7windows系统&#xff1a;Windows 10 显卡&#xff1a;6G以上GPU 二、实现过程 2.1 下载chatglm2-6b的项目源码 上chatglm2-6B的官…

[PM]流程与结构设计

流程图 流程就是为了达到特定目标, 进行的一系列有逻辑性的操作步骤, 由两个及已上的步骤, 完成一个完整的行为过程, 即可称为流程, 流程图就是对这个过程的图形化展示 分类 业务流程图 概念: 描述业务流程的一种图, 通过特定符号和连线表示具体某个业务的处理步骤和过程作…

推荐一个比 Jenkins 使用更简单的项目构建和部署工具

最近发现了一个比 Jenkins 使用更简单的项目构建和部署工具&#xff0c;完全可以满足个人以及一些小企业的需求&#xff0c;分享一下。 项目介绍 Jpom 是一款 Java 开发的简单轻量的低侵入式在线构建、自动部署、日常运维、项目监控软件。 日常开发中&#xff0c;Jpom 可以解…

来聊聊Redis持久化AOF管道通信的设计

写在文章开头 最近遇到很多烦心事&#xff0c;希望通过技术来得以放松&#xff0c;今天这篇文章笔者希望会通过源码的方式分析一下AOF如何通过Linux父子进程管道通信的方式保证进行AOF异步重写时还能实时接收用户处理的指令生成的AOF字符串&#xff0c;从而保证尽可能的可靠性…

保密U盘仍然存在数据安全危机?该怎么用才能规避?

保密U盘以前主要用于国家涉密单位或部门&#xff0c;但随着人们对于信息安全的重视越来越高&#xff0c;在民用企事业单位以及个人用户方面也应用得日益广泛。 使用保密U盘在安全性上比普通U盘具有优势&#xff0c;但却仍然存在安全危机&#xff0c;具体为&#xff1a; 病毒和…

万字学习——DCU编程实战

参考资料 2.1 DCU软件栈&#xff08;DCU ToolKit, DTK&#xff09; DCU 开发与使用文档 (hpccube.com) DCU软件栈 DCU的软件栈—DCU Toolkit&#xff08;DTK&#xff09; HIP&#xff08;Heterogeneous-Compute Interface for Portability&#xff09;是AMD公司在2016年提出…

基于jeecgboot-vue3的Flowable流程-集成仿钉钉流程(五)仿钉钉流程的json数据保存与显示

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、需要做一个界面保存与显示仿钉钉的流程&#xff0c;先建一个表&#xff0c;用online建 2、通过上面生成代码&#xff0c;放入到相应的前后端工程里 3、修改前端仿钉钉流程的设计功能&a…

Java版Flink使用指南——分流导出

大纲 新建工程编码Pom.xml自定义无界流分流 测试工程代码 在之前的案例中&#xff0c;我们一直使用的是单个Sink来做数据的输出。实际上&#xff0c;Flink是支持多个输出流的。本文我们就来讲解如何在Flink数据输出时做分流处理。 我们将基于《Java版Flink使用指南——自定义无…

java如何实现一个死锁 ?

死锁(Deadlock)是指在并发系统中,两个或多个线程(或进程)因争夺资源而互相等待,导致它们都无法继续执行的一种状态。 一、简易代码 public class DeadlockExample {private static final Object lock1 = new Object();private

Python面试宝典第9题:买卖股票

题目 给定一个整型数组&#xff0c;它的第i个元素是一支给定股票第i天的价格。如果最多只允许完成一笔交易&#xff08;即买入和卖出一支股票一次&#xff09;&#xff0c;设计一个算法来计算你所能获取的最大利润。注意&#xff1a;你不能在买入股票前卖出股票。 示例 1&#…

前端面试题36(js栈和堆)

在JavaScript中&#xff0c;内存管理是自动进行的&#xff0c;主要通过栈(stack)和堆(heap)两种方式来分配和管理内存。理解这两者对于深入学习JavaScript以及优化代码性能非常关键。 栈 (Stack) 栈是一种后进先出&#xff08;Last In, First Out, LIFO&#xff09;的数据结构…

U盘启动快捷键查询

电脑开机一般默认自身硬盘启动系统&#xff0c;如需要U盘重装系统&#xff0c;开机时一直按对应机型的U盘启动快捷键&#xff0c;选择对应USB设备即可U盘启动。 一、品牌台式 二、品牌笔记本 三、组装电脑

Go语言---Json

JSON (JavaScript Object Notation)是一种比XML 更轻量级的数据交换格式&#xff0c;在易于人们阅读和编写的同时&#xff0c;也易于程序解析和生成。尽管JSON是 JavaScript的一个子集&#xff0c;但 JSON采用完全独立于编程语言的文本格式&#xff0c;且表现为键/值对集合的文…