首页 > 其他分享 >数据结构合集

数据结构合集

时间:2023-03-23 19:23:48浏览次数:45  
标签:cout int cin 链表 队列 数据结构 合集 op

链表

链表是一种本身并不常用的数据结构。
然而其衍生出的许多数据结构如块状链表链式前项星等却十分甚至九分的常用。

链表

简介

顾名思义,链表就是使用链连接在一起的数组。
可以实现\(O(1)\)的插入,\(O(1)的删除\)和\(O(n)\)的查询。

实现

我们使用一个结构体来实现链表:

struct point{
int val,to;
}

其中\(val\)表示节点的存值,\(to\)表示索引的链。
为了防止无限遍历,我们通常在链表的末端添加一个\(to=-1\)(特殊值)来结束输入。
遍历时,我们跳\(to\)即可。
删除时,我们用这个节点的链连给下一个节点的链。
插入时,我们先动态开点,再将新节点的链连给下一节点,最后用该节点的链连给新节点。
双向链表同理,这里略过

例题

以下是一个例题:
Vessels
我们考虑建立一个链表来维护每个沙漏,当沙漏装满了之后,就无法承受更多的水,删除这个沙漏即可。
分类讨论:
\(1.\)如果删除:\(O(1)\)均摊。
\(2.\)如果不删除:\(O(1)\)。
综上,总复杂度为\(O(m)\)。
代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
int n,m;//同题意 
int a[N];//初始容量
struct point{
	int val,to;
}p[N];
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		p[i].val=a[i];
		if(i==n)
		p[i].to=-1;
		else
		p[i].to=i+1;
	}
	cin>>m;
	while(m--)
	{
		int op;
		cin>>op;
		if(op==1)
		{
			int x,y;
			cin>>x>>y;
			if(p[x].val>=y)
			{
				p[x].val-=y;
				continue;
			}
			else
			{
				y-=p[x].val;
				p[x].val=0;
			}
			while(p[x].to!=-1&&y!=0)
			{
				if(p[p[x].to].val<=y)
				{
					y-=p[p[x].to].val;
					p[p[x].to].val=0;
					int ox=x;
					x=p[x].to;
					p[ox].to=p[x].to;
				}
				else
				{
					p[p[x].to].val-=y;
					break;
				}
			}
		}
		else
		{
			int x;
			cin>>x;
			cout<<a[x]-p[x].val<<'\n';
		}
	}
	return 0;
}

块状链表

简介

我们知道,链表拥有\(O(1)\)的插入,\(O(1)的删除\)和\(O(n)\)的查询。
可\(O(n)\)的查询,实在太大了,有没有办法优化呢?
于是,块状链表诞生了。
它十分巧妙的将分块与链表结合。用链表形式连接每一个块。使用合并与分裂维护。实现\(O(\sqrt n )\)的插入,\(O(\sqrt n)的删除\)和\(O(\sqrt n)\)的查询。
最重要的是:
它有\(STL\)啊!!!

实现

块状链表的实现代码冗长,但是我们可以使用\(STL\ rope\)实现。
引用:

#include<ext/rope> 
using namespace __gnu_cxx;
rope<type>x;

函数:
\(a.substr(pos,x)\):返回一个\(rope\)类型,而且等于\(a[pos~(pos+x-1)]\),且两者互不相干。

\(a.erase(pos,x)\)删除\(a[pos~(pos+x-1)]\),并且把两端拼至一起。

\(a.at(x)\)返回\(a[x]\)(也可以直接索引下标)

\(a.insert(pos,char)\)在\(pos\)位置插入一个字符或者字符数组(\(int\)也可以)。

\(a.replace(pos,x,char)\)把\(a[pos~(pos+x-1)]\)替换为\(char\)(可以是字符数组也可以是\(int\))。

例题

块状链表在实现平衡树和主席树上很有建树。
以下是有关主席树的例题。(可以暴力72分)
P3919 【模板】可持久化线段树 1(可持久化数组)
代码:

#include<bits/stdc++.h>
#include<ext/rope> 
using namespace std;
using namespace __gnu_cxx;
const int N=1e6+100;
int n,m;
int a[N];
int l;
rope<int>p[N];
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		p[0].push_back(a[i]);
	}
	while(m--)
	{
		int w,op;
		cin>>w>>op;
		if(op==1)
		{
			int loc,val;
			cin>>loc>>val;
			p[++l]=p[w];
			p[l].replace(loc-1,1,val);
		}
		else
		{
			int loc;
			cin>>loc;
			p[++l]=p[w];
			cout<<p[l].at(loc-1)<<'\n';
		}
	}
	return 0;
}

