C语言:链表

链表

  • 介绍
    • 单向链表
    • 节点结构
    • 创建节点
    • 插入节点
    • 删除节点
    • 遍历链表
    • 尾部插入
    • 查找节点
    • 链表反转
    • 示例程序
      • 程序1
      • 程序2

介绍

链表是一种常见的数据结构,用于存储一系列线性数据。与数组不同,链表中的元素在内存中不必是连续存放的,而是通过指针将每个元素(节点)链接在一起。链表有很多种类型,例如单向链表、双向链表和循环链表。这里我们主要介绍单向链表。

单向链表

单向链表由一系列节点组成,每个节点包含两个部分:

  1. 数据部分:存储节点的实际内容。
  2. 指针部分:存储指向下一个节点的指针。

节点结构

在 C 语言中,我们可以通过定义一个结构体来表示链表的节点:

struct Node {int data;          // 数据部分struct Node* next; // 指针部分
};

创建节点

可以通过动态内存分配函数 malloc 来创建新节点:

#include <stdio.h>
#include <stdlib.h>// 定义节点结构
struct Node {int data;struct Node* next;
};// 创建新节点
struct Node* createNode(int data) {struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));if (!newNode) {printf("内存分配失败\n");exit(1);}newNode->data = data;newNode->next = NULL;return newNode;
}

插入节点

我们可以在链表的头部或尾部插入节点。以头部插入为例:

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

删除节点

删除链表中的节点也很常见。假设我们要删除值为 key 的节点:

void deleteNode(struct Node** head, int key) {struct Node* temp = *head;struct Node* prev = NULL;// 如果头节点本身就是要删除的节点if (temp != NULL && temp->data == key) {*head = temp->next;free(temp); // 释放内存return;}// 搜索要删除的节点while (temp != NULL && temp->data != key) {prev = temp;temp = temp->next;}// 如果没找到要删除的节点if (temp == NULL) return;// 断开链接并释放内存prev->next = temp->next;free(temp);
}

遍历链表

遍历链表可以通过循环来实现:

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

尾部插入

尾部插入与头部插入类似,我们需要找到链表的最后一个节点,然后将新节点添加到末尾。

// 尾部插入
void insertAtTail(struct Node** head, int data) {struct Node* newNode = createNode(data);if (*head == NULL) {*head = newNode;return;}struct Node* temp = *head;while (temp->next != NULL) {temp = temp->next;}temp->next = newNode;
}

查找节点

查找链表中的某个节点,返回其位置或者指针:

struct Node* searchNode(struct Node* head, int key) {struct Node* current = head;while (current != NULL) {if (current->data == key) {return current;}current = current->next;}return NULL; // 未找到
}

链表反转

反转链表是一个经典的问题,可以通过迭代的方式实现:

void reverseList(struct Node** head) {struct Node* prev = NULL;struct Node* current = *head;struct Node* next = NULL;while (current != NULL) {next = current->next; // 暂存下一个节点current->next = prev; // 反转当前节点的指针prev = current;       // 移动 prev 指针current = next;       // 移动 current 指针}*head = prev;
}

示例程序

程序1

#include <stdio.h>
#include <stdlib.h>struct Node {int data;struct Node* next;
};struct Node* createNode(int data) {struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));if (!newNode) {printf("内存分配失败\n");exit(1);}newNode->data = data;newNode->next = NULL;return newNode;
}void insertAtHead(struct Node** head, int data) {struct Node* newNode = createNode(data);newNode->next = *head;*head = newNode;
}void deleteNode(struct Node** head, int key) {struct Node* temp = *head;struct Node* prev = NULL;if (temp != NULL && temp->data == key) {*head = temp->next;free(temp);return;}while (temp != NULL && temp->data != key) {prev = temp;temp = temp->next;}if (temp == NULL) return;prev->next = temp->next;free(temp);
}void printList(struct Node* head) {struct Node* current = head;while (current != NULL) {printf("%d -> ", current->data);current = current->next;}printf("NULL\n");
}int main() {struct Node* head = NULL;insertAtHead(&head, 1);insertAtHead(&head, 2);insertAtHead(&head, 3);printf("Created Linked List: ");printList(head);deleteNode(&head, 2);printf("Linked List after deletion of 2: ");printList(head);return 0;
}

输出结果:
在这里插入图片描述

程序2

