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

【洛谷】用两个数组实现静态单链表、静态双向链表,排队顺序

文章目录

  • 链表的静态实现
    • 单链表的模拟实现
      • 定义单链表
      • 头插
      • insert
      • erase
      • 打印链表
      • 查找
      • 单链表源码
    • 双向链表的模拟实现
      • 定义双向链表
      • 头插
      • 任意位置之后插入
      • 任意位置之前插入
      • erase
      • 打印链表
      • find
      • 双向链表源码
    • 循环链表
  • 排队顺序
    • 题目描述
    • 题目解析
    • 代码


链表的静态实现

动态实现是通过 new 申请结点,然后通过 delete 释放结点的形式构造链表。这种实现⽅式最能体现链表的特性;
静态实现是利⽤两个数组配合来模拟链表。第⼀次接触可能⽐较抽象,但是它的运⾏速度很快,在算法竞赛中会经常会使⽤到,虽然空间消耗大,但是算法竞赛中时间效率更重要

单链表的模拟实现

我们要把数组同一下标的两个数据打包看成一个整体,用来存储链表的其中一个结点的信息。这个next数组的作用就是用来模拟list的指定位置O1插入删除,比如下面我们想在B、C结点之间插入一个C,如果只用elem一个数组的话就需要挪动数据,但是如果有next数组的话我们就可以将D直接尾插,然后通过修改next数组的数据达到和list一样的效果。
静态单链表的尾插、尾删、任意位置插入删除操作时间复杂度太高,我们就不实现了,因为这里实现静态单链表的目的就是看中了它效率高,所以这里我们实现一部分效率高的操作。

在这里插入图片描述

定义单链表

const int N = 1e5 + 10;
int e[N], ne[N], h, id;

e[N]为存放数据的数组,ne[N]为存放指针也就是指向下一数据下标的数组,若对应数据的ne[N]数组的值为零,则代表该位置为尾结点,h一直指向头结点,id跟随插入的数据而移动,它们俩的值默认为0,所以直接把它们定义在全局就不用初始化了,全局int变量定义在全局默认为0。

头插

在这里插入图片描述

void push_front(int x)
{id++;//放入数据e[id] = x;//修改指针ne[id] = ne[h];  //新节点指向原头结点ne[h] = id;      //哨兵位指向新头结点
}

insert

//pos后插入
void insert(int pos, int x)
{id++;e[id] = x;mp[x] = id;ne[id] = ne[pos];ne[pos] = id;
}

insert只能从指定位置后面插入,也就是物理结构的数组下标位置pos,不能在某个值后面插入,因为拿到某个值后也要通过这个值去找对应的下标才能实现插入操作。

erase

删除操作也很简单,把当前位置结点指向的下标改为当前位置的下一位置的结点指向的下标就行了,但是要注意当pos结点是尾结点时不能删除,因为会造成两个结点指向同一个结点,形成环形链表。
删除操作的pos也是物理结构的数组下标位置pos。

//删除pos位置之后的数据
void erase(int pos)
{//当pos位置结点不是单链表的尾结点时才能执行删除操作if(ne[pos])ne[pos] = ne[ne[pos]];
}

打印链表

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

i从头结点开始遍历打印,当i为0即i指向哨兵位时停止循环打印。

查找

法一:

这里查找数据一定要按链表的逻辑顺序来查找,不能直接遍历e[N]数组,因为e[N]数组里有可能会存在我们已经删除了的元素。

在这里插入图片描述

int find(int x)
{for (int i = ne[h]; i; i = ne[i]){if (x == e[i]){return i;}}return 0;
}

法二:
在这里插入图片描述

首先创建一个数组mp,登记数据存储的位置到mp,方便find直接通过数据的值return它的下标,然后在每次插入数据时把值登记到mo数组,因为数组是在全局创建的,会自动把mp数组的值初始化为0,那么如果find的目标值不存在就会返回0。

