C数据结构之单链表详细示例分析

C数据结构之单链表详细示例分析

介绍

在C和数据结构中,单链表是一个非常有用的数据结构,可以用来存储一个列表的元素。单链表由节点构成,每个节点包含一个指向下一个节点的指针和一个存储数据的值。本文将详细介绍单链表的各个方面,包括创建、插入、删除和遍历节点。同时提供两个实际的应用例子:一个是使用单链表实现的简单画图程序,另一个是使用单链表实现的简单图书馆管理系统。

创建单链表

单链表的创建过程包括两个主要步骤:申请空间和初始化指针。具体过程如下:

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

struct Node* createNode(int data) {
    struct Node* node = (struct Node*)malloc(sizeof(struct Node));
    node->data = data;
    node->next = NULL;
    return node;
}

struct Node* createList(int* data, int n) {
    struct Node* head = createNode(data[0]);
    struct Node* tail = head;
    for (int i = 1; i < n; i++) {
        struct Node* node = createNode(data[i]);
        tail->next = node;
        tail = node;
    }
    return head;
}

上面的代码中,首先定义了每个节点的结构体,并利用malloc函数申请空间来存储节点的数据和指针,然后通过初始化指针,将节点组装成链表。其中,createNode函数创建一个新的节点,createList函数创建新的链表,其中data是存储的数据,n是节点的数目,head是指向链表头节点的指针,tail是当前尾节点的指针。

例如,创建一个包含5个元素的链表:

int a[5] = { 1, 2, 3, 4, 5 };
struct Node* head = createList(a, 5);

插入节点

在单链表中插入一个新节点,需要考虑两个主要问题:插入位置和插入元素。一般来说,插入位置可以分为两种情况:在链表头插入和在链表中间或尾部插入。具体插入代码如下:

struct Node* insertAtHead(struct Node* head, int data) {
    struct Node* node = createNode(data);
    node->next = head;
    return node;
}

struct Node* insertAtTail(struct Node* head, int data) {
    struct Node* node = createNode(data);
    if (head == NULL) {
        return node;
    }
    struct Node* p = head;
    while (p->next != NULL) {
        p = p->next;
    }
    p->next = node;
    return head;
}

struct Node* insertAtIndex(struct Node* head, int index, int data) {
    struct Node* node = createNode(data);
    if (head == NULL) {
        return node;
    }
    if (index == 0) {
        node->next = head;
        return node;
    }
    struct Node* p = head;
    int i = 0;
    while (p != NULL && i < index-1) {
        p = p->next;
        i++;
    }
    if (p == NULL) {
        return head;
    }
    node->next = p->next;
    p->next = node;
    return head;
}

上述代码中,insertAtHead函数在单链表头部插入节点,insertAtTail函数在单链表尾部插入节点,insertAtIndex函数插入到指定位置。其中,head是指向链表头节点的指针,data是存储的数据,index是插入的位置。如果head为空,则创建新的头节点并返回。

例如,在单链表的尾部插入一个新节点:

int a[5] = { 1, 2, 3, 4, 5 };
struct Node* head = createList(a, 5);
head = insertAtTail(head, 6);

删除节点

在单链表中删除节点,同样需要考虑两个主要问题:删除位置和删除元素。一般来说,删除位置可以分为两种情况:删除第一个节点和删除中间或尾部节点。具体删除代码如下:

struct Node* deleteAtHead(struct Node* head) {
    if (head == NULL) {
        return NULL;
    }
    struct Node* p = head->next;
    free(head);
    return p;
}

struct Node* deleteAtIndex(struct Node* head, int index) {
    if (head == NULL) {
        return NULL;
    }
    if (index == 0) {
        struct Node* p = head->next;
        free(head);
        return p;
    }
    struct Node* p = head;
    int i=0;
    while (p != NULL && i < index-1) {
        p = p->next;
        i++;
    }
    if (p == NULL || p->next == NULL) {
        return head;
    }
    struct Node* q = p->next->next;
    free(p->next);
    p->next = q;
    return head;
}

上述代码中,deleteAtHead函数删除单链表的头节点,deleteAtIndex函数删除指定位置的节点。其中,head是指向链表头节点的指针,index是删除的位置。如果head为空,则返回NULL。

例如,从单链表中删除第4个节点:

