数据结构漫游记:静态链表的实现(CPP)

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let's go!

我的博客:yuanManGan

我的专栏:C++入门小馆 C言雅韵集 数据结构漫游记 闲言碎语小记坊

之前我们了解到动态链表的实现感兴趣的可以点点链接看一看

数据结构漫游记:动态链表的实现-CSDN博客

静态链表的认识

我们知道链表有两部分组成

一部分是数据域

一部分是指针域

我们动态实现链表时每次都会为新的链表申请空间,会搞得很麻烦代码量也很高,运行的时间也会很高,但静态实现完美的解决了这个问题。

我们是不是可以用空间很大的数组来分开存储指针和指针呢?

用数组的下标来找到每个结点。

静态链表的实现

定义两个数组分别为e和ne存储数据和指针。再用h指向哨兵位(指第一个不存储任何有效数据的结点),id指向最后一个结点。

这是有人就会问了你这个ne数组是不是多余了,我靠一个一个下标就能找到下一个元素啊,根本用不到ne数组啊

小伙子你想的太天真了,那你来实现下面这个呢?

如果你画出来这个结构会发现是A-》D-》E,C去哪里啦?每次C是无效数据,可能被删除了

创建空链表

cpp 复制代码
const int N = 1e5 + 10;

int ne[N], e[N]; // 创建两个很大的数组

int id, h;

int main()
{

    return 0;
} 

注意这里将数组放在全局变量有两个好处,一个是全局变量的内存更大,溢出问题更少出现;另一个是数组等变量不初始化放在main函数外会自动初始化为0。

这就实现了第一步创建空链表。

头插

无论是头插还是什么基本的思路都和动态的链表无二。我们需要先将新结点指向下一个结点,再将哨兵位的指针指向新节点。顺序不能搞错,不然就不能找到下一个结点了。

代码实现:

cpp 复制代码
void push_front(int x)
{
    id++;//指向下一个空的位置
    
    //处理新结点
    e[id] = x;//存储数据
    ne[id] = ne[h];
    
    //处理哨兵位
    ne[h] = id;
}

遍历链表打印

遍历链表的思路就是,定义一个指针cur令cur =necur直到cur等于0就结束了。也和动态链表的思路大差不差。

实现:

cpp 复制代码
void print()
{
    for (int i = ne[id]; i; i = ne[i])
    {
        cout << e[i] << " ->";
    }
    cout << endl << endl;
}

按值查找

实现按值查找一种方法就是遍历链表然后一个一个找,但这种做法时间复杂度是O(N)。这里我们可以先创建一个mp数组,以存储的数据为下标存储每个元素的地址。

cpp 复制代码
const int N = 1e5 + 10;

int ne[N], e[N]; // 创建两个很大的数组

int id, h;

int mp[N];

int main()
{

    return 0;
} 

然后在插入元素时储存元素的下标

cpp 复制代码
void push_front(int x)
{
    id++;//指向下一个空的位置
    
    //处理新结点
    e[id] = x;//存储数据
    ne[id] = ne[h];
    
    //处理哨兵位
    ne[h] = id;
    //标记新结点的位置
    mp[x] = id;
}

就可以实现find函数了

cpp 复制代码
int find(int x)
{
    /*int i = ne[h];
    while (i)
    {
	    if (e[i] == x) return i;
	    i = ne[i];
    }
    return 0;*/

    return mp[x];
}

注释部分是第一种方法。

这里有一个弊端,当存储两个相同的数时,mp数组就不知道存储谁的下标,当没有重复的数据时使用这个方法的时间复杂度是O(1),大大的优化。

在任意位置之后处插入数据

这个功能要传入的数据是某个位置的下标,如果传入的是数据,也得转化为下标来计算,这个位置之后的插入就和头插的执行过程差不多,这里就简单带过咯

cpp 复制代码
void push_front(int p,int x)
{
    id++;//指向下一个空的位置
    
    //处理新结点
    e[id] = x;//存储数据
    ne[id] = ne[p];
    
    //处理p位置
    ne[p] = id;
    //标记新结点
    mp[x] = id;
}

这里就是把h换成了p。

删除任意位后的数据

删除下一个位置就是将这个位置的下一个指针指向下下个元素。

实现也很简单

cpp 复制代码
void erase(int p)
{
    if(ne[p]) // 当 p 不是最后一个元素的时候
    {
        mp[e[ne[p]]] = 0; // 把标记清空

        ne[p] = ne[ne[p]];
    }
}

注意这里的p不能是最后一个元素哦!

这里不实现尾插,在任意位置之前插入,删除任意位置的原因很简单,相对与这些代码要复杂一点,并且时间复杂度都基本上是O(n),我们可以使用其他的数据结构来实现。

比如下期我要写的循环链表,请大家敬请期待!谢谢! ~

相关推荐
Yfhonier14 分钟前
6440. 极大连通图个数(DFS)
数据结构·算法·深度优先
Rnan-prince20 分钟前
从 Bitmap、BloomFilter到 Count-Min Sketch:三个数据结构,一条“用误差换空间“的演进线
数据结构·sketch·bitmap
旖旎夜光35 分钟前
LeetCode 974:和可被 K 整除的子数组(前缀和) —— 题解
数据结构·c++·算法·leetcode·前缀和
SelectDB技术团队1 小时前
StarRocks 适合做日志分析吗?
大数据·数据结构·后端·python·doris·日志分析·starrock
AI情绪识别开源1 天前
检信 ALLEMOTION OS 加密打包可执行程序 — 全面测试报告版本: v1.3功能测试 / 性能测试 /
开发语言·数据结构·人工智能·功能测试
伟大的车尔尼2 天前
贪心的概念
数据结构·算法·贪心
AI情绪识别开源2 天前
检信AI高一分班分科智选评估系统 v2.0测试报告
开发语言·数据结构·人工智能·科技
CoderYanger2 天前
A.每日一题:输入单词需要的最少按键次数 Ⅰ+Ⅱ
java·数据结构·算法·leetcode·面试
雪碧聊技术2 天前
KMP算法详解
数据结构
positive_zpc2 天前
进阶数据结构图——关键路径(四)
数据结构·图论·关键路径