C语言之链表详解

这篇具有很好参考价值的文章主要介绍了C语言之链表详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、链表定义

二、链表分类

三、链表操作

四、单向链表

1.链表定义

2.插入操作

3.删除操作

4.修改操作

5.查找操作

五、双向链表

1.链表定义

2.插入操作

3.删除操作

4.修改操作

5.查找操作


一、链表定义

        链表是一种基本的数据结构,它由一系列节点组成,每个节点包含一个值和指向下一个节点的指针。链表的特点是可以动态添加和删除节点,而不需要预先知道数据的数量。与数组不同,链表中的节点不一定是连续的存储空间,因此可以有效地利用内存空间。

二、链表分类

链表可以分为三种类型:

  • 单向链表:每个节点只有一个指针指向下一个节点,最后一个节点的指针指向NULL。
  • 双向链表:每个节点有两个指针,分别指向上一个节点和下一个节点,可以在O(1)时间内实现向前和向后遍历。
  • 循环链表:在单向或双向链表的基础上,将最后一个节点的指针指向头节点,形成一个环。

三、链表操作

链表的操作包括插入、删除、查找、遍历等。

  • 插入操作:可以在链表头或尾插入节点,也可以在指定位置插入节点。
  • 删除操作:可以删除指定节点或按照值删除节点。
  • 查找操作:可以查找指定节点或按照值查找节点。
  • 遍历操作:可以遍历整个链表,输出每个节点的值或执行其他操作。

        链表的优点是可以动态添加和删除节点,因此非常适用于需要频繁插入和删除数据的场景。链表的缺点是访问操作的时间复杂度为O(n),而且需要额外的空间存储节点的指针,因此在需要频繁访问数据的场景中,效率可能不如数组。

        链表在计算机科学中有广泛的应用,例如操作系统中的进程链表、文件系统中的目录链表、图论中的邻接表等。在C语言中,链表常常用于实现动态内存分配、函数调用栈、多项式运算等问题。

四、单向链表

        单向链表是由若干个节点组成的数据结构,每个节点包含两个部分:数据域和指针域。数据域存储节点的数据,指针域存储下一个节点的地址。

c语言之链表,算法,链表,数据结构,算法,c语言

1.链表定义

单向链表定义如下:

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

2.插入操作

链表的插入操作可以在链表的头部、尾部或指定位置插入节点。具体实现如下:

// 在头部插入节点
struct ListNode* insertAtHead(struct ListNode* head, int val) {
    struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode));
    new_node->val = val;
    new_node->next = head;
    return new_node;
}

// 在尾部插入节点
struct ListNode* insertAtTail(struct ListNode* head, int val) {
    struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode));
    new_node->val = val;
    new_node->next = NULL;
    if (head == NULL) {
        return new_node;
    }
    struct ListNode* p = head;
    while (p->next != NULL) {
        p = p->next;
    }
    p->next = new_node;

    return head;
}

// 在指定位置插入节点
struct ListNode* insertAtIndex(struct ListNode* head, int index, int val) {
    int i = 0;

    struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode));
    new_node->val = val;
    if (index == 0) {
        new_node->next = head;
        return new_node;
    }
    struct ListNode* p = head;
    
    while (i < index - 1 && p != NULL) {
        p = p->next;
        i++;
    }
    if (p == NULL) {
        free(new_node);
        return head;
    }
    new_node->next = p->next;
    p->next = new_node;

    return head;
}

3.删除操作

链表的删除操作可以删除指定位置或指定值的节点。具体实现如下:

// 删除指定位置的节点
struct ListNode* deleteAtIndex(struct ListNode* head, int index) {
    int i = 0;
   
    if (head == NULL) {
        return NULL;
    }
    if (index == 0) {
        struct ListNode* temp = head;
        head = head->next;

        free(temp);
        return head;
    }
    struct ListNode* p = head;
    
    while (i < index - 1 && p != NULL) {
        p = p->next;
        i++;
    }

    if (p == NULL || p->next == NULL) {
        return head;
    }

    struct ListNode* temp = p->next;
    p->next = p->next->next;
    free(temp);

    return head;
}
// 删除指定值的节点
struct ListNode* deleteNode(struct ListNode* head, int val) {
    struct ListNode* p = head;
    struct ListNode* prev = NULL;

    while (p != NULL && p->val != val) {
        prev = p;
        p = p->next;
    }

    if (p == NULL) {
        return head;
    }

    if (prev == NULL) {
        head = head->next;
    } else {
        prev->next = p->next;
    }

    free(p);

    return head;
}

4.修改操作

链表的修改操作可以修改指定位置或指定值的节点的值。具体实现如下:

