用数组实现单、双链表。单调栈和单调队列 板子

算法题中 涉及链表 要用数组模拟 不然超时

单链表 head(清楚头指针的含义), e[], ne[], idx(只有插入操作会让idx++)

五个操作 初始化+ 头插头删+ k下标插 k下标删

 head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点
int head, e[N], ne[N], idx;

 初始化!!!!!!!!!!!!
void init()
{
    head = -1;
    idx = 0;
}

 在链表头插入一个数a  先右后左
void insert(int a) 
{
    e[idx] = a;
    ne[idx] = head;
    head = idx ++ ;
}

 将头结点删除,需要保证头结点存在
void remove()
{
    head = ne[head];
}

 将x插到下标是k的点后面 先右后左
void add(int k, int x)
{
    e[idx] = x;
    ne[idx] = ne[k];
    ne[k] = idx ++ ;
}

 将下标是k的点【后面】的点删掉!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
void remove(int k)
{
    ne[k] = ne[ne[k]];
}

在这里插入图片描述

#include<iostream>
#include<cstring>
using namespace std;

const int N=100000;
int head,idx,e[N],ne[N];

void init(){
	head=-1;
	idx=0;
}

void head_insert(int x){
	e[idx]=x;
	ne[idx]=head;
	head=idx;
	idx++;
}

void k_insert(int k,int x){
	e[idx]=x;
	ne[idx]=ne[k];
	ne[k]=idx;
	idx++;
}

void k_delete(int k){
	ne[k]=ne[ne[k]];
}

int main(){
	init();
	int n;
	cin>>n;
	while(n--){
		string a;
		cin>>a;
		if(a=="H"){
			int x;
			cin>>x;
			head_insert(x);
		}
		if(a=="I"){
			int k,x;
			cin>>k>>x;
			k_insert(k-1,x);
		}
		if(a=="D"){
			int k;
			cin>>k;
			if(k==0) head=ne[head];
			else k_delete(k-1);
		}
	}
	for(int i=head;i!=-1;i=ne[i]){  遍历的操作
		cout<<e[i]<<" ";
	}
}

双链表 0是左端点,1是右端点

初始化 右插(同时实现左插)

// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
int e[N], l[N], r[N], idx;

// 初始化
void init()
{
    //0是左端点,1是右端点
    r[0] = 1, l[1] = 0;
    idx = 2;
}

 在节点a的右边插入一个数x 先新后右最后左  右插insert(a,x)  左插insert(l[a],x)
void insert(int a, int x)
{
    e[idx] = x;
    l[idx] = a, r[idx] = r[a];  先新
    l[r[a]] = idx;后右
    r[a] = idx ++ ; 最后左
}

  删除下标为a的结点
void remove(int a)
{
    l[r[a]] = l[a];
    r[l[a]] = r[a];
}


单调栈O(N) 找出每个数左边离它最近的比它大/小的数

找左边邻近小

在这里插入图片描述

#include<bits/stdc++.h> 
using namespace std;

stack<int> stk;

int main(){
	int n; cin>>n;
	while(n--){
		int x;
		scanf("%d",&x);
		
		while(!stk.empty()&&x<=stk.top()) stk.pop();栈里比我大的都弹出 他们因为比我小不会再被输出
		if(!stk.empty()) cout<<stk.top()<<" "; 栈里余下的第一个即为我的左邻近小
		else cout<<"-1 "; 栈空说明没有我的左邻近小
		
		stk.push(x);
	}
} 

找右邻近大 可以逆着看 相当于找左邻近大 但是输出要逆序输出

在这里插入图片描述

#include<bits/stdc++.h> 
using namespace std;

const int N=1000;
int a[N];
stack<int> stk;
stack<int> answer;   逆序输出用

int main(){
	int n; cin>>n;
	for(int i=0;i<n;i++){
		scanf("%d,",&a[i]);
	}
	for(int i=n-1;i>=0;i--){   逆着看
		while(!stk.empty()&&a[i]>=stk.top()) stk.pop();  找大 则栈里小的出去
		if(!stk.empty())   answer.push(stk.top());
		else answer.push(-1);
		
		stk.push(a[i]);
	}
	while(!answer.empty()){  逆序输出
		cout<<answer.top()<<" ";
		answer.pop();
	}
} 

单调队列 求滑动窗口中的最大最小值

在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;

const int N=1000010;
int a[N];

int main(){
	deque<int> Q;   因为头尾都会删 所以要用双端队列  队列中存放下标
	int n,k;
	cin>>n>>k;
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
	} 
	输出窗口里的最小值
	for(int i=0;i<n;i++){ 遍历数组
		if(!Q.empty()&&Q.front()<i-k+1) Q.pop_front();  保证队列在当前下表的感受野内
		
		以下操作保证队列单调
		while(!Q.empty()&&a[i]<=a[Q.back()]) Q.pop_back();  队列里比我大的都弹出
		Q.push_back(i);                                     我进去
		
		if(i>=k-1) cout<<a[Q.front()]<<" ";  不断输出队首 因为单调,队首总是最小值
	}
	
	cout<<endl;
	Q.clear();  清零
	
	输出窗口里的最大值
	for(int i=0;i<n;i++){
		if(!Q.empty()&&Q.front()<i-k+1) Q.pop_front();
		
		while(!Q.empty()&&a[i]>=a[Q.back()]) Q.pop_back();
		Q.push_back(i);
		
		if(i>=k-1) cout<<a[Q.front()]<<" ";
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
树状数组、并查集和单调栈是常用的数据结构,它们在算法和数据处理中有着广泛的应用。 1. 树状数组(Binary Indexed Tree)是一种用于高效处理区间和的数据结构。它可以在O(logN)的时间内完成点更新和区间查询操作。树状数组主要用于解决一些前缀和相关的问题,例如计算数组的前缀和、区间和等。树状数组的基本原理是利用二进制表示的索引来维护和查询区间和。具体操作包括更新操作和查询操作。 2. 并查集(Union-Find Set)是一种用于处理不相交集合的数据结构。它支持合并集合和查询元素所在集合的操作。并查集的基本原理是使用树形结构来表示集合,每个节点储存其父节点的信息。通过路径压缩和按秩合并的优化策略,可以实现较快的合并和查询操作。并查集常用于解决一些连通性问题,例如判断图中的连通分量、判断两个元素是否在同一个集合中等。 3. 单调栈(Monotonic Stack)是一种特殊的栈数据结构,它可以在O(N)的时间内解决一些与调性相关的问题。单调栈的基本原理是维护一个调递增或调递减的栈,通过比较栈顶元素和当前元素的大小关系来确定栈中元素的位置。单调栈常用于解决一些与最大值、最小值、下一个更大元素、下一个更小元素等相关的问题。 以下是对树状数组、并查集和单调栈的简介绍。如果你对其中某个数据结构感兴趣,我可以为你提供更详细的解释和示例代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值