当前位置: 首页 > article >正文

单链表-代码精简版

单链表核心知识详解

单链表是一种动态存储的线性数据结构,其特点是逻辑上连续,物理上非连续,每个节点包含数据域和指向下一个节点的指针域。以下是核心知识点与完整实现代码:

一、单链表的结构定义

单链表节点通过结构体自引用实现:

typedef int SLTDataType;  // 数据类型可自定义

typedef struct SListNode {
    SLTDataType data;      // 数据域
    struct SListNode* next; // 指针域,指向下一个节点
} SLTNode;

关键点

  • 头指针:指向第一个节点的地址(若链表为空则为NULL)。
  • 尾节点next指针为NULL,表示链表结束 。

二、单链表的增删改查操作实现

1. 创建新节点

SLTNode* SLTBuyNode(SLTDataType x) {
    SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
    newnode->data = x;
    newnode->next = NULL;
    return newnode;
}

作用:动态分配内存创建新节点,初始化数据和指针域。

2. 插入操作

(1) 头插法:在链表头部插入新节点

void SLTPushFront(SLTNode** pphead, SLTDataType x) {
    assert(pphead);
    SLTNode* newnode = SLTBuyNode(x);
    newnode->next = *pphead;
    *pphead = newnode;
}

逻辑:新节点的next指向原头节点,头指针更新为新节点。

(2) 尾插法:在链表尾部插入新节点

void SLTPushBack(SLTNode** pphead, SLTDataType x) {
    assert(pphead);
    SLTNode* newnode = SLTBuyNode(x);
    if (*pphead == NULL) {
        *pphead = newnode;
    } else {
        SLTNode* tail = *pphead;
        while (tail->next != NULL) {
            tail = tail->next;
        }
        tail->next = newnode;
    }
}

逻辑:若链表为空直接插入,否则遍历到尾部再插入。

(3) 指定位置后插入

void SLTInsertAfter(SLTNode* pos, SLTDataType x) {
    assert(pos);
    SLTNode* newnode = SLTBuyNode(x);
    newnode->next = pos->next;
    pos->next = newnode;
}

逻辑:将新节点插入到pos节点之后,时间复杂度为O(1)。

3. 删除操作

(1) 头删:删除链表头节点

void SLTPopFront(SLTNode** pphead) {
    assert(pphead && *pphead);
    SLTNode* tmp = *pphead;
    *pphead = (*pphead)->next;
    free(tmp);
}

逻辑:保存原头节点地址,头指针后移,释放原头节点。

(2) 尾删:删除链表尾节点

void SLTPopBack(SLTNode** pphead) {
    assert(pphead && *pphead);
    if ((*pphead)->next == NULL) { // 只有一个节点
        free(*pphead);
        *pphead = NULL;
    } else {
        SLTNode* prev = *pphead;
        while (prev->next->next != NULL) {
            prev = prev->next;
        }
        free(prev->next);
        prev->next = NULL;
    }
}

逻辑:遍历到倒数第二个节点,释放尾节点并置空指针。

(3) 删除指定节点

void SLTErase(SLTNode** pphead, SLTNode* pos) {
    assert(pphead && pos && *pphead);
    if (*pphead == pos) {
        *pphead = pos->next;
        free(pos);
    } else {
        SLTNode* prev = *pphead;
        while (prev->next != pos) {
            prev = prev->next;
        }
        prev->next = pos->next;
        free(pos);
    }
}

逻辑:若删除头节点直接处理,否则找到前驱节点调整指针。

4. 查找与修改

(1) 按值查找

SLTNode* SLTFind(SLTNode* phead, SLTDataType x) {
    SLTNode* cur = phead;
    while (cur) {
        if (cur->data == x) return cur;
        cur = cur->next;
    }
    return NULL;
}

逻辑:遍历链表直到找到匹配值的节点。

(2) 修改节点值

void ModifyNode(SLTNode* pos, SLTDataType new_val) {
    if (pos) pos->data = new_val;
}

逻辑:直接修改指定节点的数据域。

四、关键总结

  • 优点:动态内存分配,插入/删除时间复杂度为O(1)(已知位置时) 
     
  • 缺点:无法随机访问,需遍历查找,空间开销较大(指针占用内存) 
     
  • 应用场景:频繁插入删除、数据量动态变化的场景(如内存管理、任务调度)


http://www.kler.cn/a/579929.html

相关文章:

  • Pytorch 转向TFConv过程中的卷积转换
  • (每日一题) 力扣 860 柠檬水找零
  • 详解继承、多态、消息(对象间通信)和重载
  • A523 527 pk口控制
  • 【实战ES】实战 Elasticsearch:快速上手与深度实践-5.1.2基于Painless脚本的日志告警
  • GB/T4706.1-2024标准下的UV-C低压汞灯老化试验箱
  • [微服务设计]1_微服务
  • 循环链表 - 使用JavaScript封装
  • 原生iOS集成react-native (react-native 0.65+)
  • Unity Shader教程:Lambert漫反射实现原理解析
  • 通过数据集微调LLM后怎么调用
  • 【算法学习计划】动态规划 -- 路径问题
  • DeepSeek进阶应用(一):结合Mermaid绘图(流程图、时序图、类图、状态图、甘特图、饼图)
  • Git系列之git checkout
  • (枚举专题)组合数枚举
  • [MERN] 使用 socket.io 实现即时通信功能
  • 力扣-单调栈-84 柱状图中最大的矩形
  • Leetcode-整数反转
  • 每日学Java之一万个为什么
  • 分布式事务的原理