数据结构:静态链表( Static Linked List)及其实现

什么是静态链表?

静态链表是一种特殊的链表结构,它用数组来模拟链表的操作。你可以把它想象成一个"固定大小的链表",每个节点都存储在一个固定的位置(数组下标),并通过一个"游标"来指向下一个节点。

静态链表的特点是:

  1. 用数组实现:节点存储在数组中,数组的大小是固定的。

  2. 游标代替指针:用数组下标(游标)来模拟指针,指向下一个节点。

  3. 适合内存受限的场景:因为不需要动态分配内存,适合嵌入式系统等内存受限的环境。


静态链表的原理

静态链表的底层是一个数组,数组的每个元素(节点)包含两部分:

  1. 数据:存储实际的数据(比如数字、字符串等)。

  2. 游标:存储下一个节点的数组下标。

静态链表的核心思想是:

  • 用数组的下标来模拟指针,游标为 -1 表示链表的结束。

  • 需要一个额外的"空闲链表"来管理未使用的数组空间。


静态链表的基本操作

静态链表的基本操作包括:增、删、查、改。下面我们用大白话解释这些操作。

  1. 增加节点

    • 从空闲链表中分配一个节点,插入到链表的指定位置。

    • 修改前后节点的游标,使其指向新节点。

  2. 删除节点

    • 找到要删除的节点,修改前后节点的游标。

    • 将被删除的节点放回空闲链表。

  3. 查找节点

    • 从头节点开始,依次遍历每个节点,直到找到目标节点。
  4. 修改节点

    • 找到目标节点后,直接修改它的数据。

C 语言实现静态链表

下面是一个简单的静态链表实现代码,包含初始化、插入、删除、查找和打印功能。

复制代码
#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 10  // 静态链表的最大容量

// 定义静态链表节点结构体
typedef struct {
    int data;  // 数据
    int next;  // 游标,指向下一个节点的下标
} Node;

Node list[MAX_SIZE];  // 静态链表数组
int head;             // 头节点下标
int freeListHead;     // 空闲链表的头节点下标

// 初始化静态链表
void InitList() {
    // 初始化空闲链表
    for (int i = 0; i < MAX_SIZE - 1; i++) {
        list[i].next = i + 1;  // 每个节点指向下一个节点
    }
    list[MAX_SIZE - 1].next = -1;  // 最后一个节点的游标为 -1
    freeListHead = 0;              // 空闲链表的头节点下标为 0

    // 初始化静态链表
    head = -1;  // 头节点初始化为 -1
}

// 从空闲链表中分配一个节点
int MallocNode() {
    if (freeListHead == -1) {
        return -1;  // 空闲链表为空,分配失败
    }
    int newNodeIndex = freeListHead;       // 分配空闲链表的头节点
    freeListHead = list[freeListHead].next;  // 更新空闲链表的头节点
    return newNodeIndex;
}

// 将节点放回空闲链表
void FreeNode(int index) {
    list[index].next = freeListHead;  // 将节点插入空闲链表的头部
    freeListHead = index;             // 更新空闲链表的头节点
}

// 在链表头部插入节点
void InsertHead(int value) {
    int newNodeIndex = MallocNode();  // 分配一个新节点
    if (newNodeIndex == -1) {
        printf("链表已满,无法插入新节点\n");
        return;
    }

    list[newNodeIndex].data = value;  // 设置新节点的数据
    list[newNodeIndex].next = head;   // 新节点指向原来的头节点
    head = newNodeIndex;              // 更新头节点
}

// 删除链表中指定值的节点
void DeleteNode(int value) {
    int prev = -1;  // 前一个节点的下标
    int current = head;

    while (current != -1) {
        if (list[current].data == value) {
            if (prev == -1) {
                // 如果要删除的是头节点
                head = list[current].next;
            } else {
                // 如果要删除的是中间或尾节点
                list[prev].next = list[current].next;
            }
            FreeNode(current);  // 将被删除的节点放回空闲链表
            return;
        }
        prev = current;
        current = list[current].next;
    }

    printf("未找到要删除的节点\n");
}

// 查找链表中指定值的节点
int FindNode(int value) {
    int current = head;
    while (current != -1) {
        if (list[current].data == value) {
            return current;  // 找到目标节点
        }
        current = list[current].next;
    }
    return -1;  // 未找到目标节点
}

// 打印链表
void PrintList() {
    int current = head;
    printf("链表内容:");
    while (current != -1) {
        printf("%d -> ", list[current].data);
        current = list[current].next;
    }
    printf("NULL\n");
}

int main() {
    InitList();  // 初始化静态链表

    // 插入节点
    InsertHead(10);  // 在头部插入 10
    InsertHead(20);  // 在头部插入 20
    InsertHead(30);  // 在头部插入 30
    PrintList();     // 打印链表

    // 删除节点
    DeleteNode(20);  // 删除值为 20 的节点
    PrintList();     // 打印链表

    // 查找节点
    int index = FindNode(30);
    if (index != -1) {
        printf("找到节点:%d,下标:%d\n", list[index].data, index);
    } else {
        printf("未找到节点\n");
    }

    return 0;
}
静态链表的使用场景
  1. 内存受限的场景:比如嵌入式系统,无法动态分配内存。

  2. 固定大小的数据存储:比如实现一个固定大小的任务队列。

  3. 文件系统:某些文件系统用静态链表来管理磁盘块。


图片介绍

下面是一个静态链表的示意图:

复制代码
头节点下标:1
空闲链表头节点下标:3

数组下标:0    1    2    3    4    5
数据:   [_,   20,  10,  _,   _,   _]
游标:   [2,   2,   -1,  4,   5,   -1]
  • 数组下标表示节点的位置。

  • 数据存储实际的值,游标指向下一个节点的下标。

  • 空闲链表管理未使用的数组空间。


应用实例:任务调度器

任务调度器可以用静态链表实现:

  • 任务队列:用静态链表存储待执行的任务。

  • 空闲链表:管理未使用的任务槽。

  • 插入任务:从空闲链表中分配一个节点,插入到任务队列。

  • 删除任务:将已完成的任务放回空闲链表。


总结

静态链表是一种用数组模拟链表的数据结构,适合内存受限的场景。虽然它的灵活性不如动态链表,但在某些场景下非常高效。希望通过这篇文章,你能轻松掌握静态链表!

相关推荐
apocelipes2 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
CSharp精选营5 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假8 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠9 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦16 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
LDR00617 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
小小工匠17 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
Luminous.17 天前
C语言--day30
c语言·开发语言
玖玥拾17 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
謓泽17 天前
C语言不是语法,是通往机器的地图。
c语言·开发语言