C语言链表与单链表详解

C语言链表与单链表详解

什么是链表

链表是由一系列节点组成的线性结构,每个节点由两个部分组成:数据域和指针域。数据域用来存储节点的数据,指针域用来指向下一个节点的地址,也就是说每个节点保存了下一个节点的地址信息。由此构成的链式结构被称为链表。

链表相对于数组来说,其大小可以动态调整,插入和删除元素操作更加高效。

单链表

单链表是链表的一种,每个节点中只包含一个指针,指向下一个节点的地址。链表的头节点不包含数据,只包含指向第一个节点的指针。

单链表结构体定义

在C语言中,可以如下定义单链表结构体:

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

其中,Node表示一个节点,LinkList代表一个指向链表头节点的指针。

单链表的创建

单链表的创建需要一个头节点和一系列数据,可以使用一个循环来依次添加节点,最后返回头节点指针。

LinkList createList() {
    Node *head, *tail, *p;
    int data;
    head = tail = (Node*)malloc(sizeof(Node));
    tail->next = NULL;
    printf("请输入数据,输入-1结束:\n");
    scanf("%d", &data);
    while (data != -1) {
        p = (Node*)malloc(sizeof(Node));
        p->data = data;
        tail->next = p;
        tail = p;
        scanf("%d", &data);
    }
    tail->next = NULL;
    return head;
}

在该函数中,首先定义头节点和尾节点,然后按顺序添加节点,直到输入-1停止。最后返回头节点指针。

单链表的遍历

单链表的遍历可以使用一个指针从头节点开始挨个访问每个节点。

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

该函数首先将指针指向第一个节点,若节点存在,则输出数据域,并将指针指向下一个节点,循环直到最后一个节点。

单链表的插入

单链表的插入需要指定插入位置,可以使用一个指针找到待插入位置,然后插入新节点。

void insertNode(LinkList list, int data, int pos) {
    Node* p = list;  // 创建指针指向第一个节点
    Node* q = NULL;  // 创建指针指向待插入位置前面的节点
    Node* new = NULL;  // 创建新节点
    int i = 1;
    while (p != NULL && i < pos) {  // 找到待插入位置的前一个节点
        p = p->next;
        i++;
    }
    if (p == NULL || i > pos) {  // 位置不合法,退出插入。
        printf("位置不合法\n");
        return;
    }
    q = p->next;  // 待插入位置前一个节点
    new = (Node*)malloc(sizeof(Node));  // 创建新节点
    new->data = data;  // 写入数据域
    new->next = q;  // 连接到后面的节点
    p->next = new;  // 连接到前面的节点
}

该函数首先根据输入的位置找到待插入位置和前一个节点,然后创建新节点,并将它插入到链表中。

单链表的删除

单链表的删除同样需要指定删除位置,可以使用一个指针找到待删除位置,然后删除该节点。

void deleteNode(LinkList list, int pos) {
    Node* p = list;  // 创建指针指向第一个节点
    Node* q = NULL;  // 创建指针指向待删除位置前面的节点
    int i = 1;
    while (p != NULL && i < pos) {  // 找到待删除位置的前一个节点
        p = p->next;
        i++;
    }
    if (p == NULL || i > pos || p->next == NULL) {  // 位置不合法,退出删除。
        printf("位置不合法\n");
        return;
    }
    q = p->next;  
    p->next = q->next;  
    free(q);  // 释放掉待删除节点的内存空间
}

该函数同样根据输入的位置找到待删除位置和前一个节点,然后删除该节点。

单链表的示例

下面是一个完整的单链表的示例,包含了创建、遍历、插入和删除操作。

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

typedef struct node {
    int data;           
    struct node *next;  
} Node, *LinkList;

LinkList createList() {
    Node *head, *tail, *p;
    int data;
    head = tail = (Node*)malloc(sizeof(Node));
    tail->next = NULL;
    printf("请输入数据,输入-1结束:\n");
    scanf("%d", &data);
    while (data != -1) {
        p = (Node*)malloc(sizeof(Node));
        p->data = data;
        tail->next = p;
        tail = p;
        scanf("%d", &data);
    }
    tail->next = NULL;
    return head;
}

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

void insertNode(LinkList list, int data, int pos) {
    Node* p = list;  
    Node* q = NULL;  
    Node* new = NULL;  
    int i = 1;
    while (p != NULL && i < pos) {  
        p = p->next;
        i++;
    }
    if (p == NULL || i > pos) {  
        printf("位置不合法\n");
        return;
    }
    q = p->next;  
    new = (Node*)malloc(sizeof(Node));  
    new->data = data;  
    new->next = q;  
    p->next = new;  
}

void deleteNode(LinkList list, int pos) {
    Node* p = list;  
    Node* q = NULL;  
    int i = 1;
    while (p != NULL && i < pos) {  
        p = p->next;
        i++;
    }
    if (p == NULL || i > pos || p->next == NULL) {  
        printf("位置不合法\n");
        return;
    }
    q = p->next;  
    p->next = q->next;  
    free(q);  
}

