浅谈离散化

离散化

前言:

因为做洛谷P1955 程序自动分析 的时候,卡在离散化这里,硬是过不了第二个点

所以...感觉离散化还是逃不掉,得学...

于是...我就去看了资料看了博客,现在写一下学习记录


知识搬运:

我们还是先通过问答的形式来了解一下“离散化”

  • 离散化是什么啊?在什么地方用啊?(听着好高级哦ovo

面对数据贼大的情况(例如上面那道题,1e9的数据),直接开数组肯定会炸,所以我们引入“离散化”这个东西,将大数据映射到一个较小的值域来处理

  • 那怎么实现离散化呢?

主要有两种吧(也许更多,可以自行学习(逃~):

  1. STL实现离散化(STL大法好啊 orz)

STL实现离散化呢,还是很简单的,就是如下三步:

(1)排序(sort函数)

(2)去重(unique函数):返回去重之后的尾迭代器(或指针),即去重之后末尾元素的下一个位置

把一个vector去重:
int m=unique(a.begin(),a.end())-a.begin();
把一个数组去重,元素存放在下标1~n:
int m=unique(a+1,a+1+n)-(a+1);

(3)二分索引(lower_bound或upper_bound函数):两个迭代器(或指针)指定的部分应该是提前排好序

lower_bound的第三个参数传入一个元素x,在两个迭代器(或指针)指定的部分上执行二分查找,返回第一个大于等于x的元素的位置的迭代器(或指针)

upper_bound的用法和lower_bound大致相同,唯一的区别是查找第一个大于x的元素

在有序int数组,元素下标1~n,查找大于等于x的最小整数的下标:
int i=lower_bound(a+1,a+1+n,x)-a;
在一个有序的vector<int>中查找小于等于x的最大整数:
int y=*--upper_bound(a.begin(),a.end(),x);

不好理解?我们来举个栗子:

n=7
a[](b[]):4 3 6 10 7 7 8
sort之后:3 4 6 7 7 8 10
unique后:3 4 6 7 8 10

此时unique返回的的迭代器(或指针)指向元素10的后一个位置,(a+1)表示元素3的位置
那么unique(a+1,a+1+n)-(a+1)=7-1=6,即为去重后的元素个数

现给出完整STL实现离散化的代码,如下:

#include <bits/stdc++.h>
using namespace sts;
int n,res,tot,a[MAXN],b[MAXN];
int main() {
	scanf("%d",&n);
	for(register int i=1;i<=n;i++) {
		scanf("%d",&a[i]);
		b[++tot]=a[i]; //b[]是a[]的副本 
	}
	sort(b+1,b+1+tot);  //第一步:排序 
	res=unique(b+1,b+1+tot)-(b+1);  //unique函数计算出去重后的元素个数,存在res中
	for(register int i=1;i<=n;i++) {
		a[i]=lower_bound(b+1,b+1+tot,a[i])-b;  //lower_bound函数进行索引 
	}
	return 0;
} 
  1. Hash表(也叫散列表)实现离散化

Hash表一般有Hash函数(散列函数)与链表结构共同实现,通过Hash函数将原值映射到一个容易维护的值域中

但是使用Hash肯定避不开的就是Hash冲突,解决方案是建立一个邻接表结构,以Hash函数的值域作为head,映射后值相同的原始信息被分到同一个head后面,构成链表

这里给出一篇使用Hash表实现离散化题解,感觉讲得还蛮详细


补充

这里补充一种比较低配的实现离散化的方式:map函数

我们知道,map函数实现的就是两种相同或不同数据类型之间的映射

那我们就可以使用map实现离散化啊!代码如下:

#include <bits/stdc++.h>
using namespace std;
int n,u,v,tot;

map<int,int> shan;

int main() {
	scanf("%d",&n);
	for(register int i=1;i<=n;i++) {
		scanf("%d%d",&u,&v);
		if(shan[u]==0) shan[u]=++tot;
		if(shan[v]==0) shan[v]=++tot;
	}
	return 0;
} 

原文地址:https://www.cnblogs.com/Eleven-Qian-Shan/p/13157949.html