C语言链表详解及代码分析

C语言链表详解及代码分析

简介

链表是一种常见的数据结构,它主要用于存储线性数据结构,可以动态地进行添加和删除操作。在C语言中,链表可以通过链式存储结构来实现。本篇攻略将详细讲解C语言链表的实现,包括定义链表、节点、添加节点、删除节点等操作。

链表的定义

链表由一个个节点组成,每个节点包含两个信息:数据和指向下一个节点的指针。在C语言中,可以通过结构体实现每个节点的定义。

struct Node {
    int data;           // 存储节点数据
    struct Node *next;  // 存储指向下一个节点的指针
};

这里定义了一个名为Node的结构体,包含了一个用于存储节点数据的整型变量data和一个用于存储指向下一个节点的指针的结构体类型Node*。其中,Node*是指向该类型结构体的指针类型,因此可以指向该类型的某个节点。

添加节点

链表的添加操作主要有两个:在链表头部添加新节点和在链表尾部添加新节点。以下代码分别实现这两个操作:

在链表头部添加新节点:

struct Node* addNodeAtHead(struct Node* head, int data) {
    // 创建新节点
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    // 把原先的头节点作为新节点的next指针
    newNode->next = head;
    // 把新节点设置为新的头节点
    head = newNode;
    return head;
}

在链表尾部添加新节点:

struct Node* addNodeAtTail(struct Node* head, int data) {
    // 创建新节点
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;
    // 如果链表为空,把新节点作为头节点
    if (head == NULL) {
        head = newNode;
        return head;
    }
    // 找到链表尾部
    struct Node* curNode = head;
    while (curNode->next != NULL) {
        curNode = curNode->next;
    }
    // 把新节点作为链表的最后一个节点
    curNode->next = newNode;
    return head;
}

两个函数都接收一个Node*类型的参数表示链表头节点,返回一个指向头节点的指针。其中,使用了动态内存分配函数malloc来分配一个新节点,并将节点的两个信息进行初始化。

删除节点

链表的删除操作通常通过找到要删除的节点,然后将其上一个节点的next指针指向其下一个节点,进而将其从链表中移除。以下是找到对应节点并删除的代码:

struct Node* deleteNode(struct Node* head, int data) {
    struct Node* curNode = head;
    struct Node* prevNode = NULL;
    // 找到节点
    while (curNode != NULL && curNode->data != data) {
        prevNode = curNode;
        curNode = curNode->next;
    }
    // 如果链表中不存在要删除的节点
    if (curNode == NULL) {
        return head;
    }
    // 如果要删除的节点是头节点
    if (curNode == head) {
        head = head->next;
    } else {
        prevNode->next = curNode->next;
    }
    free(curNode);
    return head;
}

函数接收一个指向头节点的指针和一个要删除的节点的数据,返回一个指向头节点的指针。在找到要删除的节点后,需要保存其上一个节点的指针,否则无法将其从链表中删除。如果要删除的节点是头节点,则需要特殊处理。

示例说明

以下是一个使用链表实现求平均数的示例。

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

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

double getAverage(struct Node* head) {
    int sum = 0;
    int count = 0;
    struct Node* curNode = head;
    while (curNode != NULL) {
        sum += curNode->data;
        count++;
        curNode = curNode->next;
    }
    return (double)sum / (double)count;
}

int main() {
    int arr[] = { 1,2,3,4,5 };
    int len = sizeof(arr) / sizeof(int);

    struct Node* head = NULL;

    for (int i = 0; i < len; i++) {
        head = addNodeAtTail(head, arr[i]);
    }

    double avg = getAverage(head);
    printf("平均数为:%.2f", avg);

    // 释放链表内存
    struct Node* curNode = head;
    while (curNode != NULL) {
        struct Node* temp = curNode;
        curNode = curNode->next;
        free(temp);
    }

    return 0;
}

该程序首先定义了一个名为Node的结构体,用于表示链表节点。接着定义了一个计算平均数的函数getAverage,该函数接收一个指向头节点的指针并返回一个浮点型平均数。函数中使用了链表遍历的方法来计算总和,并统计链表中元素的个数。

在主函数中,将一组数据存储于数组arr中,并使用addNodeAtTail函数将元素添加到链表中,最后调用getAverage函数计算平均数并输出。程序结束后需要手动释放链表内存。

另一个示例是使用链表来实现红包扫雷游戏的。游戏规则:共有$n$个红包,每个红包的金额是随机生成的,并且保证总金额为$m$元。每轮游戏中,用户需要猜测剩余红包的总金额,如果猜对则获得该金额,并继续下一轮游戏,否则游戏结束。以下是一个使用链表实现游戏的示例。

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

struct Node {
    int money;
    struct Node* next;
};

int getRemainMoney(struct Node* head) {
    int sum = 0;
    struct Node* curNode = head;
    while (curNode != NULL) {
        sum += curNode->money;
        curNode = curNode->next;
    }
    return sum;
}