int main() {
    LinkList list = createList();
    printf("原始链表:\n");
    traverseList(list);
    printf("插入节点前:\n");
    insertNode(list, 99, 3);
    traverseList(list);
    printf("删除节点后:\n");
    deleteNode(list, 2);
    traverseList(list);
    return 0;
}

运行结果:

请输入数据,输入-1结束:
1 2 3 4 5 -1
原始链表:
1 2 3 4 5 
插入节点前:
1 2 99 3 4 5 
删除节点后:
1 3 4 5 

双向链表

双向链表是相对于单向链表而言的另一种链表结构,每个节点中包含两个指针,分别指向前一个节点和后一个节点。双向链表的优点是在单向链表的基础上增加了向前访问的功能,但其缺点是节点中需要保存更多指针,占用的空间更大。

双向链表的创建、遍历、插入和删除和单向链表类似,只需要修改部分代码即可。

总结

链表是一种重要的数据结构,在算法和程序设计中被广泛使用。本文介绍了链表的基本概念,并通过单向链表为例讲解了链表的创建、遍历、插入和删除操作。读者可以通过修改代码实现双向链表和其他版本的链表。

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

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

相关文章

  • 三星s4无限自动重启解决办法

    三星S4无限自动重启解决办法 问题描述 三星S4手机出现无限自动重启的问题是比较常见的,可能会给用户造成很大的困扰。这种问题一般是由于软件更新、应用冲突或系统文件丢失等原因引起的。那么,应该如何解决这个问题呢? 解决步骤 步骤一:尝试软重启 软重启是指先进行一次正常关机,然后再开机,这个过程可以清除一些手机中的缓存,通常可以解决一些问题。 长按手机电源键,进…

    other 2023年6月27日
    00
  • Java中泛型通配符的使用方法示例

    Java中泛型通配符的使用方法示例 介绍 Java中的泛型通配符(Wildcard)是一种特殊的类型参数,用于表示未知的类型。通配符可以增加代码的灵活性,使得我们可以处理不同类型的数据。在本攻略中,我们将详细讲解泛型通配符的使用方法,并提供两个示例说明。 通配符的类型 Java中的通配符有两种类型:上界通配符(? extends T)和下界通配符(? sup…

    other 2023年6月28日
    00
  • 搬瓦工服务器搭建vpn

    以下是“搬瓦工服务器搭建VPN的完整攻略”的详细讲解,过程中包含两个示例说明的标准Markdown格式文本: 搬瓦工服务器搭建VPN的完整攻略 在搬瓦工服务器上搭建VPN可以帮助我们实现网络加密和匿名访问的功能。本文将介绍如何在搬瓦工服务器上搭建VPN,并提供两个常用的示例。 1. 选择VPN协议 在搭建VPN之前,我们需要选择合适的VPN协议。常用的VPN…

    other 2023年5月10日
    00
  • 文件夹怎么设密码

    当用户需要在计算机上保护一些敏感文件时,他们可以使用文件夹密码保护功能。这种方法可以确保未经许可的用户无法访问文件夹中的文件。以下是设置文件夹密码的完整攻略。 步骤1:创建一个新文件夹 首先,用户需要创建一个新的文件夹,并将其中包含的所有敏感文件移到其中。 步骤2:创建一个.bat文件 接下来,用户需要在新文件夹内创建一个“ .BAT ”文件,如“ prot…

    其他 2023年4月16日
    00
  • Win11蓝屏收集错误信息重启怎么修复? Win11蓝屏自动重启的解决办法

    Win11蓝屏收集错误信息重启是一种紧急方式,用于避免系统损坏。但是,用户可能会遇到失败收集错误信息并重启电脑的情况。下面是这种问题的解决办法: 解决Win11蓝屏收集错误信息重启失败的问题 方法一:进入“安全模式”并通过“高级选项”修复 重启你的电脑,在Win11启动界面上,按住Shift键,然后单击“重新启动”选项。这将进入“高级选项”菜单。 在“高级选…

    other 2023年6月20日
    00
  • SpringBoot整合WebService服务的实现代码

    下面是 SpringBoot 整合 WebService 服务的实现代码的完整攻略。 1. 添加 WebService 相关依赖 在 pom.xml 中添加以下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spr…

    other 2023年6月27日
    00
  • Windows环境下的MYSQL5.7配置文件定位图文分析

    下面是完整的攻略: Windows环境下的MYSQL5.7配置文件定位图文分析 1. 配置文件的作用和作用范围 MYSQL5.7的配置文件定义了MYSQL数据库服务器的运行参数,也包含了MYSQL服务器的行为规则等内容。MYSQL5.7的配置文件可以作用于以下几个范围: 全局级别:适用于MYSQL服务器范围内的全部计算机或实例。 组级别:只适用于指定的组。 …

    other 2023年6月25日
    00
  • ASP如何获取真实IP地址

    ASP如何获取真实IP地址的攻略 在ASP中,要获取客户端的真实IP地址,可以通过以下几个步骤来实现: 步骤一:使用Request.ServerVariables集合 ASP提供了一个名为Request.ServerVariables的集合,其中包含了一些服务器变量的信息,包括客户端的IP地址。可以通过以下代码来获取真实IP地址: <% Dim cli…

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