记录:
link

简介

栈是一种后进先出的数据结构。可以说是数据结构中最为朴实的了。

实现

栈的实现有两种。
一:
一是可以使用\(STLstack\)实现。
\(stack\)的函数有以下几种:
\(push(x):\)向栈中加入一个数 \(x\)。
\(pop():\)将栈顶弹出。
\(query():\)输出栈顶元素。
\(size():\)输出此时栈内元素个数。
二:
二是手写栈。
只需要一个栈顶指针\(l\)。
以及数组\(z\)即可实现。

模板

B3614 【模板】栈

#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N=1e6+100;
int l,t,q;
ull a[N];
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>t;
	while(t--)
	{
		l=0;
		cin>>q;
		while(q--)
		{
			string s;
			cin>>s;
			if(s=="push")
			{
				ull x;
				cin>>x;
				a[++l]=x;
			}
			if(s=="pop")
			{
				if(l==0)
				cout<<"Empty"<<'\n';
				else
				l--;
			}
			if(s=="query")
			{
				if(l==0)
				cout<<"Anguei!"<<'\n';
				else
				cout<<a[l]<<'\n';
			}
			if(s=="size")
			{
				cout<<l<<'\n';
			}
		}
	}
	return 0;
}

单调栈

简介

单调栈旨在维护前缀的后缀最值。

实现

单调栈的实现旨在维护一个储存前缀的后缀最值的栈。
当新的元素破坏了最值之后,弹出被破坏的值。
任在栈内的元素即为当前前缀的后缀随值。

模板

B3666 求数列所有后缀最大值的位置

#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
int n;
ull a[1000001]; 
ull ans;
stack<int>z;
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		while(z.size()!=0&&a[i]>=a[z.top()])
		{
			ans^=z.top();
			z.pop();
		}
		z.push(i);
		ans^=i;
		cout<<ans<<endl;
	}
	return 0;
}

队列

队列

简介

队列是一种非常简单的数据结构,本质上是一个先进先出的数组。

实现

队列的实现十分甚至九分的简单。
我们使用\(STL\ queue\)。

queue<type>q;
q.push(x);//入队
q.pop(x);//出队
q.front();查询队首
q.size();查询队列元素数量

没了。

例题

代码:
B3616 【模板】队列
代码:

#include<bits/stdc++.h>
using namespace std;
queue<int>q;
int n;
int main()
{
	cin>>n;
	while(n--)
	{
		int op;
		cin>>op;
		if(op==1)
		{
			int x;
			cin>>x;
			q.push(x);
		}
		if(op==2)
		{
			if(q.size()!=0)
			q.pop();
			else
			cout<<"ERR_CANNOT_POP"<<'\n';
		}
		if(op==3)
		{
			if(q.size()!=0)
			cout<<q.front()<<'\n';
			else
			cout<<"ERR_CANNOT_QUERY"<<'\n';
		}
		if(op==4)
		{
			cout<<q.size()<<'\n';
		} 
	}
	return 0;
}

双端队列

简介

双端队列的特点是可以两边入队,两边出队。

实现

我们通常使用\(STLdeque\)实现。
该\(STL\)有以下函数:
\(push\_back(x):\)在双端队列中从尾部插入一个元素 \(x\);
\(pop\_back():\)在双端队列中从尾部弹出一个元素。
\(push\_front(x):\)在双端队列中从头部插入一个元素 \(x\);
\(pop\_front():\)在双端队列中从头部弹出一个元素。
\(size():\)查询双端队列的元素个数;
\(front():\)查询双端队列的队首元素;
\(back():\)查询双端队列的队尾元素;
额外的:
如果只需使用上面的操作我们可以使用\(list\)代替\(deque\),速度更快,空间更小。(尽管他是双向链表)

模板

