静态链表C语言(非伪代码)

个人感觉用不到,当个了解知识吧,遇到再说....写了非常久,感觉是所有类型链表里面最难的!!接近花了接近半天,有很多逻辑还是比较绕的,写了静态链表才发现,C语言的指针真是个好东西!!!pS:双向静态链表不写了,真的脑子要炸开了.....

一、静态链表的 结点/链表

  • 结点与单向链表结点一致
  • 链表多了一个free游标指向下一个赋值的位置
  • 相较于动态链表,静态链表的结点/空间是固定好的,所以定义了一个MAX_SIZE表示空间量
typedef struct {
    int data;    // 数据域
    int next;    // 指针域(索引)
} ListNode;

typedef struct {
    ListNode nodes[MAX_SIZE]; // 节点数组
    int head;                 // 头节点的索引
    int len;                  // 当前链表的长度
    int free;                 // 游标,指向下一个空闲位置
} StaticLinkedList;

二、初始化静态链表

2.1、核心代码实现:

  • head置空,len置空,空闲结点置0
  • 将所有位置连接为一个空闲链表  相当于规划了一整块的连续内容空间来实现
  • 最后一个空闲节点指向 -1,表示没有更多空闲位置
//初始化静态链表
void Init_StaticLinkedList(StaticLinkedList* list) 
{
    list->head = -1; // 初始时链表为空,head为-1表示 无有效元素
    list->len = 0;
    list->free = 0;  // 空闲节点从数组的第0个元素开始

    for (int i = 0; i < MAX_SIZE - 1; i++) 
    {
        list->nodes[i].next = i + 1; // 将所有位置连接为一个空闲链表  相当于规划了一整块的连续内容空间来实现
    }
    list->nodes[MAX_SIZE - 1].next = -1; // 最后一个空闲节点指向-1,表示没有更多空闲位置
}

三、销毁链表

  • head=-1(头指针置空)
  • 长度置0
  • 游标置空(注意置为0,这样下次使用时,赋值仍然是以0开始)
//销毁链表
void Destroy_StaticLinkedList(StaticLinkedList* list) 
{
    list->head = -1;    //无有效元素,相当于头指针置空
    list->len = 0;      //长度置空
    list->free = 0;     //游标置空,相当与头指针next置空
}

四、创建节点

4.1、核心代码实现:

  • 因为在静态链表中不存在 开辟空间 这样的概念,所以创建节点 就是给数组中的(以游标作为下标的)元素元素赋值即可
  • 直接返回游标的值即可
  • 注意返回时还应该刷新一次游标的值,使得下一次游标的值合法
//创建节点
//因为在静态链表中不存在开辟空间这样概念,所以创建节点就是 给 数组中的元素赋值即可
int Malloc_Node(StaticLinkedList* list) 
{
    if (list->free == -1) 
    {
        printf("内存不足!\n");
        return -1;
    }

    int index = list->free; //  表明获取下一个 空闲位置的数组下标
    list->free = list->nodes[index].next;   //再规定一下我插入这个元素数组下标的游标
    return index;   //返回下标即可
}

4.2、算法图解:

五、释放节点

5.1、核心代码实现:

//删除链表中的节点后,将该节点归还给空闲链表(即恢复该节点可被再次使用的状态)
void Free_Node(StaticLinkedList* list, int index) 
{
    list->nodes[index].next = list->free;   // 将该节点的 next 指针指向当前空闲节点链表的头
    list->free = index;     //更新 free 指针,指向这个刚刚释放的节点
}

 5.2、算法图解:

ps:此时的节点3应该与1/2都无任何联系,图忘记改了...

  • 这样,节点 3 被成功归还到空闲链表中,且成为新的头节点。
  • 这个函数的作用类似于动态链表中的 free 函数,用于释放节点但不是释放内存,而是将节点放回空闲节点池中

 六、插入元素

6.1、核心代码实现