// 修改指定位置的节点的值
struct ListNode* modifyAtIndex(struct ListNode* head, int index, int val) {
    struct ListNode* p = head;
    int i = 0;

    while (i < index && p != NULL) {
        p = p->next;
        i++;
    }
    if (p == NULL) {
        return head;
    }
    p->val = val;

    return head;
}

// 修改指定值的节点的值
struct ListNode* modifyNode(struct ListNode* head, int old_val, int new_val) {
    struct ListNode* p = head;

    while (p != NULL && p->val != old_val) {
        p = p->next;
    }
    if (p == NULL) {
        return head;
    }
    p->val = new_val;

    return head;
}

5.查找操作

链表的查找操作可以查找指定位置或指定值的节点。具体实现如下:

// 查找指定位置的节点的值
int getValAtIndex(struct ListNode* head, int index) {
    struct ListNode* p = head;
    int i = 0;

    while (i < index && p != NULL) {
        p = p->next;
        i++;
    }
    if (p == NULL) {
        return -1;
    }

    return p->val;
}

// 查找指定值的节点的位置
int getIndexByVal(struct ListNode* head, int val) {
    struct ListNode* p = head;
    int i = 0;

    while (p != NULL && p->val != val) {
        p = p->next;
        i++;
    }
    if (p == NULL) {
        return -1;
    }

    return i;
}

        以上是链表的基本操作,实现时需要注意空指针和越界等问题。

五、双向链表

        双向链表和单向链表的不同在于每个节点有两个指针,分别指向前驱节点和后继节点。双向链表的优点是可以实现双向遍历和O(1)的删除操作,缺点是每个节点需要额外的一个指针。

c语言之链表,算法,链表,数据结构,算法,c语言

 1.链表定义

双向链表定义如下:

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

2.插入操作

双向链表的插入操作可以在指定位置前面或后面插入节点,具体实现如下:

// 在指定位置前面插入节点
struct ListNode* insertBefore(struct ListNode* head, int index, int val) {
    struct ListNode* p = head;
    int i = 0;

    while (i < index && p != NULL) {
        p = p->next;
        i++;
    }
    if (p == NULL) {
        return head;
    }

    struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
    node->val = val;
    node->prev = p->prev;
    node->next = p;
    if (p->prev != NULL) {
        p->prev->next = node;
    } else {
        head = node;
    }
    p->prev = node;

    return head;
}

// 在指定位置后面插入节点
struct ListNode* insertAfter(struct ListNode* head, int index, int val) {
    struct ListNode* p = head;
    int i = 0;

    while (i < index && p != NULL) {
        p = p->next;
        i++;
    }
    if (p == NULL) {
        return head;
    }

    struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
    node->val = val;
    node->prev = p;
    node->next = p->next;
    if (p->next != NULL) {
        p->next->prev = node;
    }
    p->next = node;

    return head;
}

3.删除操作

双向链表的删除操作可以删除指定位置或指定值的节点,具体实现如下:

// 删除指定位置的节点
struct ListNode* deleteAtIndex(struct ListNode* head, int index) {
    struct ListNode* p = head;
    int i = 0;

    while (i < index && p != NULL) {
        p = p->next;
        i++;
    }
    if (p == NULL) {
        return head;
    }
    if (p->prev != NULL) {
        p->prev->next = p->next;
    } else {
        head = p->next;
    }
    if (p->next != NULL) {
        p->next->prev = p->prev;
    }
    free(p);

    return head;
}

// 删除指定值的节点
struct ListNode* deleteNode(struct ListNode* head, int val) {
    struct ListNode* p = head;

    while (p != NULL && p->val != val) {
        p = p->next;
    }
    if (p == NULL) {
        return head;
    }
    if (p->prev != NULL) {
        p->prev->next = p->next;
    } else {
        head = p->next;
    }
    if (p->next != NULL) {
        p->next->prev = p->prev;
    }
    free(p);

    return head;
}

4.修改操作

双向链表的修改操作可以直接修改指定节点的值,具体实现如下:

// 修改指定位置的节点值
struct ListNode* updateAtIndex(struct ListNode* head, int index, int val) {
    struct ListNode* p = head;
    int i = 0;

    while (i < index && p != NULL) {
        p = p->next;
        i++;
    }
    if (p == NULL) {
        return head;
    }
    p->val = val;

    return head;
}

5.查找操作

双向链表的查找操作可以按位置或按值查找,具体实现如下:

// 按位置查找节点
struct ListNode* getNodeAtIndex(struct ListNode* head, int index) {
    struct ListNode* p = head;
    int i = 0;

    while (i < index && p != NULL) {
        p = p->next;
        i++;
    }

    return p;
}