int a[5] = { 1, 2, 3, 4, 5 };
struct Node* head = createList(a, 5);
head = deleteAtIndex(head, 3);

遍历节点

遍历节点是指访问单链表中所有节点的数据。通常,需要遍历所有节点来完成某些任务,比如输出单链表的所有元素,或者查找单链表中的某个元素。具体遍历代码如下:

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

上述代码中,printList函数输出整个链表的所有元素。其中,head是指向链表头节点的指针。

例如,输出单链表的所有元素:

int a[5] = { 1, 2, 3, 4, 5 };
struct Node* head = createList(a, 5);
printList(head);

示例应用一:使用单链表实现的简单画图程序

这是一个基于单链表实现的简单画图程序,可以支持插入、删除和遍历节点。每个节点包含一个值,此程序使用了结构体作为节点(即“图形”)。程序实现的所有操作都是简单的链表操作,并且完全可扩展。

#include <stdio.h>
#include <stdlib.h>
struct Shape {
    int type;
    int x;
    int y;
    int w;
    int h;
    struct Shape* next;
};
struct Shape* createShape(int type, int x, int y, int w, int h) {
    struct Shape* shape = (struct Shape*)malloc(sizeof(struct Shape));
    shape->type = type;
    shape->x = x;
    shape->y = y;
    shape->w = w;
    shape->h = h;
    shape->next = NULL;
    return shape;
}
struct Shape* insertShape(struct Shape* head, struct Shape* shape) {
    if (head == NULL) {
        return shape;
    }
    struct Shape* p = head;
    while (p->next != NULL) {
        p = p->next;
    }
    p->next = shape;
    return head;
}
struct Shape* deleteShape(struct Shape* head, struct Shape* shape) {
    if (head == shape) {
        struct Shape* next = head->next;
        free(head);
        return next;
    }
    struct Shape* p = head;
    while (p->next != NULL) {
        if (p->next == shape) {
            p->next = shape->next;
            free(shape);
            return head;
        }
        p = p->next;
    }
    return head;
}
void printShapes(struct Shape* head) {
    struct Shape* p = head;
    while (p != NULL) {
        printf("%d (%d,%d,%d,%d)\n", p->type, p->x, p->y, p->w, p->h);
        p = p->next;
    }
}

上述代码实现了createShape函数创建一个新的图形,insertShape函数插入一个新的图形节点,deleteShape函数删除一个图形节点,printShapes函数遍历节点并输出所有图形的信息。此示例仅用于演示链表的操作方式。

示例应用二:使用单链表实现的简单图书馆管理系统

这是一个基于单链表实现的图书馆管理系统,可以支持插入、删除和遍历节点。每个节点包含一个值,此程序使用了结构体作为节点(即“图书”)。程序实现的所有操作都是简单的链表操作,并且完全可扩展。

#include <stdio.h>
#include <stdlib.h>
struct Book {
    int id;
    char* title;
    char* author;
    struct Book* next;
};
struct Book* createBook(int id, char* title, char* author) {
    struct Book* book = (struct Book*)malloc(sizeof(struct Book));
    book->id = id;
    book->title = title;
    book->author = author;
    book->next = NULL;
    return book;
}
struct Book* insertBook(struct Book* head, struct Book* book) {
    if (head == NULL) {
        return book;
    }
    struct Book* p = head;
    while (p->next != NULL) {
        p = p->next;
    }
    p->next = book;
    return head;
}
struct Book* deleteBook(struct Book* head, int id) {
    if (head == NULL) {
        return NULL;
    }
    if (head->id == id) {
        struct Book* next = head->next;
        free(head);
        return next;
    }
    struct Book* p = head;
    while (p->next != NULL) {
        if (p->next->id == id) {
            struct Book* q = p->next->next;
            free(p->next);
            p->next = q;
            return head;
        }
        p = p->next;
    }
    return head;
}
void printBooks(struct Book* head) {
    struct Book* p = head;
    while (p != NULL) {
        printf("%d (%s,%s)\n", p->id, p->title, p->author);
        p = p->next;
    }
}

上述代码实现了createBook函数创建一个新的图书信息,insertBook函数插入一个新的图书信息节点,deleteBook函数删除一个图书信息节点,printBooks函数遍历节点并输出所有图书信息。此示例仅用于演示链表的操作方式。