#include <stdio.h>
#include <stdlib.h>// 定义节点结构
struct Node {int data;struct Node* next;
};// 创建新节点
struct Node* createNode(int data) {struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));if (!newNode) {printf("内存分配失败\n");exit(1);}newNode->data = data;newNode->next = NULL;return newNode;
}// 头部插入
void insertAtHead(struct Node** head, int data) {struct Node* newNode = createNode(data);newNode->next = *head;*head = newNode;
}// 尾部插入
void insertAtTail(struct Node** head, int data) {struct Node* newNode = createNode(data);if (*head == NULL) {*head = newNode;return;}struct Node* temp = *head;while (temp->next != NULL) {temp = temp->next;}temp->next = newNode;
}// 删除节点
void deleteNode(struct Node** head, int key) {struct Node* temp = *head;struct Node* prev = NULL;if (temp != NULL && temp->data == key) {*head = temp->next;free(temp);return;}while (temp != NULL && temp->data != key) {prev = temp;temp = temp->next;}if (temp == NULL) return;prev->next = temp->next;free(temp);
}// 查找节点
struct Node* searchNode(struct Node* head, int key) {struct Node* current = head;while (current != NULL) {if (current->data == key) {return current;}current = current->next;}return NULL;
}// 反转链表
void reverseList(struct Node** head) {struct Node* prev = NULL;struct Node* current = *head;struct Node* next = NULL;while (current != NULL) {next = current->next;current->next = prev;prev = current;current = next;}*head = prev;
}// 打印链表
void printList(struct Node* head) {struct Node* current = head;while (current != NULL) {printf("%d -> ", current->data);current = current->next;}printf("NULL\n");
}int main() {struct Node* head = NULL;insertAtHead(&head, 1);insertAtHead(&head, 2);insertAtHead(&head, 3);printf("初始链表: ");printList(head);// 测试尾部插入insertAtTail(&head, 4);printf("尾部插入 4 后的链表: ");printList(head);// 测试删除节点deleteNode(&head, 2);printf("删除节点 2 后的链表: ");printList(head);// 测试查找节点struct Node* foundNode = searchNode(head, 3);if (foundNode) {printf("找到节点 3\n");} else {printf("未找到节点 3\n");}// 测试反转链表reverseList(&head);printf("反转后的链表: ");printList(head);return 0;
}

输出结果:
在这里插入图片描述

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

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

相关文章

Jackson的使用

一引入依赖 <!--Jackson是spring-boot-starter-json的一个依赖&#xff08;spring-boot-starter-web中包含spring-boot-starter-json&#xff09;。也就是说&#xff0c;当项目中引入spring-boot-starter-web后会自动引入spring-boot-starter-json --> <dependency&g…

4款好用的文本扩展器!!提高工作效率!【送源码】

今天的文章中为大家带来几款好用的文本扩展器&#xff0c;帮助大家提供工作效率&#xff0c;减少重复劳动&#xff5e; Beeftext Beeftext 是一个文本扩展工具&#xff0c;可以帮助用户快速输入短语、段落或者常用的文本片段。它允许你创建自定义的缩写和对应的文本替换&…

使用tkinter创建带有图标的菜单栏

使用tkinter创建带有图标的菜单栏 效果代码代码解析创建主窗口加载图标创建菜单栏添加文件菜单添加带图标的菜单项 Tkinter 的默认菜单外观较为简单&#xff0c;可以通过自定义和添加图标&#xff0c;让菜单显示更好看。 效果 代码 import tkinter as tk from tkinter import …

课时154:项目发布_手工发布_手工发布

1.2.3 手工发布 学习目标 这一节&#xff0c;我们从 基础知识、简单实践、小结 三个方面来学习 基础知识 简介 为了合理的演示生产环境的项目代码发布&#xff0c;同时又兼顾实际实验环境的资源&#xff0c;我们这里将 B主机和C主机 用一台VM主机来实现&#xff0c;A主机单…

Arduino入门2——常用函数及用法

Arduino入门2——串口驱动函数及用法 IO串口 上期&#xff0c;我们简单的认识了一下Arduino&#xff0c;浅浅的入了个门&#xff0c;这一期我们介绍以下Arduino串口常用的函数及用法 IO 常用串口库函数如下&#xff1a; 函数名用法及解析pinMode()用于IO口初始化digitalWrite…

2024050802-重学 Java 设计模式《实战模板模式》

重学 Java 设计模式&#xff1a;实战模版模式「模拟爬虫各类电商商品&#xff0c;生成营销推广海报场景」 一、前言 黎明前的坚守&#xff0c;的住吗&#xff1f; 有人举过这样一个例子&#xff0c;先给你张北大的录取通知书&#xff0c;但要求你每天5点起床&#xff0c;12点…

Proteus 新建工程

Proteus 新建工程 新建简单工程 首先在File工具栏中点击New Project&#xff0c;弹出新建工程向导程序(New Proteus Wizard) 填写工程名称与存储路径&#xff0c;选择New Proteus并点击Next进行下一步设置 我们不需要生成PCB文件&#xff0c;一路默认&#xff0c;点击Next即…

