C语言一篇精通链表的各种操作

C 语言精通链表操作攻略

简介

链表是一种常用的数据结构,它相对于数组等数据结构来说,具有更高的灵活性和增删操作的效率。在 C 语言中,我们可以用指针来实现链表,这也是指针与动态内存分配的重要应用之一。本文将提供在 C 语言中精通链表操作的攻略,包括链表的创建、添加、删除、搜索、遍历等常用操作。

基本结构体定义

链表一般由结构体和指针构成,下面我们定义一个链表结构体节点:

struct ListNode {
    int val;
    struct ListNode* next;
};

其中,val 表示节点中存储的值,next 表示下一个节点的指针。为了方便后续的实现,我们还定义一个指向链表开头的指针:

typedef struct ListNode* LinkedList;

创建链表

首先,我们需要创建一个空链表。因为链表的第一个节点没有前驱节点,所以需要特别处理一下:

LinkedList createLinkedList() {
    LinkedList head = (LinkedList)malloc(sizeof(struct ListNode));
    head->next = NULL;
    return head;
}

手动添加节点

接下来,我们手动向链表中添加几个节点:

LinkedList head = createLinkedList();
LinkedList p = (LinkedList)malloc(sizeof(struct ListNode));
p->val = 1;
p->next = NULL;
head->next = p;

LinkedList q = (LinkedList)malloc(sizeof(struct ListNode));
q->val = 2;
q->next = NULL;
p->next = q;

这样就创建了一个有两个节点的链表。

添加节点

在链表结尾处添加一个节点

为了在链表结尾处添加一个节点,我们需要先找到链表的最后一个节点,即 next 指针为NULL的节点。然后在此节点之后,添加新的节点即可:

void addAtTail(LinkedList head, int val) {
    // 找到最后一个节点
    LinkedList p = head;
    while (p->next) {
        p = p->next;
    }

    // 在最后一个节点之后添加新的节点
    LinkedList newNode = (LinkedList)malloc(sizeof(struct ListNode));
    newNode->val = val;
    newNode->next = NULL;
    p->next = newNode;
}

在链表头部添加一个节点

在链表头部添加节点与在链表尾部添加节点相似,只是我们需要让新节点指向原来的头节点,然后将新节点作为新的头节点即可:

void addAtHead(LinkedList head, int val) {
    LinkedList newNode = (LinkedList)malloc(sizeof(struct ListNode));
    newNode->val = val;
    newNode->next = head->next;
    head->next = newNode;
}

在链表中间添加一个节点

为了在链表的中间位置添加一个节点,我们需要先找到要插入的位置,移动指针即可:

void addAtIndex(LinkedList head, int index, int val) {
    // 链表头结点为第0个元素
    if (index <= 0) {
        addAtHead(head, val);
        return;
    }

    // 找到要插入节点的前驱节点
    LinkedList p = head;
    for (int i = 0; i < index - 1; i++) {
        p = p->next;
        if (p == NULL) {
            return; // index 超出链表范围
        }
    }

    LinkedList newNode = (LinkedList)malloc(sizeof(struct ListNode));
    newNode->val = val;
    newNode->next = p->next;
    p->next = newNode;
}

删除节点

删除指定节点

为了删除指定的节点,我们需要先找到这个节点的前驱节点,然后将前驱节点的 next 指针,指向要删除节点的后继节点即可:

void deleteNode(LinkedList head, int val) {
    LinkedList p = head;
    while (p->next != NULL && p->next->val != val) {
        p = p->next;
    }
    if (p->next == NULL) {
        return; // 没有节点包含val值
    }

    LinkedList temp = p->next;
    p->next = temp->next;
    free(temp);
}

删除指定下标的节点

为了删除指定下标的节点,我们需要先找到要删除节点的前驱节点:

void deleteAtIndex(LinkedList head, int index) {
    // 链表头结点为第0个元素
    if (index < 0) {
        return;
    }

    LinkedList p = head;
    for (int i = 0; i < index; i++) {
        p = p->next;
        if (p == NULL) {
            return; // index 超出链表范围
        }
    }

    LinkedList temp = p->next;
    if (temp == NULL) {
        return; // index 超出链表范围
    }

    p->next = temp->next;
    free(temp);
}

搜索节点

为了搜索指定值的节点,我们只需要遍历整个链表,直到找到一个值为指定值,或者链表遍历结束:

LinkedList searchLinkedList(LinkedList head, int val) {
    LinkedList p = head->next;
    while (p != NULL && p->val != val) {
        p = p->next;
    }
    return p;
}

遍历节点

遍历节点是链表的最常见操作之一,我们可以用循环来遍历整个链表:

void traverseLinkedList(LinkedList head) {
    LinkedList p = head->next;
    while (p != NULL) {
        printf("%d ", p->val);
        p = p->next;
    }
}

示例运行

下面是这些链表操作的完整代码和使用示例:

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

struct ListNode {
    int val;
    struct ListNode* next;
};

typedef struct ListNode* LinkedList;

LinkedList createLinkedList() {
    LinkedList head = (LinkedList)malloc(sizeof(struct ListNode));
    head->next = NULL;
    return head;
}

void addAtTail(LinkedList head, int val) {
    LinkedList p = head;
    while (p->next) {
        p = p->next;
    }

    LinkedList newNode = (LinkedList)malloc(sizeof(struct ListNode));
    newNode->val = val;
    newNode->next = NULL;
    p->next = newNode;
}

void addAtHead(LinkedList head, int val) {
    LinkedList newNode = (LinkedList)malloc(sizeof(struct ListNode));
    newNode->val = val;
    newNode->next = head->next;
    head->next = newNode;
}

void addAtIndex(LinkedList head, int index, int val) {
    if (index <= 0) {
        addAtHead(head, val);
        return;
    }

    LinkedList p = head;
    for (int i = 0; i < index - 1; i++) {
        p = p->next;
        if (p == NULL) {
            return;
        }
    }

    LinkedList newNode = (LinkedList)malloc(sizeof(struct ListNode));
    newNode->val = val;
    newNode->next = p->next;
    p->next = newNode;
}

void deleteNode(LinkedList head, int val) {
    LinkedList p = head;
    while (p->next != NULL && p->next->val != val) {
        p = p->next;
    }
    if (p->next == NULL) {
        return;
    }

    LinkedList temp = p->next;
    p->next = temp->next;
    free(temp);
}

void deleteAtIndex(LinkedList head, int index) {
    if (index < 0) {
        return;
    }

    LinkedList p = head;
    for (int i = 0; i < index; i++) {
        p = p->next;
        if (p == NULL) {
            return;
        }
    }

    LinkedList temp = p->next;
    if (temp == NULL) {
        return;
    }

    p->next = temp->next;
    free(temp);
}

LinkedList searchLinkedList(LinkedList head, int val) {
    LinkedList p = head->next;
    while (p != NULL && p->val != val) {
        p = p->next;
    }
    return p;
}

void traverseLinkedList(LinkedList head) {
    LinkedList p = head->next;
    while (p != NULL) {
        printf("%d ", p->val);
        p = p->next;
    }
}

int main() {
    LinkedList head = createLinkedList();
    addAtHead(head, 5);
    addAtTail(head, 6);
    addAtIndex(head, 1, 4);
    deleteAtIndex(head, 1);
    LinkedList p = searchLinkedList(head, 5);
    printf("5 是否在链表中:");
    if (p) {
        printf("是");
    } else {
        printf("否");
    }
    printf("\n链表:");
    traverseLinkedList(head);
    printf("\n");

    return 0;
}

输出结果为:5 是否在链表中:是 链表:5 6

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言一篇精通链表的各种操作 - Python技术站

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