int main() {
    srand((unsigned int)time(NULL));

    int n = 10;
    int m = 100;

    // 初始化红包
    struct Node* head = NULL;
    struct Node* curNode = NULL;
    for (int i = 0; i < n; i++) {
        int money = rand() % (m - n + 1) + 1;
        curNode = (struct Node*)malloc(sizeof(struct Node));
        curNode->money = money;
        curNode->next = NULL;
        if (head == NULL) {
            head = curNode;
        } else {
            struct Node* tail = head;
            while (tail->next != NULL) {
                tail = tail->next;
            }
            tail->next = curNode;
        }
    }

    // 游戏开始
    int remainMoney = getRemainMoney(head);
    int count = 0;
    int guess;
    printf("红包总金额为:%d元\n", m);
    while (remainMoney > 0) {
        printf("剩余红包总金额为:%d元,请猜测总金额:", remainMoney);
        scanf("%d", &guess);
        if (guess == remainMoney) {
            int money = curNode->money;
            printf("恭喜你,猜对了,红包金额为:%d元\n", money);
            head = head->next;
            free(curNode);
            curNode = head;
            count++;
            remainMoney = getRemainMoney(head);
        } else {
            printf("猜错了,游戏结束。");
            break;
        }
    }
    printf("游戏结束,你猜了%d次。", count);

    // 释放链表内存
    curNode = head;
    while (curNode != NULL) {
        struct Node* temp = curNode;
        curNode = curNode->next;
        free(temp);
    }

    return 0;
}

该程序首先定义了一个名为Node的结构体,用于表示红包。接着使用函数srand随机设置种子,生成每个红包的金额,并将其添加到链表中。在游戏开始后,程序每轮接受用户的猜测并将其与剩余金额进行比较,如果猜对则移除当前红包节点并将游戏次数加1,否则游戏结束。程序结束后需要手动释放链表内存。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言链表详解及代码分析 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • C语言数据结构实现银行模拟

    C语言数据结构实现银行模拟攻略 背景介绍 银行模拟是计算机学科中一个重要的数据结构实践练习项目。它涉及到队列(Queue)等数据结构的应用,也是计算机基础课程的一个重要组成部分。 代码实现 1. 队列的实现 首先,我们需要实现一个队列(Queue)结构体,包含 QueueSize、Front、Rear 三个成员变量: struct Queue { int Q…

    数据结构 2023年5月17日
    00
  • JavaScript数据结构之链表的实现

    JavaScript数据结构之链表的实现 什么是链表 链表是一种线性数据结构,其中的元素在内存中不连续地存储,每个元素通常由一个存储元素本身的节点和一个指向下一个元素的引用组成。相比较于数组,链表具有如下优缺点: 优点:动态地添加或删除元素时,无需移动其它元素。(数组则需要移动其它元素) 缺点:不能随机地访问某个元素,必须从头开始顺序遍历。(而数组可以通过索…

    数据结构 2023年5月17日
    00
  • Java红黑树的数据结构与算法解析

    Java红黑树的数据结构与算法解析 红黑树简介 红黑树是一种平衡二叉搜索树,其中的每个节点上都有一个黑色或红色的标记,并且满足以下性质: 根节点是黑色的; 叶子节点是黑色的空节点(NULL); 如果一个节点是红色的,则其子节点必须是黑色的; 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点; 新插入的节点默认是红色的。 具体来说,只有在删除或者某…

    数据结构 2023年5月17日
    00
  • C语言单链队列的表示与实现实例详解

    C语言单链队列的表示与实现实例详解 什么是队列? 在计算机科学中,队列(Queue)是一种特殊的数据结构,它只允许在一端进行插入操作,在另一端进行删除操作。将新元素插入队列的过程可以称之为入队,而将元素从队列中删除的过程则可以称之为出队。队列的核心思想是“先进先出”(First In First Out,FIFO),即先入队的元素先出队。 单链队列的表示方式…

    数据结构 2023年5月17日
    00
  • GPS北斗卫星时间同步系统助力电力自动化网络系统

    GPS北斗卫星时间同步系统助力电力自动化网络系统 GPS北斗卫星时间同步系统助力电力自动化网络系统 京准电子官微——ahjzsz 前言 近几年来,随着电力自动化水平的提高,在电力中计算机监控系统、微机保护装置、微机故障录波装置以及各类数据管理机得到了广泛的应用,而这些自动装置的配合工作需要有一个精确统一的时间。当电力系统发生故障时,既可实现全站各系统在统一时…

    算法与数据结构 2023年5月8日
    00
  • Redis五种数据结构在JAVA中如何封装使用

    Redis 是一款高性能的键值存储数据库,支持五种不同的数据结构:字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。在Java中使用Redis需要封装对应的数据结构,本文将详细介绍如何封装Redis的五种数据结构。 封装Redis字符串数据结构 Redis字符串数据结构对应Java中的String类…

    数据结构 2023年5月17日
    00
  • JavaScript数据结构和算法之二叉树详解

    JavaScript数据结构和算法之二叉树详解 什么是二叉树? 二叉树是一种树形结构,其中每个节点最多有两个子节点:左子节点和右子节点。每个节点都是一个对象,包括属性和方法。节点的属性可能包括值,左节点和右节点。节点的方法可能包括插入和删除。 二叉树的应用场景 二叉树的常用场景包括: 排序算法(二叉排序树); 表达式求值; 线段树; 图形图像学; 数据压缩算…

    数据结构 2023年5月17日
    00
  • JavaScript数据结构与算法之二叉树遍历算法详解【先序、中序、后序】

    JavaScript数据结构与算法之二叉树遍历算法详解 什么是二叉树 二叉树是一种每个节点最多只有两个子节点的树结构,可以用来组织数据、搜索、排序等。 二叉树的遍历 遍历是指按照一定次序访问二叉树中的所有节点。常见的二叉树遍历有三种方式:先序遍历、中序遍历、后序遍历。以下分别对它们进行详细讲解。 前序遍历 前序遍历是指先访问节点本身,然后再遍历其左子树和右子…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部