zoukankan      html  css  js  c++  java
  • 浅谈离散化

    离散化

    前言:

    因为做洛谷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;
    } 
    

  • 相关阅读:
    Linq调试实时输出信息扩展方法(摘抄)
    RSA签名和验证数据
    Vue+abp微信扫码登录
    vue学习笔记4
    icon共享网站 可以获得wpf里用的Geometry
    wpf 父控件和子控件 各自触发鼠标按下事件
    C# Timespan Tostring 时分秒格式
    新公司第二天
    C# 反转单向链表
    经纬度转数字经纬度时,如果是负数
  • 原文地址:https://www.cnblogs.com/Eleven-Qian-Shan/p/13157949.html
Copyright © 2011-2022 走看看