重生之我在异世界学编程之C语言:深入结构体篇(下)

news2025/2/24 4:21:06

大家好,这里是小编的博客频道
小编的博客:就爱学编程

很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!

本文目录

  • 引言
  • 结构体的自引用实现链表
      • 一、链表的基本概念
        • 1. 单向链表
        • 2. 双向链表
        • 3. 循环链表
      • 二、使用结构体定义链表节点
      • 三、创建链表的基本操作
        • 1. 创建新节点
        • 2. 在链表头部插入节点
        • 3. 在链表尾部插入节点
        • 4. 删除节点
        • 5. 打印链表
      • 四、完整示例代码
  • 快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

引言

在C语言中,结构体(struct)是一种用户自定义的数据类型,它允许将多个不同类型的数据项组合成一个单一的类型。结构体是编程中组织相关数据的有效方式,尤其在处理复杂数据时显得尤为重要。以下是对C语言结构体进阶知识-——实现链表的介绍,一起来看看吧!!

在这里插入图片描述


那接下来就让我们开始遨游在知识的海洋!

结构体的自引用实现链表


一、链表的基本概念

链表是一种线性数据结构,但与数组不同的是,链表中的元素在内存中不必连续存储。链表由一系列的节点(Node)组成,每个节点包含两部分:一部分是存储数据的域(Data Field),另一部分是指向下一个节点的指针(Pointer Field)。根据指针的指向不同,链表可以分为单向链表、双向链表和循环链表等。

1. 单向链表

单向链表是最简单的链表形式,其中每个节点只包含一个指向下一个节点的指针。最后一个节点的指针为NULL,表示链表的结束。

2. 双向链表

双向链表中的每个节点除了包含指向下一个节点的指针外,还包含指向前一个节点的指针。这使得在链表中向前或向后遍历都成为可能。

3. 循环链表

循环链表的特点是最后一个节点的指针不是指向NULL,而是指向链表的第一个节点,从而形成一个环状结构。


二、使用结构体定义链表节点

在C语言中,可以使用结构体来定义链表节点。以下是一个单向链表节点的定义示例:

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

// 定义链表节点结构体
typedef struct Node {
    int data;           // 数据域
    struct Node* next;  // 指针域,指向下一个节点
} Node;

在这个例子中,Node结构体有两个成员:一个是整型变量data用于存储数据,另一个是指针next用于指向下一个Node类型的节点。


三、创建链表的基本操作

1. 创建新节点

要创建一个新的链表节点,需要动态分配内存并初始化其数据和指针。以下是创建新节点的函数示例:

// 创建新节点并返回其指针
Node* createNode(int data) {
    Node* newNode = (Node*)malloc(sizeof(Node)); // 动态分配内存
    if (!newNode) {
        printf("Memory allocation error
");
        exit(1);
    }
    newNode->data = data;                       // 初始化数据域
    newNode->next = NULL;                       // 初始化指针域为空
    return newNode;
}
2. 在链表头部插入节点

要在链表的头部插入一个新节点,只需更新新节点的next指针使其指向当前的头节点,然后更新头指针指向新节点。以下是该操作的函数示例:

// 在链表头部插入新节点
void insertAtHead(Node** head, int data) {
    Node* newNode = createNode(data); // 创建新节点
    newNode->next = *head;            // 新节点的next指向当前头节点
    *head = newNode;                  // 更新头指针指向新节点
}

注意这里使用了双重指针Node** head,以便能够修改头指针本身的值。

3. 在链表尾部插入节点

要在链表的尾部插入一个新节点,需要遍历到链表的末尾,然后将末尾节点的next指针指向新节点。以下是该操作的函数示例:

// 在链表尾部插入新节点
void insertAtTail(Node** head, int data) {
    Node* newNode = createNode(data); // 创建新节点
    if (*head == NULL) {              // 如果链表为空,则新节点成为头节点
        *head = newNode;
        return;
    }
    Node* temp = *head;               // 使用临时指针遍历链表
    while (temp->next != NULL) {      // 找到最后一个节点
        temp = temp->next;
    }
    temp->next = newNode;             // 将最后一个节点的next指向新节点
}
4. 删除节点

删除节点需要根据给定的值找到目标节点,并调整前一个节点的next指针使其跳过目标节点。以下是删除节点的函数示例:

// 根据值删除节点
void deleteNode(Node** head, int key) {
    Node* temp = *head;
    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); // 释放被删除节点的内存
}
5. 打印链表