// 在链表的第i个位置插入一个元素
void Insert_StaticLinkedList(StaticLinkedList* list, int i, int value) 
{
    if (i < 0 || i > list->len) 
    {
        printf("插入失败,位置不合法!\n");
        return;
    }

    int newIndex = Malloc_Node(list); // 从空闲链表中取出一个下一个赋值节点的下标
    if (newIndex == -1) return; // 若分配失败,退出

    list->nodes[newIndex].data = value; // 设置新节点的值

    if (i == 0) 
    { // 头插法
        list->nodes[newIndex].next = list->head;    //让新节点指向头节点
        list->head = newIndex;      //让头节点指向新节点
    }
    else 
    {
        int current = list->head;   //定义一个迭代器指向头节点
        for (int j = 0; j < i - 1; j++) 
        {
            current = list->nodes[current].next;    //找到插入元素的前一个节点
        }
        list->nodes[newIndex].next = list->nodes[current].next;//让新的节点指向当前节点的后一个节点,
        list->nodes[current].next = newIndex;   //让当前节点指向新节点
    }
    list->len++;
}

6.2、算法图解

6.2.1、头插法

  • 创建一个节点(即获取游标节点下标index)给index下标的节点赋值
  • 更新index节点的next,使其指向头节点
  • 头节点移动到index上

 6.2.2、尾插法

  • 创建一个节点(即获取游标节点下标index)给index下标的节点赋值

  • 定义一个迭代器cur指向头节点,并且让它移动到要插入元素下标的前一个结点

  • 新结点index指向cur的下一个结点

  • 让cur指向index结点

ps:有小伙伴询问,3/4步骤是否可以调换??  答案当然是不行的

如果你先让cur去指向index的话,就会导致index无法找到它应该连接的下一个结点,也就是找不到结点4,因为此时2->next已经被修改成了7,自然就错啦!!!!

七、删除元素:

7.1、核心代码实现:

//删除元素
void Delete_StaticLinkedList(StaticLinkedList* list, int i) 
{
    if (i < 0 || i >= list->len) 
    {
        printf("删除失败,位置不合法!\n");
        return;
    }

    int toDelete;   //定义一个toDelete,用来释放和检索要删除的下标

    if (i == 0) //删除头节点
    {
        toDelete = list->head;  //让删除下标指向头节点
        list->head = list->nodes[toDelete].next;  //头节点往后移动一位
    }
    else 
    {
        int current = list->head;   //定义一个迭代器,指向头节点

        for (int j = 0; j < i - 1; j++) 
        {
            current = list->nodes[current].next;    //找到删除元素的前一个节点
        }

        toDelete = list->nodes[current].next; //让删除检索指向要删除的节点
        list->nodes[current].next = list->nodes[toDelete].next;//跃过删除节点
    }

    Free_Node(list, toDelete);
    list->len--;
}

7.2、算法图解

7.2.1、头删法

  • 定义一个删除迭代器toDelete ,并让其指向index=0 (用来释放和检索要删除的下标)
  • 让头节点移动到删除节点的next节点(即节点1,这样节点1就变成了首节点)
  • 释放toDelete所指向的节点

7.2.2、尾删法

  • 定义一个删除迭代器toDelete  (用来释放和检索要删除的下标)
  • 定义一个迭代器cur让它指向头节点,并且遍历到找到要删除元素的前一个结点
  • 让删除检索指向要删除的结点(cur->next)
  • 让cur的next越过toDelete指向toDelete的下一个结点
  • 释放toDelete结点

八、根据下标查找元素