相关文章

  • C语言数据结构不挂科指南之线性表详解

    C语言数据结构不挂科指南之线性表详解 本篇攻略将为大家介绍C语言数据结构中的线性表,包括定义、实现和应用。希望能够为初学者提供帮助,让大家轻松学习和掌握线性表的相关知识。 一、线性表的定义 线性表是由一组元素构成的有限序列,其中每个元素可以有零个或一个前驱元素,也可以有零个或一个后继元素。线性表通常用于存储和处理具有相同类型的数据元素。 线性表的实现方式有多…

    数据结构 2023年5月17日
    00
  • C语言进阶数据的存储机制完整版

    C语言进阶数据的存储机制完整版攻略 1. 前言 C语言是一门高度可控的语言,其中其数据的存储机制是必须掌握的基础知识点。本文介绍了C语言数据存储的机制,包括变量在内存中的分配、指针的应用及结构体的组织等内容,旨在帮助读者掌握C语言中的数据存储机制。 2. 变量在内存中的分配 变量在内存中的分配既涉及到内存的分配可操作性,也涉及到相应的存储结构。 2.1. 变…

    数据结构 2023年5月17日
    00
  • EMI/EMS/EMC有什么关系?

    EMI(Electromagnetic Interference)直译是“电磁干扰”,是指电子设备(即干扰源)通过电磁波对其他电子设备产生干扰的现象。 从“攻击”方式上看,EMI主要有两种类型:传导干扰和辐射干扰。 电磁传导干扰是指干扰源通过导电介质(例如电线)把自身电网络上的信号耦合到另一个电网络。 电磁辐射干扰往往被我们简称为电磁辐射,它是指干扰源通过空…

    算法与数据结构 2023年4月17日
    00
  • 详解C语言实现空间索引四叉树

    详解C语言实现空间索引四叉树攻略 四叉树是一种常见的空间索引方法,可以有效地处理二维或三维空间中的数据。本攻略将详细介绍使用C语言实现空间索引四叉树的方法,包括数据结构的设计,插入和查询操作的实现。 数据结构设计 结点结构体 struct QuadtreeNode { int depth; // 结点深度 double x, y; // 结点中心坐标 dou…

    数据结构 2023年5月17日
    00
  • LinkedList学习示例模拟堆栈与队列数据结构

    下面是关于“LinkedList学习示例模拟堆栈与队列数据结构”的完整攻略。 什么是LinkedList? LinkedList是Java语言中的一个类,用于表示链表数据结构。链表数据结构可以根据需要进行增、删、改、查等操作,是常用的数据结构之一。 如何使用LinkedList实现堆栈? 堆栈是一种先进后出(LIFO)的数据结构,可以使用LinkedList…

    数据结构 2023年5月17日
    00
  • C语言数据结构之单链表存储详解

    C语言数据结构之单链表存储详解 什么是单链表 链表是一种非顺序存储的数据结构,其每个节点都保存下一个节点的地址。单链表是最简单的链表,每个节点只包含下一个节点的地址。 单链表节点的定义 单链表的节点定义一般包括两个部分:数据域和指针域。数据域存放节点的数据,指针域存放下一个节点的地址。 以下是单链表节点的定义: typedef struct node { i…

    数据结构 2023年5月17日
    00
  • c++ 数据结构map的使用详解

    c++ 数据结构map的使用详解 什么是map map是C++ STL中提供的一种用以存储键值对(key-value)的容器。它能够以平均O(log n)复杂度进行搜索、插入、删除操作,并且保持元素顺序,是一种比较高效的数据结构。 map的基本用法 定义map 定义map需要包含头文件<map>。 语法:map<key_type, valu…

    数据结构 2023年5月17日
    00
  • C语言数据结构之模式匹配字符串定位问题

    C语言数据结构之模式匹配字符串定位问题 什么是模式匹配字符串定位? 模式匹配字符串定位即在一个文本串中匹配一个模式串,并且返回模式串在文本串中第一次出现的位置。 例如,对于文本串“this is a test string”,我们想要匹配模式串“test”,我们期望得到的结果是第一次出现的位置为10。 KMP算法 算法思路 KMP算法是一种高效的字符串匹配算…

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