int mp[N];   //把数据的值当作mp数组的下标,mp存的值为数据的下标void push_front(int x)
{id++;//放入数据e[id] = x;mp[x] = id;      //登记数据存储的位置到mp,方便直接return//修改指针ne[id] = ne[h];  //新节点指向原头结点ne[h] = id;      //哨兵位指向新头结点
}int find(int x)
{return mp[x];
}

单链表源码

using namespace std;
#include <iostream>const int N = 1e5;
int e[N], ne[N], h, id;
int mp[N];   //把数据的值当作mp数组的下标,mp存的值为数据的下标void push_front(int x)
{id++;//放入数据e[id] = x;mp[x] = id;//修改指针ne[id] = ne[h];  //新节点指向原头结点ne[h] = id;      //哨兵位指向新头结点
}void print()
{for (int i = ne[h]; i; i = ne[i]){cout << e[i] << " ";}cout << endl;
}//int find(int x)
//{
//	for (int i = ne[h]; i; i = ne[i])
//	{
//		if (x == e[i])
//		{
//			return i;
//		}
//	}
//	return 0;
//}int find(int x)
{return mp[x];
}//pos后插入
void insert(int pos, int x)
{id++;e[id] = x;mp[x] = id;ne[id] = ne[pos];ne[pos] = id;
}//删除pos位置之后的数据
void erase(int pos)
{//当pos位置结点不是单链表的尾结点时才能执行删除操作if (ne[pos] != 0){   //清空mp里pos下一个位置的值mp[e[ne[pos]]] = 0;ne[pos] = ne[ne[pos]];}
}int main()
{push_front(3);push_front(2);push_front(1);print();push_front(7);print();push_front(8);print();push_front(9);print();cout << find(1) << endl;cout << find(9) << endl;cout << find(4) << endl;insert(5, 100);print();insert(1, 200);print();erase(1);print();erase(5);print();//push_front(1);//push_front(2);//push_front(3);//push_front(4);//push_front(5);//print();//erase(1);//   print();//   erase(4);//   print();return 0;
}

双向链表的模拟实现

在这里插入图片描述

定义双向链表

const int N = 1e5;
int e[N], ne[N], pre[N], id, h;

头插

在这里插入图片描述

注意:指针1最后修改。

void push_front(int x)
{id++;e[id] = x;ne[id] = ne[h];pre[id] = h;pre[ne[h]] = id;ne[h] = id;
}

任意位置之后插入

这里这是在物理存储位置的下标插入。

//pos之后插入
void insert(int pos, int x)
{id++;e[id] = x;mp[x] = id;ne[id] = ne[pos];pre[id] = pos;pre[ne[pos]] = id;ne[pos] = id;
}

任意位置之前插入

注意插入删除都要登记mp。

//pos之前插入
void insert_back(int pos, int x)
{id++;e[id] = x;mp[x] = id;ne[id] = pos;pre[id] = pre[pos];ne[pre[pos]] = id;pre[pos] = id;
}

erase

注意插入删除都要登记mp。

//删除任意位置元素
void erase(int pos)
{mp[e[pos]] = 0;ne[pre[pos]] = ne[pos];pre[ne[pos]] = pre[pos];
}

打印链表

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

find

这里为了效率更高,我们就用创建mp数组的方法了。

int mp[N];void push_front(int x)
{id++;e[id] = x;mp[x] = id;ne[id] = ne[h];pre[id] = h;pre[ne[h]] = id;ne[h] = id;
}int find(int x)
{return mp[x];
}

双向链表源码

using namespace std;
#include <iostream>const int N = 1e5 + 10;
int e[N], ne[N], pre[N], id, h;
int mp[N];void push_front(int x)
{id++;e[id] = x;mp[x] = id;ne[id] = ne[h];pre[id] = h;pre[ne[h]] = id;ne[h] = id;
}//pos之后插入
void insert(int pos, int x)
{id++;e[id] = x;mp[x] = id;ne[id] = ne[pos];pre[id] = pos;pre[ne[pos]] = id;ne[pos] = id;
}//pos之前插入
void insert_back(int pos, int x)
{id++;e[id] = x;mp[x] = id;ne[id] = pos;pre[id] = pre[pos];ne[pre[pos]] = id;pre[pos] = id;
}//删除任意位置元素
void erase(int pos)
{mp[e[pos]] = 0;ne[pre[pos]] = ne[pos];pre[ne[pos]] = pre[pos];
}void print()
{for (int i = ne[h]; i; i = ne[i]){cout << e[i] << " ";}cout << endl; 
}int find(int x)
{return mp[x];
}int main()
{push_front(5);print();push_front(6);print();push_front(7);print();push_front(8);print();push_front(9);print();cout << find(7) << endl;cout << find(9) << endl;cout << find(10) << endl;insert(2, 100);print();insert(1, 200);print();insert(1, 500);print();insert(4, 300);print();insert_back(5, 800);print();insert_back(3, 900);print();erase(3);print();erase(5);print();return 0;
}

