离散化

离散化就是把有限数量但范围很大数据,如果不考虑数值大小,只关注相对顺序, 那么可以映射到一个小范围去
分为两种,保序离散化和无序离散化

无序离散化适用于只关注数据本身,而不关注它们顺序的离散化

保序离散化即保证离散化后的数据依旧符合原先顺序不变。
保序离散化需要另开一个数组(vector),来方便进行排序 + 判重 + 二分 = 离散化

当然不保序的也少用,一般都保序离散化

不保序

可以开一个map 或者 hash 表来映射

map <int, int> a;
unordered_map<int, int> a;
unordered_map<int, int> a;
int g[N];
int cnt = 0;
for (int i = 1; i <= n; i ++ )
{
	cin >> g[i];
	a[g[i]] = ++ cnt ; // a为离散化数组
}

保序

一般离散化的都是坐标之类的东西
新开数组 g,内容和原数组 a 相同,把 g 排序加去重(细节不在强调),然后用二分查找,返回下标即为离散化大小。

  • 预处理(复制数组)
  • 排序
  • 去重
  • 二分查找
代码

vector 版


const int N = 100010;

int n, k; 
int a[N]; // 原数组
vector<int> g; // 离散数组,存储离散化后的 数据

int find(int x) // 给与一个原值(可能是下标),查询离散化后的值
{
	int l = 0, r = k - 1; // 因为 g 是 vector 从0开始储存
	while (l < r)
	{
		int mid = l + r >> 1;
		if (x <= g[mid]) r = mid;
		else l = mid + 1;
	}
	return l + 1;
}

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i ++ ) 
	{
		cin >> a[i];
		g.push_back(a[i]); 
	}
	sort(g.begin(), g.end());
	g.erase(unique(g.begin(), g.end()), g.end()); //去重,unique本质是把相邻项
	// (即重复项)放到末尾,并在处理完之后返回一个指向去重后的末尾项的下一项的迭代器,
	// 而erase是删除元素,如此使用可以直接删除末尾的重复元素
	int k = g.size(); // k 为去重后数组长度
	// 后续调用 find() 即可找到离散化之后的的下标
}

数组版

const int N = 10010;

int k, n; 
int a[N]; // 原数组
int g[N];

int find(int x)
{
	int l = 1, r = k;
	while (l < r)
	{
		int mid = l + r >> 1;
		if (x <= g[mid]) r = mid;
		else l = mid + 1;
	}
	return l;
}

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i ++ ) 
	{
		cin >> a[i];
	}
	memcpy(g, a, sizeof g); // 复制数组使用,意为把 a 复制给 g, sizeof g的长度
							// sizeof 给数组使用,可直接返回数组长度
	sort(g + 1, g + 1 + n); // 自行体会
	int k = unique(g + 1, g + 1 + n) - (g + 1); // unique 返回末地址的下一位,
	// 减去首地址就是去重后的长度
	
	// 后续调用 find() 即可找到离散化之后的的下标
}

posted @ 2025-10-28 16:06  blind5883  阅读(2)  评论(0)    收藏  举报