C语言数据结构之单向链表详解分析

C语言数据结构之单向链表详解分析

什么是单向链表?

单向链表是一种常见的数据结构,它由一系列节点(或称单元)组成,每个节点都包含两个数据域:数据和指针。其中,数据用于存储具体的数据信息,指针则用于指向下一个节点。这样,一个链表就可以看做是由一个一个节点链接而成的数据结构。而单向链表中的指针只能指向下一个节点,因此被称为单向链表。

如何使用单向链表?

单向链表通常用于需要频繁插入、删除节点的场景,因为这种情况下使用数组等静态数据结构会导致效率低下。另外,链表还可以根据需求来灵活扩充大小,可以节省空间。

单向链表的实现

单向链表的实现主要包括链表的初始化、节点的插入、节点的删除、查找节点等功能。

链表的初始化

初始化需定义一个链表头结点,头节点的作用主要为了方便链表中节点的插入、删除等操作。

typedef struct node {
    int data; // 数据域
    struct node *next; // 指针域
} Node, *LinkList; 

LinkList InitList() {
    LinkList head = (LinkList)malloc(sizeof(Node)); // 动态分配头结点的内存空间
    head->next = NULL;
    return head; // 返回头结点
}

节点的插入

节点的插入需要根据插入位置创建新节点,然后将其连接到链表中。

void InsertNode(LinkList head, int pos, int elem) {
    Node *p = head;
    for (int i = 1; i < pos; i++) {
        if (p == NULL) return;
        p = p->next; // 找到需要插入的位置
    }
    Node *newNode = (Node *)malloc(sizeof(Node)); // 动态分配一个新节点
    newNode->data = elem;
    newNode->next = p->next; // 将新节点插入到链表中
    p->next = newNode;
}

节点的删除

删除节点同样需要找到节点位置,然后将其从链表中删除。

bool DeleteNode(LinkList head, int pos) {
    Node *p = head;
    for (int i = 1; i < pos; i++) {
        if (p == NULL) return false;
        p = p->next; // 找到需要删除的位置
    }
    if (p == NULL || p->next == NULL) return false;
    Node *temp = p->next; // 将节点从链表中删除
    p->next = temp->next;
    free(temp);
    return true;
}

查找节点

查找节点需要遍历整个链表,直到找到目标节点。

Node *GetNode(LinkList head, int pos) {
    Node *p = head;
    for (int i = 1; i <= pos; i++) {
        if (p == NULL || p->next == NULL) return NULL;
        p = p->next; // 遍历链表,直到找到目标节点
    }
    return p;
}

示例

示例1

现在我们需要用单向链表实现一个存储10个元素的列表,列表中元素分别为1, 3, 5,..., 19。可以通过以下方式实现:

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

typedef struct node {
    int data; // 数据域
    struct node *next; // 指针域
} Node, *LinkList; 

LinkList InitList() {
    LinkList head = (LinkList)malloc(sizeof(Node)); // 动态分配头结点的内存空间
    head->next = NULL;
    return head; // 返回头结点
}

void InsertNode(LinkList head, int pos, int elem) {
    Node *p = head;
    for (int i = 1; i < pos; i++) {
        if (p == NULL) return;
        p = p->next; // 找到需要插入的位置
    }
    Node *newNode = (Node *)malloc(sizeof(Node)); // 动态分配一个新节点
    newNode->data = elem;
    newNode->next = p->next; // 将新节点插入到链表中
    p->next = newNode;
}

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

int main() {
    LinkList head = InitList(); // 初始化链表
    for (int i = 1; i <= 10; i++) {
        InsertNode(head, i, 2 * i - 1); // 插入节点
    }
    PrintList(head); // 输出链表
    return 0;
}

输出结果:

1 3 5 7 9 11 13 15 17 19

示例2

现在我们需要实现一个存储学生信息的单向链表。每个学生信息包含学号和姓名两个字段。可以通过以下方式实现:

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

typedef struct student {
    int no; // 学号
    char name[50]; // 姓名
    struct student *next; // 指针域
} Student, *LinkList; 

LinkList InitList() {
    LinkList head = (LinkList)malloc(sizeof(Student)); // 动态分配头结点的内存空间
    head->next = NULL;
    return head; // 返回头结点
}

void InsertStudent(LinkList head, int pos, int no, char *name) {
    Student *p = head;
    for (int i = 1; i < pos; i++) {
        if (p == NULL) return;
        p = p->next; // 找到需要插入的位置
    }
    Student *newStudent = (Student *)malloc(sizeof(Student)); // 动态分配一个新学生
    newStudent->no = no;
    strcpy(newStudent->name, name);
    newStudent->next = p->next; // 将新学生插入到链表中
    p->next = newStudent;
}

