【数据结构】链表

1、链表介绍

​ 链表不同于顺序表,顺序表底层采用数组作为存储容器,需要分配一块连续且完整的内存空间进行使用,而链表不需要,它通过一个指针来连接各个分散的结点,形成了一个链状的结构,每个结点存放一个元素,以及一个指向下一个结点的指针,通过这样一个一个相连,最后形成了链表。

​ 它不需要申请连续的空间,只需要按顺序连接即可,虽然物理上可能不想邻,但在逻辑上依然是每个元素相邻存放的,这种结构就叫链表(单链表)

image-20240512182951354

​ 链表分为带头结点的链表和不带头结点的链表,戴头结点的链表就是会有一个头结点指向后续的整个链表,但头结点不存放数据。

image-20240512183052129

2、链表实现

带头结点的链表

typedef int E;      //定义别名

struct ListNode{
    E element;      //保存当前元素
    struct ListNode * next;     //指向下一个结点的指针
};

typedef struct ListNode * Node;     //结点指针起别名,可以直接作为表实现

初始化

void initList(Node head){
    head->next = NULL;  //头结点默认下一个为null
}

int main(){
    struct ListNode head;       //创建一个新的头结点,头结点不放任何元素,只做连接,连接整个链表
    initList(&head);    //进行初始化
}
3、链表的插入

图解

假设想要插入第二个

image-20240512191815953

我们可以修改新插入的结点的后继结点(也就是下一个结点)指向,指向原本在这个位置的结点

image-20240512191900901

接下来我们可以将前驱结点(也就是上一个结点)的后继结点指向修改为我们新插入的结点

image-20240512191958548

这样我们就成功插入了一个新的结点,现在新插入的结点到达了原本的第二个位置上

image-20240512192157579

代码实现

/**
 * 在链表的指定位置插入元素
 * @param head      头结点
 * @param element   要插入的元素
 * @param index     要插入的位置(从1开始)
 * @return          插入成功返回true,否则返回false
 */
bool insertList(Node head, E element, int index) {
    if (index < 1) return false; // 如果索引小于1,插入失败,因为头结点不存放元素

    while (--index) { // 通过遍历找到要插入位置的前一个结点
        head = head->next;
        if (head == NULL) return false; // 如果到达链表末尾仍未找到位置,插入失败
    }

    Node node = static_cast<Node>(malloc(sizeof(struct ListNode))); // 创建一个新结点
    if (node == NULL) return false; // 检查内存分配是否成功

    node->element = element; // 将要插入的元素赋值给新结点
    node->next = head->next; // 将新结点的指针指向后继结点
    head->next = node;       // 将前一个结点的指针指向新结点
    
    return true;
}
4、链表的删除

图解

如果想删除第二个结点

image-20240512194757165

其实可以将6的前继结点指向6的后继结点

image-20240512194850931

这样,在逻辑上来说,待删除结点其实已经不在链表中了,我们只需要释放掉待删除结点占用的内存空间就行了

代码实现

/**
 * 在链表中删除指定位置的节点
 * @param head  头结点
 * @param index 待删除节点的位置(从1开始)
 * @return      删除成功返回true,否则返回false
 */
bool deleteList(Node head, int index) {
    if (index < 1) return false; // 如果索引小于1,删除失败

    while (--index) { // 通过遍历找到待删除节点的前一个节点
        head = head->next;
        if (head == NULL) return false; // 如果到达链表末尾仍未找到位置,删除失败
    }

    if (head->next == NULL) return false; // 如果待删除节点的下一个节点为空,删除失败

    Node nodeTmp = head->next;      // 保存要删除的节点的指针

    head->next = head->next->next;  // 将前一个节点指向待删除节点的下一个节点

    free(nodeTmp); // 释放待删除节点的内存

    return true;
}
5、链表查询元素

代码实现

获取链表指定位置的元素值

/**
 * 获取链表指定位置的元素值
 * @param head  头结点
 * @param index 查找位置(从1开始)
 * @return      指向查找位置元素值的指针,如果位置无效或链表为空则返回NULL
 */
E *getList(Node head, int index) {
    if (index < 1) return NULL; // 如果索引小于1,返回NULL,表示位置无效

    do {
        head = head->next;
        if (head == NULL) return NULL; // 如果到达链表末尾仍未找到位置,返回NULL
    } while (--index);

    return &head->element; // 返回指向查找位置元素值的指针
}

查找对应元素的的位置

/**
 * 在链表中查找指定元素的位置
 * @param head    头结点
 * @param element 要查找的元素值
 * @return        返回指定元素在链表中的位置(从0开始计数),如果未找到则返回-1
 */
int findList(Node head, E element) {
    int i = 0; // 初始化计数器

    while (head) {
        if (head->element == element) return i;  // 如果找到指定元素,返回当前位置
        head = head->next; // 移动到下一个节点
        i++; // 增加计数器
    }

    return -1; // 如果未找到指定元素,则返回-1
}
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小林学习编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值