实战计算机网络02——物理层

实战计算机网络02——物理层 1、物理层实现的功能2、数据与信号2.1 数据通信模型2.2 通信领域常用术语2.3 模拟信号和数字信号 3、信道和调制3.1 信道3.2 单工通信、半双工通信、全双工通信3.3 调制3.4 奈式准则3.5 香农定律 4、传输媒体4.1 导向传输媒体4.2 非导向传输媒体 5、…

高级人工智能复习 题目整理 中科大

题目整理 填空 1.准确性&#xff0c;复杂性&#xff0c;验证集 2. 3 2 n 3^{2^n} 32n 3 C 2 n m 3^{C^m_{2n}} 3C2nm​ 3 m 3^m 3m n 1 n1 n1 3. 状态 从状态s采取行动a后继续采用策略 π \pi π的收益 环境 4. 语法 语义 推理规则 5. 参与者&#xff0c;策略集&#xff…

Elasticsearch 8.1官网文档梳理 - 十一、Ingest pipelines(管道)

Ingest pipelines 管道&#xff08;Ingest pipelines&#xff09;可让让数据在写入前进行常见的转换。例如可以利用管道删除文档&#xff08;doc&#xff09;的字段、或从文本中提取数据、丰富文档&#xff08;doc&#xff09;的字段等其他操作。 管道&#xff08;Ingest pip…

VirtualBox、Centos7下安装docker后pull镜像问题、ftp上传文件问题

Docker安装篇(CentOS7安装)_docker 安装 centos7-CSDN博客 首先&#xff0c;安装docker可以根据这篇文章进行安装&#xff0c;安装完之后&#xff0c;我们就需要去通过docker拉取相关的服务镜像&#xff0c;然后安装相应的服务容器&#xff0c;比如我们通过docker来安装mysql,…

vue 使用 ztree 超大量数据,前端树形结构展示

ztree 是一个很经典的基于jquey开发的树结构编辑展示UI组件库。 创建一个文件 ztree.vue&#xff0c;代码如下&#xff1a; <template><div><div class"ztree vue-giant-tree" :id"ztreeId"></div><div class"treeBox&q…

Termius安装docker

安装Termius 直接上官网 新建主机 更新一下yum 更新完成 安装docker的包 直接用命令安装 设置一下开机启动&#xff0c;可以查看docker的版本

Ui学习--UITableView

UI学习 UITableView基础UITableView协议UITableView高级协议与单元格总结 UITableView基础 UITableView作为iOS中的一个控件&#xff0c;用于以表格形式展示数据。例如通讯录好友&#xff0c;朋友圈信息等&#xff0c;都是UITableView的实际运用场景。 首先我们先要加入两个协…

K210使用雷龙NAND完成火灾检测

NAND 文章目录 NAND前言一、NAND是什么&#xff1f;二、来看一看NAND三、部署火灾检测 前言 前几天收到了雷龙NAND的芯片&#xff0c;一共两个芯片和一个转接板&#xff0c;我之前也没有使用过这款芯片&#xff0c;比较好奇&#xff0c;体验了一下&#xff0c;个人认为&#x…

嵌入式微处理器重点学习(三)

堆栈操作 R1=0x005 R3=0x004 SP=0x80014 STMFD sp!, {r1, r3} 指令STMFD sp!, {r1, r3}是一条ARM架构中的存储多个寄存器到内存的指令,这里用于将r1和r3寄存器的内容存储到栈上。STMFD(Store Multiple Full Descending)是一种全递减模式的多寄存器存储指令,它会先将栈指针…

three.js 基础01

1.场景创建 Scene() 2.常用形状集几何体「Geometry」[可设置长宽高等内容,如:new THREE.BoxGeometry(...)] 长方体 BoxGeometry圆柱体CylinderGeometry 球体SphereGeometry圆锥体ConeGeometry矩形平面 PlaneGeometry 圆面体CircleGeometry 3.常用材质「Materi…

linux 部署瑞数6实战(维普,药监局)sign第二部分

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx …

C/C++李峋同款跳动的爱心代码

一、写在前面 在编程的世界里&#xff0c;代码不仅仅是冷冰冰的命令&#xff0c;它也可以成为表达情感、传递浪漫的工具。今天&#xff0c;就让小编带着大家用C语言打造出李峋同款跳动的爱心吧&#xff01; 首先&#xff0c;我们需要知道C作为一种高级编程语言&#xff0c;拥…

宠物健康顾问系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;顾问管理&#xff0c;用户管理&#xff0c;健康知识管理&#xff0c;管理员管理&#xff0c;论坛管理&#xff0c;公告管理 顾问账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;顾…