结论

单链表是C语言中非常有用的数据结构,可以用于存储各种类型的元素。本文提供了单链表的一些基本操作,包括创建、插入、删除和遍历节点。此外,本文还提供了两个简单的实例应用,可以轻松地扩展和修改以实现各种其他应用。

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

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

相关文章

  • SQL如何实现MYSQL的递归查询

    SQL可以通过递归查询实现类似MySQL WHERE id IN (SELECT id FROM category WHERE parent_id = 0) 这样的功能。下面给出详细的攻略。 1. 定义表结构 首先需要明确递归查询针对的表结构,本文以一个简单的分类目录结构为例: CREATE TABLE category ( id BIGINT NOT NU…

    other 2023年6月27日
    00
  • Win10中怎么利用的一个位置管理所有存储空间?

    在Windows 10中,你可以使用“存储空间”功能来管理所有的存储设备和磁盘空间。下面是一个详细的攻略,包含了两个示例说明: 步骤1:打开“存储空间”设置 首先,点击任务栏上的Windows图标,然后在弹出的菜单中选择“设置”图标(齿轮状图标)。接下来,在“设置”窗口中,点击“系统”选项。 在“系统”选项卡中,你会看到一个侧边栏,选择“存储”选项。 步骤2…

    other 2023年8月1日
    00
  • C语言详解用char实现大小写字母的转换

    C语言详解用char实现大小写字母的转换攻略 在C语言中,我们可以使用char类型来实现大小写字母的转换。下面是一个详细的攻略,包含了两个示例说明。 步骤1:了解ASCII码表 在C语言中,每个字符都有一个对应的ASCII码值。大写字母的ASCII码值范围是65到90,而小写字母的ASCII码值范围是97到122。我们可以利用这个特性来实现大小写字母的转换。…

    other 2023年8月16日
    00
  • 如何批量生成MySQL不重复手机号大表实例代码

    当涉及到批量生成MySQL不重复手机号大表时,以下是一个完整的攻略,包含两个示例说明: 1. 使用Python生成不重复手机号数据 首先,我们可以使用Python编写一个脚本来生成不重复的手机号数据。可以使用随机数生成器来生成手机号码,并使用集合(Set)来确保生成的手机号不重复。以下是一个示例代码: import random def generate_p…

    other 2023年10月18日
    00
  • StatusStrip控件

    StatusStrip控件 StatusStrip控件是Windows Forms的一个组件,主要用于应用程序的底部显示状态栏信息。其中包含一些常见的信息,例如应用程序的名称、当前日期和时间、状态文本等。 如何使用StatusStrip控件 使用StatusStrip控件非常简单,只需要在Windows Forms的工具箱中选择StatusStrip控件然后…

    其他 2023年3月28日
    00
  • R语言ComplexHeatmap绘制复杂热图heatmap

    当使用R语言绘制复杂热图时,可以使用ComplexHeatmap包。下面是一个完整的攻略,包括两个示例说明。 安装和加载包 首先,确保已经安装了ComplexHeatmap包。如果没有安装,可以使用以下命令进行安装: install.packages(\"ComplexHeatmap\") 安装完成后,加载包: library(Compl…

    other 2023年8月15日
    00
  • pycharm专业版免费激活的三种方法

    以下是“PyCharm专业版免费激活的三种方法”的完整攻略: PyCharm专业版免费激活的三种方法 PyCharm是一款强大的Python集成开发环境,提供了丰富的功能和工具。PyCharm专业版是其高级版本,提供了更多的功能和扩展性。本攻略将详细讲解PyCharm专业版免费激活的三种方法,包括使用激活码、使用破解补丁和使用Docker容器等。 使用激活码…

    other 2023年5月8日
    00
  • C++类中的特殊成员函数示例详解

    下面我来详细讲解“C++类中的特殊成员函数示例详解”的攻略。 一、什么是C++类中的特殊成员函数? 在C++中,类和结构体都有一些特殊的成员函数,也称为特殊成员函数。这些函数在特定情况下会自动创建或者被调用。C++中的特殊成员函数有以下几种: 默认构造函数 拷贝构造函数 拷贝赋值函数 移动构造函数 移动赋值函数 析构函数 二、示例说明 1. 默认构造函数 默…

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