void PrintStudent(LinkList head) {
    Student *p = head->next;
    while (p != NULL) {
        printf("学号:%d 姓名:%s\n", p->no, p->name);
        p = p->next;
    }
    printf("\n");
}

int main() {
    LinkList head = InitList(); // 初始化链表
    InsertStudent(head, 1, 101, "小明"); // 插入学生
    InsertStudent(head, 2, 102, "小红");
    InsertStudent(head, 3, 103, "小刚");
    PrintStudent(head); // 输出链表
    return 0;
}

输出结果:

学号:101 姓名:小明
学号:102 姓名:小红
学号:103 姓名:小刚

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言数据结构之单向链表详解分析 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • js静态作用域的功能。

    JS静态作用域的功能 静态作用域是指在JavaScript中,变量的作用域在函数定义的时候就确定了,而不是在函数调用的时候确定。下面将详细讲解JS静态作用域的功能,并提供两个示例说明。 示例1:全局作用域 var name = \"John\"; function greet() { console.log(\"Hello, \…

    other 2023年8月19日
    00
  • 全面解析PHP面向对象的三大特征

    PHP中面向对象编程有三大特征:封装、继承和多态。 封装 封装是指将对象的属性和方法封装在类中,并对外部数据提供访问接口,通过这些接口来控制外部数据的使用。在PHP中,可以通过访问修饰符(public、protected、private)来限制属性和方法的访问权限。 示例 class Person { private $name; public functi…

    other 2023年6月26日
    00
  • springboot修改上传文件(图片等)的默认大小

    Spring Boot修改上传文件(图片等)的默认大小攻略 在Spring Boot应用程序中,上传文件(例如图片)时,可能会遇到默认上传文件大小限制的问题。本攻略将介何修改Spring Boot应用程序的默认上传文件大小限制,并提供两个示例。 修改默认上传文件大小限制 Spring Boot应用程序的文件大小限制为1MB。如果要上传更大的文件,需要修改应用…

    other 2023年5月9日
    00
  • 使用PHP开发留言板功能

    使用PHP开发留言板功能攻略 留言板是一个常见的功能,可以让用户在网站上发布留言并与其他用户进行交流。下面是使用PHP开发留言板功能的完整攻略。 步骤一:创建数据库 首先,我们需要创建一个数据库来存储留言信息。可以使用MySQL或其他关系型数据库管理系统。以下是一个示例的MySQL数据库创建语句: CREATE DATABASE message_board;…

    other 2023年7月27日
    00
  • C++ 解决求两个链表的第一个公共结点问题

    下面我将为您详细讲解C++如何解决求两个链表的第一个公共结点问题。 问题描述 给定两个单向链表的头指针head1和head2,请找出它们的第一个公共结点。 解决思路 要想求两个链表的第一个公共结点,我们可以使用如下思路: 先遍历两个链表得到它们的长度len1和len2。同时标记一下两个链表的尾节点是否相同。 如果两个链表的尾节点不同,则两个链表没有公共节点,…

    other 2023年6月27日
    00
  • java中子类继承父类,程序运行顺序的深入分析

    下面是详细讲解“Java中子类继承父类,程序运行顺序的深入分析”的完整攻略。 1. 继承基础 继承是一种面向对象编程的重要特性,它能够让我们定义一个类,并从某个现有的类中继承其属性和方法。Java中的继承关系是通过extends关键字来实现的。 在Java中,所继承的类被称为父类或者超类,而新定义的类则称为子类或者派生类。子类继承父类之后,就可以使用父类中定…

    other 2023年6月26日
    00
  • 显存封装是什么及主要形式介绍

    下面是对于“显存封装是什么及主要形式介绍”的详细讲解。 什么是显存封装? 在计算机显示系统中,显存是用于存储图像数据的一种专用内存。而显存封装实际上指的是将显存芯片和相关电路组装在一起,形成一个独立的整体。显存封装可以用于各种图形处理设备,提供高速访问和容量控制的硬件支持,为计算机显示系统的性能提供了重要的贡献。 主要形式介绍 显存封装的主要形式有以下几种:…

    other 2023年6月25日
    00
  • 如何设置家庭或小型办公网络? 家庭小型办公室路由器设置及组网

    接下来我将分享一些关于如何设置家庭或小型办公网络的完整攻略。 1. 购买合适的路由器 首先,你需要购买一台适合家庭或小型办公室使用的路由器。因为在组网过程中,路由器会扮演重要的角色,它可以把来自互联网的信号转发给内部网络设备,并且可以充当网络的隔离器,防止攻击者入侵内部网络。建议选择有信誉、功能强大的品牌,比如华为、TP-LINK、小米等。 2. 连接路由器…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部