为了验证链表的正确性,通常需要编写一个打印链表的函数:

// 打印链表中的所有节点
void printList(Node* head) {
    Node* temp = head;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("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) {
        printf("Memory allocation error
");
        exit(1);
    }
    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* temp = *head;
    while (temp->next != NULL) {
        temp = temp->next;
    }
    temp->next = newNode;
}

void deleteNode(Node** head, int key) {
    Node* temp = *head;
    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(Node* head) {
    Node* temp = head;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("NULL
");
}

int main() {
    Node* head = NULL;

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

    printf("Linked List: ");
    printList(head);

    deleteNode(&head, 20);
    printf("After deleting 20: ");
    printList(head);

    deleteNode(&head, 10);
    printf("After deleting 10: ");
    printList(head);

    return 0;
}
  • 通过上述步骤,我们了解了如何在C语言中使用结构体来实现链表,并掌握了基本的链表操作如创建节点、插入节点、删除节点以及打印链表的方法。这些基本操作是实现更复杂链表算法和数据结构

快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

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

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

相关文章

使用Redis Stream偶发空指针问题

问题描述&#xff1a;使用redission客户端封装的stream消息队列&#xff0c;在进行消息轮询时&#xff0c;偶发出现空指针问题。 [2024-11-13 09:59:20] [] [] [redis-stream-consumer-thread-1 ] [lambda$streamMessageListenerContainer$1] [ERROR] [c.r.c.r.s.config.Redi…

35页PDF | 元数据与数据血缘落地实施(限免下载)

一、前言 这份报告详细介绍了元数据与数据血缘的概念、重要性以及在企业数据中台中的应用。报告阐述了数据中台的核心价值在于整合和管理体系内的数据&#xff0c;以提升数据资产化能力并支持业务决策。报告还涵盖了元数据的分类&#xff08;技术元数据和业务元数据&#xff0…

方案精读:50页智慧园区数字化平台总体规划与建设方案PPT

本文介绍了智慧园区数字化平台总体规划与建设方案&#xff0c;包括智慧园区工业云平台、智慧办公平台、智能工厂、智慧能源管理、智慧政务管理等方面的建设内容。方案旨在通过技术手段加强园区内部沟通和管理能力&#xff0c;实现个性化营销、柔性化制造、高效智能协同的供应链…

深入浅出:Go语言标准库探索

深入浅出&#xff1a;Go语言标准库探索 引言 Go语言自发布以来&#xff0c;以其简洁的语法、高效的性能和强大的并发支持赢得了开发者的青睐。除了这些特性外&#xff0c;Go还拥有一个功能丰富且设计精良的标准库&#xff0c;几乎涵盖了现代应用程序开发所需的所有基本功能。…

python selenium(4+)+chromedriver最新版 定位爬取嵌套shadow-root(open)中内容

废话不多说&#xff0c;直接开始 本文以无界作为本文测试案例&#xff0c;抓取shadow-root&#xff08;open&#xff09;下的内容 shadow Dom in selenium&#xff1a; 首先先讲一下shadow Dom in selenium 版本的区别&#xff0c;链接指向这里 在Selenium 4版本 以及 chrom…

1207论文速读

1、SCN_GNN: A GNN-based fraud detection algorithm combining strong node and graph topology information 全文总结&#xff1a;本文介绍了一种基于图神经网络的欺诈检测算法——SCN_GNN。在欺诈检测中&#xff0c;由于欺诈者经常使用多种关系类型来掩盖其活动&#xff0c…

5.3_小程序渗透

小程序 行为工具小程序抓包全局代理&#xff0c;Proxifer小程序渗透小程序反编译Wxapkg 参数&#xff1a;scan 联网自动扫描&#xff0c;-r 指定 wx文件路径小程序逆向WeChatOpenDevTools 小程序抓包 工具步骤 全局代理 Burp中Proxy setings导出证书选择 Select file &a…

怎么实现邮件营销自动化?

邮件营销能够出色地帮助我们与客户建立良好关系。无论是新客户还是老客户&#xff0c;都可以通过邮件来达成较为良好的客户关系。然而&#xff0c;从消费者的角度来看&#xff0c;每个人都有自己独特的习惯和特点&#xff0c;没有人希望收到千篇一律、营销意味过重的邮件。因此…

使用ensp搭建内外互通,使用路由跨不同vlan通信。

1.网络拓扑图 2.规则 &#xff08;1&#xff09;允许 &#xff08;自己&#xff09;ping通内外网&#xff0c;内外网随便一个pc就可以. &#xff08;2&#xff09; 允许&#xff08;电信&#xff09;ping通内外网&#xff0c;内外网随便一个pc就可以 &#xff08;时间问题不做…

鸿蒙分享(一):添加模块,修改app名称图标

码仓库&#xff1a;https://gitee.com/linguanzhong/share_harmonyos 鸿蒙api:12 新建公共模块common 在entry的oh-package.json5添加dependencies&#xff0c;引入common模块 "dependencies": {"common": "file:../common" } 修改app名称&…

自定义指令,全局,局部,注册

让输入框自动获取焦点(每次刷新自动获取焦点&#xff09; <template><div><h3>自定义指令</h3><input ref"inp" type"text"></div> </template><script> export default {mounted(){this.$refs.inp.focus…

【C语言】C语言的变量和声明系统性讲解

声明和定义的概念 在C语言中&#xff0c;**声明&#xff08;Declaration&#xff09;和定义&#xff08;Definition&#xff09;**是两个重要的基础概念&#xff0c;它们都涉及到变量、函数、结构体等的使用&#xff0c;但功能和作用存在明显区别&#xff1a; 声明&#xff1a…

【优选算法篇】:滑动窗口算法--开启高效解题的“窗口”,透过例题看奥秘

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;c篇–CSDN博客 文章目录 一.滑动窗口算法二.例题1.长度最小的子数组2.无重复字符的最长字串…

调用大模型api 批量处理图像 保存到excel

最近需要调用大模型&#xff0c;并将结果保存到excel中&#xff0c;效果如下&#xff1a; 代码&#xff1a; import base64 from zhipuai import ZhipuAI import os import pandas as pd from openpyxl import Workbook from openpyxl.drawing.image import Image from io i…

CEEMDAN-CPO-VMD二次分解(CEEMDAN+冠豪猪优化算法CPO优化VMD)

CEEMDAN-CPO-VMD二次分解&#xff08;CEEMDAN冠豪猪优化算法CPO优化VMD&#xff09; 目录 CEEMDAN-CPO-VMD二次分解&#xff08;CEEMDAN冠豪猪优化算法CPO优化VMD&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 首先运用CEEMDAN对数据进行一次分解&#xff…

Bloom 效果

1、Bloom 效果是什么 Bloom效果&#xff08;中文也可以叫做高光溢出效果&#xff09;&#xff0c;是一种使画面中亮度较高的区域产生一种光晕或发光效果的图像处理技术&#xff0c;Bloom效果的主要目的是模拟现实世界中强光源在相机镜头或人眼中造成的散射和反射现象&#xff…

【ArkTS】列表组件的“下拉刷新”和“上拉加载”

系列文章目录 【ArkTS】关于ForEach的第三个参数键值 【ArkTS】“一篇带你读懂ForEach和LazyForEach” 【小白拓展】 【ArkTS】“一篇带你掌握TaskPool与Worker两种多线程并发方案” 【ArkTS】 一篇带你掌握“语音转文字技术” --内附详细代码 【ArkTS】技能提高–“用户授权”…

Otter数据同步原理

otter是阿里巴巴的开源的一款数据数据同步工具&#xff0c;它基于对数据库增量日志解析&#xff0c;准实时同步到本机房或者异地机房的mysql/oracle/mq等&#xff0c;是一个分布式数据同步系统。otter第一版本可追溯到04~05年&#xff0c;开发时间从2011年7月份一直持续到现在&…

【已解决】黑马点评项目中-实战篇11-状态登录刷新章节设置RefreshTokenInterceptor拦截器后登录异常的问题

黑马点评项目中-实战篇11-状态登录刷新章节设置RefreshTokenInterceptor拦截器后登录异常的问题 在 MvcConfig 文件中添加好RefreshTokenInterceptor拦截器 出现异常情况 按照验证码登录后&#xff0c;进入主页面&#xff0c;再点击“我的”&#xff0c;又跳入登录界面 原因…

AI - RAG中的状态化管理聊天记录

AI - RAG中的状态化管理聊天记录 大家好&#xff0c;今天我们来聊聊LangChain和LLM中一个重要的话题——状态化管理聊天记录。在使用大语言模型(LLM)的时候&#xff0c;聊天记录&#xff08;History&#xff09;和状态&#xff08;State&#xff09;管理是非常关键的。那我们先…