// 根据下标查找节点
int Find_Index_StaticLinkedList(StaticLinkedList* list, int i) 
{
    if (i < 0 || i >= list->len) 
    {
        printf("查找失败,位置不合法!\n");
        return -1;
    }

    int current = list->head; // 从头节点开始

    for (int j = 0; j < i; j++) 
    {
        current = list->nodes[current].next; // 按照 next 索引遍历
    }
    return current; // 返回找到的节点索引

九、根据元素来查找元素

// 根据值查找节点
int Find_Value_StaticLinkedList(StaticLinkedList* list, int value) 
{
    int current = list->head; // 从头节点开始

    while (current != -1) // 当遍历到 -1 时,说明链表结束,
    { 
        if (list->nodes[current].data == value) 
        {
            return current; // 找到匹配值的节点,返回其索引
        }
        current = list->nodes[current].next; // 继续往下查找
    }
    return -1; // 没有找到匹配的值
}

十、遍历打印

//遍历打印
void Print_StaticLinkedList(StaticLinkedList* list) 
{
    int current = list->head;
    while (current != -1) 
    {
        printf("%d -> ", list->nodes[current].data);
        current = list->nodes[current].next;
    }
    printf("NULL\n");
}

十一、完整代码实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>

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

typedef struct {
    int data;    // 数据域
    int next;    // 指针域(索引)
} ListNode;

typedef struct {
    ListNode nodes[MAX_SIZE]; // 节点数组
    int head;                 // 头节点的索引
    int len;                  // 当前链表的长度
    int free;                 // 游标,指向下一个空闲位置
} StaticLinkedList;

//初始化静态链表
void Init_StaticLinkedList(StaticLinkedList* list) 
{
    list->head = -1; // 初始时链表为空,head为-1表示 无有效元素
    list->len = 0;   
    list->free = 0;  // 空闲节点从数组的第0个元素开始

    for (int i = 0; i < MAX_SIZE - 1; i++) 
    {
        list->nodes[i].next = i + 1; // 将所有位置连接为一个空闲链表  相当于规划了一整块的连续内容空间来实现
    }
    list->nodes[MAX_SIZE - 1].next = -1; // 最后一个空闲节点指向 -1,表示没有更多空闲位置
}

//销毁链表
void Destroy_StaticLinkedList(StaticLinkedList* list) 
{
    list->head = -1;    //无有效元素,相当于头指针置空
    list->len = 0;      //长度置空
    list->free = 0;     //游标置空,相当与头指针next置空
}

//创建节点
//因为在静态链表中不存在开辟空间这样概念,所以创建节点就是 给 数组中的元素赋值即可
int Malloc_Node(StaticLinkedList* list) 
{
    if (list->free == -1) 
    {
        printf("内存不足!\n");
        return -1;
    }

    int index = list->free; //  表明获取下一个 空闲位置的数组下标
    list->free = list->nodes[index].next;   //再规定一下我插入这个元素数组下标的游标
    return index;   //返回下标即可
}

//释放链表中的节点后,将该节点归还给空闲链表(即恢复该节点可被再次使用的状态)
void Free_Node(StaticLinkedList* list, int index) 
{
    list->nodes[index].next = list->free;   // 将该节点的 next 指针指向当前空闲节点链表的头
    list->free = index;     //更新 free 指针,指向这个刚刚释放的节点
}
//这样,节点 3 被成功归还到空闲链表中,且成为新的头节点。
//这个函数的作用类似于动态链表中的 free 函数,用于释放节点但不是释放内存,而是将节点放回空闲节点池中。


// 在链表的第i个位置插入一个元素
void Insert_StaticLinkedList(StaticLinkedList* list, int i, int value) 
{
    if (i < 0 || i > list->len) 
    {
        printf("插入失败,位置不合法!\n");
        return;
    }

    int newIndex = Malloc_Node(list); // 从空闲链表中取出一个下一个赋值节点的下标
    if (newIndex == -1) return; // 若分配失败,退出

    list->nodes[newIndex].data = value; // 设置新节点的值

    if (i == 0) 
    { // 头插法
        list->nodes[newIndex].next = list->head;    //让新节点指向头节点
        list->head = newIndex;      //让头节点指向新节点
    }
    else 
    {
        int current = list->head;   //定义一个迭代器指向头节点
        for (int j = 0; j < i - 1; j++) 
        {
            current = list->nodes[current].next;    //找到插入元素的前一个节点
        }
        list->nodes[newIndex].next = list->nodes[current].next;//让新的节点指向当前节点的后一个节点,
        list->nodes[current].next = newIndex;   //让当前节点指向新节点
    }
    list->len++;
}

//删除元素
void Delete_StaticLinkedList(StaticLinkedList* list, int i) 
{
    if (i < 0 || i >= list->len) 
    {
        printf("删除失败,位置不合法!\n");
        return;
    }

    int toDelete;   //定义一个toDelete,用来释放和检索要删除的下标

    if (i == 0) //删除头节点
    {
        toDelete = list->head;  //让删除下标指向头节点
        list->head = list->nodes[toDelete].next;  //头节点往后移动一位
    }
    else 
    {
        int current = list->head;   //定义一个迭代器,指向头节点

        for (int j = 0; j < i - 1; j++) 
        {
            current = list->nodes[current].next;    //找到删除元素的前一个节点
        }

        toDelete = list->nodes[current].next; //让删除检索指向要删除的节点
        list->nodes[current].next = list->nodes[toDelete].next;//跃过删除节点
    }

    Free_Node(list, toDelete);
    list->len--;
}

// 根据下标查找节点
int Find_Index_StaticLinkedList(StaticLinkedList* list, int i) 
{
    if (i < 0 || i >= list->len) 
    {
        printf("查找失败,位置不合法!\n");
        return -1;
    }

    int current = list->head; // 从头节点开始

    for (int j = 0; j < i; j++) 
    {
        current = list->nodes[current].next; // 按照 next 索引遍历
    }
    return current; // 返回找到的节点索引
}

// 根据值查找节点
int Find_Value_StaticLinkedList(StaticLinkedList* list, int value) 
{
    int current = list->head; // 从头节点开始

    while (current != -1) // 当遍历到 -1 时,说明链表结束,
    { 
        if (list->nodes[current].data == value) 
        {
            return current; // 找到匹配值的节点,返回其索引
        }
        current = list->nodes[current].next; // 继续往下查找
    }
    return -1; // 没有找到匹配的值
}


//遍历打印
void Print_StaticLinkedList(StaticLinkedList* list) 
{
    int current = list->head;
    while (current != -1) 
    {
        printf("%d -> ", list->nodes[current].data);
        current = list->nodes[current].next;
    }
    printf("NULL\n");
}

int main() 
{
    StaticLinkedList list;

    Init_StaticLinkedList(&list);

    Insert_StaticLinkedList(&list, 0, 10);
    Insert_StaticLinkedList(&list, 1, 20);
    Insert_StaticLinkedList(&list, 2, 30);
    Insert_StaticLinkedList(&list, 3, 40);

    printf("Original List:\n");
    Print_StaticLinkedList(&list);

    // 根据下标查找
    int index = Find_Index_StaticLinkedList(&list, 2);
    if (index != -1) 
    {
        printf("Index 2 节点的值是: %d\n", list.nodes[index].data);
    }

    // 根据值查找
    int found = Find_Value_StaticLinkedList(&list, 30);
    if (found != -1) 
    {
        printf("找到值为 30 的节点,位置是: %d\n", found);
    }
    else 
    {
        printf("没有找到值为 30 的节点\n");
    }

    system("pause");
    return 0;
}

链表系列全部结束,后面还会有栈/队列奥,欢迎大家勘误

静态链表是一种特殊的线性数据结构,它的节点是在程序开始时就分配好内存的,而不是动态地随着元素增加而增加。在C语言中,我们可以创建一个静态链表节点结构体,并通过全局变量或数组的形式预先定义节点的数量。 下面是一个简单的静态链表初始化的示例,假设我们有一个名为`Node`的结构体,包含`data`和`next`两个成员(`next`指向下一个节点的指针),并且已经定义了一个大小为5的节点数组: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构 typedef struct Node { int data; struct Node* next; // 指向下一个节点的指针 } Node; // 初始化静态链表 void initializeStaticList(Node list[], int size) { for (int i = 0; i < size; i++) { // 对于每个节点,将next初始化为NULL list[i].next = NULL; // 如果是第一个节点,还需要设置data if (i == 0) list[i].data = i + 1; else list[i].data = 0; // 示例中仅用于演示,实际应用可能需要其他值 } } // 测试静态链表 int main() { Node staticList[5]; initializeStaticList(staticList, 5); for (int i = 0; i < sizeof(staticList)/sizeof(Node); i++) { printf("Node %d: Data = %d, Next = %p\n", i, staticList[i].data, staticList[i].next); } return 0; } ``` 在这个例子中,`initializeStaticList`函数负责初始化每个节点的`next`指针,并设置第一个节点的数据。注意,由于静态链表是固定的,如果节点数据需要动态填充,你应该在初始化函数之外添加相应逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值