B3656 【模板】双端队列 1
代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
list<int>que[N];
int q;
int main() 
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>q;
	while(q--)
	{
		string op;
		cin>>op;
		if(op=="push_back")
		{
			int x,y;
			cin>>x>>y;
			que[x].push_back(y);
		}
		if(op=="pop_back")
		{
			int x;
			cin>>x;
			if(!que[x].empty())
			que[x].pop_back();
		}
		if(op=="push_front")
		{
			int x,y;
			cin>>x>>y;
			que[x].push_front(y);
		}
		if(op=="pop_front")
		{
			int x;
			cin>>x;
			if(!que[x].empty())
			que[x].pop_front();
		}
		if(op=="size")
		{
			int x;
			cin>>x;
			cout<<que[x].size()<<'\n';
		}
		if(op=="front")
		{
			int x;
			cin>>x;
			if(!que[x].empty())
			cout<<que[x].front()<<'\n';
		}
		if(op=="back")
		{
			int x;
			cin>>x;
			if(!que[x].empty())
			cout<<que[x].back()<<'\n';
		}
	}
	return 0;
}

单调队列

简介

单调队列是基于双端队列实现的数据结构,旨在维护区间后缀最值。
思路与单调栈类似,不同的是,因为维护的是区间,所以还要考虑左端点的范围限制,这里不再赘述。

模板

B3667 求区间所有后缀最大值的位置
(扶苏的模板就是好,总是能揭示算法本质。不像某k,某zhe的模板,一堆诈骗)

#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N=1e6+100;
int n,k;
ull a[N];
list<int>que;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=1;i<k;i++)
	{
		while(!que.empty()&&a[i]>=a[que.back()])
		que.pop_back();
		que.push_back(i);
	}
	for(int i=k;i<=n;i++)
	{
		if(!que.empty()&&que.front()<=i-k)
		que.pop_front();
		while(!que.empty()&&a[i]>=a[que.back()])
		que.pop_back();
		que.push_back(i);
		cout<<que.size()<<'\n';
	}
	return 0;
}

标签:cout,int,cin,链表,队列,数据结构,合集,op
From: https://www.cnblogs.com/everyday2023/p/17235202.html

相关文章

  • LevelDb-基本数据结构
    目录SliceArenaskiplist跳表本质时空复杂度插入,删除数据(如何维护索引)极端情况分析:不维护索引极端情况分析:每次插入都维护插入效率和查找效率取舍删除对比红黑树的优势leve......
  • 小红书去水印技巧合集(亲测有效!!!)
    有时候我们想换头像/微信背景墙了是不是第一时间想到的是去小红书逛逛,有时候看到有些博主分享的壁纸或者表情包等,忍不住的想保存下来,很多人应该还不知道如何下载吧,今天分......
  • 【数据结构】数组与广义表 - 笔记
    数组与广义表的一章相对更为简单,第1,2节都是很熟悉的数组相关定义、实现等。因此这篇博客的讲述重点放在第3节“特殊矩阵的压缩存储”中的“稀疏矩阵”的存储以及第4节“......
  • 数据结构笔记1 绪论 概念
    最近这一段时间在学习数据结构。感觉还是很值得的。有老大的话说就是这次投资成功了。开始决定学习的时候买了一本书《数据结构(C语言版)》相信大家都看过吧。是严蔚敏老师......
  • 数据结构笔记4 栈
    栈的定义和概念栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表。(1)通常称插入、删除的这一端为栈顶(Top),另一端称为栈底(Bottom)。(2)当表中没有元素......
  • log数据结构乱做
    SPOJGSS系列这个系列题目内容以维护区间最大子段和为主线。维护这个一般需要维护区间和,区间最大前缀,区间最大后缀,区间最大子段和四个信息。使用结构体封装和重载运算符可......
  • 数据结构算法学习前言
    数据结构算法学习写在前面:今天是2023-03-21,上一次接触算法是在公司导师的带领下,学习了数据结构算法,他一题一题讲给我的,但是当时却不太争气,并没有掌握太多,由于这段时间......
  • 牛客挑战赛67 B数据结构
    牛客挑战赛67B数据结构你有一个长度为n的字符串,其中包含'0','1','2'三种字符。问字符串中有多少个字串满足'0','1','2'三种字符数量相等。\(1<=n<=3e5\)一开始想了......
  • Android数据结构-SparseArray实现原理
    SparseArray家族SparseArray基于键值对存储数据,key为int,value为object,简单使用如下://声明SparseArray<String>sparseArray=newSparseArray<>();......
  • [Java SE]Java SE异常合集
    1概述2问题集Q1:JAVA应用程序启动时报"AfatalerrorhasbeendetectedbytheJavaRuntimeEnvironment:EXCEPTION_ACCESS_VIOLATION(0xc0000005)"问题描述#......