循环链表

我们之前的单链表最后的尾结点的指向0也就是指向哨兵位的,所以先前的单链表其实就是一个循环链表,嘻嘻,所以循环链表就不用实现啦!

排队顺序

题目描述

在这里插入图片描述

题目解析

这道题很好理解,我们可以用数组模拟链表实现,首先我们把第二行数据用一个vector来保存,注意从下标1开始保存,这样可以让小朋友的编号与下标对应,保存好后用一个for循环按找链表顺序输出结果就行了,i为输出的小朋友的编号,首先输出第一个小朋友的编号,这个输出的小朋友的编号就是下一个要输出小朋友编号在数组里的下标,最后当编号为0时跳出循环。

代码

using namespace std;
#include <iostream>
#include <vector>
#include <list>
const int N = 2e6 + 10;
vector<int> v(N);int main()
{	
int n, h;	
cin >> n;	
for (int i = 1; i <= n; i++)	
{		
cin >> v[i];	
}
cin >> h;		
//若i为1跳出循环	
for (int i = h; i; i = v[i])	
{		
cout << i << " ";	
}return 0;
}

以上就是小编分享的全部内容了,如果觉得不错还请留下免费的关注和收藏如果有建议欢迎通过评论区或私信留言,感谢您的大力支持。
一键三连好运连连哦~~

在这里插入图片描述

http://www.lryc.cn/news/595745.html

相关文章:

  • 基于JAVA实现基于“obj--html--pdf” 的PDF格式文本生成
  • Android perfetto 工具使用
  • 使用vue-pdf-embed发现某些文件不显示内容
  • Stirling PDF本地PDF编辑器:cpolar内网穿透实验室第628个成功挑战
  • css3地球转动模型(动态数据)
  • vue3实现高性能pdf预览器功能可行性方案及实践(pdfjs-dist5.x插件使用及自定义修改)
  • fuse低代码工作流平台概述【已开源】-自研
  • 面试题:sql题一
  • Elastic Cloud 简化版:GCP Marketplace
  • 【Java SE】Object类
  • 行业分类表sql
  • Axios Token 设置示例
  • OEC 刷机Armbain 25.05后配置说明
  • Java 网络编程详解:从基础到实战,彻底掌握 TCP/UDP、Socket、HTTP 网络通信
  • ClearML库详解:从实验跟踪到模型部署的全流程管理
  • 网宿安全发布《2024年度网络安全态势报告》:AI驱动攻防升维,体系化主动安全成破局关键
  • ADA4522-2ARMZ-R7 ADI亚德诺 双通道零漂移运算放大器 工业高精度测试设备应用
  • WAF 防护与漏洞扫描联动:让安全防御更精准高效
  • Linux——进程间通信,匿名管道,进程池
  • 网络初级安全第三次作业
  • C++引用折叠
  • PHP与Web页面交互:从基础表单到AJAX实战
  • 【bug】ubuntu20.04 orin nx Temporary failure resolving ‘ports.ubuntu.com‘
  • 【测试开发】---Bug篇
  • Kafka监控体系搭建:基于Prometheus+JMX+Grafana的全方位性能观测方案
  • lspci/setpci用法小结
  • 《Webpack热更新瓶颈突破:全链路优化指南》
  • C++性能优化擂台技术文章大纲
  • web3.0怎么入局
  • MySql 运维性能优化