// 按值查找节点
struct ListNode* getNodeByValue(struct ListNode* head, int val) {
    struct ListNode* p = head;

    while (p != NULL && p->val != val) {
        p = p->next;
    }

    return p;
}

以上是双向链表的增删改查操作的实现,可以根据需要进行调用。需要注意的是,在使用完链表后要及时释放内存,避免内存泄漏。

        如果觉得文章写的还不错,麻烦点赞,收藏加关注哦​!


        关于更多嵌入式C语言、FreeRTOS、RT-Thread、Linux应用编程、linux驱动等相关知识,关注公众号【嵌入式Linux知识共享】,后续精彩内容及时收看了解。

 文章来源地址https://www.toymoban.com/news/detail-528636.html

到了这里,关于C语言之链表详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构之链表

    头文件 自定义函数 主函数 效果图  

    2024年01月25日
    浏览(49)
  • 【数据结构】线性表之链表

    上一篇文章讲述了线性表中的顺序表,这篇文章讲述关于链表的定义、类别、实现、多种不同链表的优缺点和链表与顺序表的优缺点。 关于上一篇文章的链接:线性表之顺序表 链表是一种物理存储结构上 非连续、非顺序 的存储结构,数据元素的逻辑顺序是通过链表中的指针

    2024年02月05日
    浏览(53)
  • 【数据结构和算法初阶(C语言)】复杂链表(随机指针,随机链表的复制)题目详解+链表顺序表结尾

    目录  1.随机链表的复制 1.2题目描述  1.3题目分析 1.4解题: 2.顺序表和链表对比 2.1cpu高速缓存利用率 3.结语 一个长度为  n  的链表,每个节点包含一个额外增加的随机指针  random   该指针可以指向链表中的任何节点或空节点。        构造这个链表的  深拷贝 。 深拷贝

    2024年03月10日
    浏览(83)
  • 数据结构之链表练习与习题详细解析

    个人主页:点我进入主页 专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶 C语言刷题       数据结构初阶 欢迎大家点赞,评论,收藏。 一起努力,一起奔赴大厂。 目录 1.前言 2.习题解析 2.1习题一 2.2习题二 2.3习题三 2.4习题四 2.

    2024年02月05日
    浏览(43)
  • C/C++数据结构之链表题目答案与解析

    个人主页:点我进入主页 专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶 C语言刷题       数据结构初阶 欢迎大家点赞,评论,收藏。 一起努力,一起奔赴大厂。 目录 1.前言  2.题目解析 2.1 移除链表元素 2.2反转链表 2.3链表的中

    2024年02月05日
    浏览(58)
  • 【023】C/C++数据结构之链表及其实战应用

    💡 作者简介:专注于C/C++高性能程序设计和开发,理论与代码实践结合,让世界没有难学的技术。包括C/C++、Linux、MySQL、Redis、TCP/IP、协程、网络编程等。 👉 🎖️ CSDN实力新星,社区专家博主 👉 🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、

    2024年02月08日
    浏览(53)
  • 数据结构之链表 - 超详细的教程,手把手教你认识并运用链表

    顺序表只适合静态的查找和更新,不适合插入和删除元素, 因为在ArrayList中插入和删除元素时,由于需要将后序元素往前后者往后移动,所以时间复杂度会相当高,能达到O(N)。 为了解决这一问题,java 引入了 LinkedList(链表)。 链表是一种 逻辑上连续,物理上不连续 的存储结

    2024年02月09日
    浏览(58)
  • C++数据结构与算法详解:链表、栈、队列、树、二叉树和图结构的实现与应用

    链表是一种常见的数据结构由一系列节点按顺序连接而成,一般每个节点包含一个数据元素和一个指向下一个节点的引用。 链表有多种类型: 单向链表:每个节点只有一个指向下一个节点的引用 双向链表:每个节点有一个指向前一个节点和一个指向后一个节点的引用 循环链

    2024年02月04日
    浏览(47)
  • 数据结构(C语言):递归算法删除链表中所有值为x的结点

           这个标题为什么要叫“一个递归算法的诞生过程”呢?因为我在写这个算法的时候可谓一波三折,冲破重重Bug最终才得到了正确的算法。        所以在这里我和大家分享一下我写这段代码的整个过程。其中提到的一些问题大家可能写代码的时候也会遇到,所以建议

    2024年02月04日
    浏览(42)
  • 【数据结构与算法】顺序表与链表(单链表和双链表)超详解图示与源码。

                                                       大家好,今天我们来学习数据结构中的顺序表与链表!源码在最后附上 首先我们先来认识一下 顺序表 :                                       **如上图所示:很多人会以为数组就是顺序表,顺序表就是数组,这

    2024年02月21日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包