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语言程序中对二叉树数据结构的各种遍历方式

    那么我们先来介绍一下二叉树。 什么是二叉树? 二叉树是一种树状的数据结构,它的每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树节点的定义如下: typedef struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NUL…

    数据结构 2023年5月17日
    00
  • Java数据结构顺序表用法详解

    Java数据结构顺序表用法详解 什么是顺序表? 在计算机科学中,顺序表(英语:Sequence)指的是一种线性数据结构,通常是用数组实现的。顺序表是一种顺序存放的线性表,其中的每个节点按照顺序依次排列。 顺序表的基本操作 顺序表主要包括以下几个基本操作: 创建顺序表 在顺序表中插入元素 从顺序表中删除元素 获取顺序表中的元素 判断顺序表是否为空 获取顺序表的…

    数据结构 2023年5月17日
    00
  • 四边形不等式学习笔记

    简要题意 四边形不等式是一种 dp 优化策略。多用于 2D DP。 内容 对于区间 \([l,r]\) 带来的贡献 \(w(l,r)\),如果其满足: 对于 \(L\leq l\leq r \leq R\),\(w(L,r)+w(l,R)\leq w(L,R)+w(l,r)\) 则称 \(w\) 满足四边形不等式。特别地,如果上式符号取等,则称其满足四边形恒…

    算法与数据结构 2023年4月17日
    00
  • C#常用数据结构和算法总结

    C#常用数据结构和算法总结 数据结构 数组(Array) 数组是一种线性数据结构,它可以在内存中连续地存储相同类型的数据。可以使用索引访问数组中的元素。数组的元素可以是任意类型。 在 C# 中,定义一个数组需要指定数组的类型和数组的大小。例如,定义一个包含 5 个整数的数组: int[] arr = new int[5]; 链表(LinkedList) 链表…

    数据结构 2023年5月17日
    00
  • 数据结构 双向链表的创建和读取详解及实例代码

    下面我为你详细讲解“数据结构 双向链表的创建和读取详解及实例代码”的完整攻略。 什么是双向链表? 双向链表是一种常见的线性数据结构,与单向链表相比,它可以在节点之间建立双向连接,使得在需要反向遍历链表时效率更高。每个节点同时保存了指向前一个节点和后一个节点的指针,因此双向链表也叫做双链表。 双向链表的创建 定义节点类 首先,我们需要定义一个表示节点的类,该类…

    数据结构 2023年5月16日
    00
  • Python数据结构与算法之链表定义与用法实例详解【单链表、循环链表】

    Python数据结构与算法之链表定义与用法实例详解 什么是链表? 链表是一种常见的数据结构,它由一个个的节点组成,每个节点包含两部分,一部分存储数据,一部分存储下一个节点在哪里的指针。通过节点之间的指针,就可以将节点串起来,形成一个链表。 链表和数组是两种截然不同的数据结构,数组的元素在内存中是连续存储的,而链表的节点却可以分散在内存的不同位置,这也是链表灵…

    数据结构 2023年5月17日
    00
  • Java数据结构与算法之单链表深入理解

    Java数据结构与算法之单链表深入理解攻略 什么是单链表? 单链表(Singly Linked List)是指一个节点只指向下一个节点的链表。 单链表由多个节点组成,每个节点有两个属性:数据域和指针域。数据域保存节点的数据,指针域保存下一个节点的指针,因此每个节点包含两个域:data和next。 单链表的基本操作 单链表常用的基本操作包括: 在链表头部添加元…

    数据结构 2023年5月17日
    00
  • C语言数据结构系列队列篇

    C语言数据结构系列队列篇攻略 简介 队列(Queue)是一种先进先出(First In First Out, FIFO)的线性数据结构,类似于排队买票的过程。本篇攻略将带您从以下三个方面深入浅出地了解C语言数据结构系列队列篇: 队列的特点; 队列的实现; 队列的应用。 队列的特点 队列有两个特殊的端点,队头(front)和队尾(rear)。队头指示队列的头部…

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