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

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

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

我的博客:yuanManGan

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

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

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

静态链表的认识

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

一部分是数据域

一部分是指针域

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

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

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

静态链表的实现

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

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

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

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


创建空链表

const int N = 1e5 + 10;

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

int id, h;

int main()
{

    return 0;
} 

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

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

头插

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

代码实现:

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

遍历链表打印

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

实现:

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

按值查找

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


const int N = 1e5 + 10;

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

int id, h;

int mp[N];

int main()
{

    return 0;
} 

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

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

就可以实现find函数了

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),大大的优化。

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

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

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

这里就是把h换成了p。

删除任意位后的数据

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

实现也很简单

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

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

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

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

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


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

相关文章:

  • 菜鸟带新鸟——基于EPlan2022的部件库制作
  • python 内存管理
  • MyBatis通过注解配置执行SQL语句原理源码分析
  • 递归读取指定目录下的文件
  • Pytorch | 利用NI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
  • Pytorch | 从零构建AlexNet对CIFAR10进行分类
  • HTTP常见异常状态码
  • Android Bootable Recovery 中的 `bspatch.cpp` 文件详解
  • Tauri 开源 - 从零打造一款跨端的 AI 笔记
  • ubuntu 网络管理
  • Clickhouse 集群配置
  • Linux系统卡顿排查
  • PostgreSql+Pgpool-II配置高可用集群(超详细)
  • scrapy实战之新浪新闻爬虫
  • Linux 批量查找与替换的常用命令
  • C++中的字符串实现
  • ACl访问控制列表
  • 高校就业管理:系统设计与实现的全流程分析
  • 如何写好一份科技报告
  • Textual Dataset Distillation via Language Model Embedding
  • 计算机视觉技术未来发展趋势:创新与变革共舞
  • MHA binlog server
  • 代码随想录day22 | 回溯算法理论基础 leetcode 77.组合 77.组合 加剪枝操作 216.组合总和III 17.电话号码的字母组合
  • 【蓝碳】基于GEE云计算、多源遥感、高光谱遥感技术、InVEST模型、PLUS模型的蓝碳储量估算;红树林植被指数计算及提取
  • vue中的css深度选择器v-deep 配合!important
  • 【MySQL】MySQL 官方安装包形式