什么是離散化?C++實現方法


簡介

離散化本質上可以看成是一種 哈希 ,其保證數據在哈希以后仍然保持原來的全/偏序關系。

通俗地講,就是當我們只關心數據的大小關系時,用排名代替原數據進行處理的一種預處理方法。離散化本質上是一種哈希,它在保持原序列大小關系的前提下把其映射成正整數。當原數據很大或含有負數、小數時,難以表示為數組下標,一些算法和數據結構(如BIT)無法運作,這時我們就可以考慮將其離散化。

用來離散化的可以是大整數、浮點數、字符串……等等。

實現

C++ 離散化有現成的 STL 算法:

離散化數組

將一個數組離散化,並進行查詢是比較常用的應用場景:

// a[i] 為初始數組,下標范圍為 [1, n]
// len 為離散化后數組的有效長度
std::sort(a + 1, a + 1 + n);
len = std::unique(a + 1, a + n + 1) - a -
      1;  // 離散化整個數組的同時求出離散化后本質不同數的個數。

在完成上述離散化之后可以使用 std::lower_bound 函數查找離散化之后的排名(即新編號):

std::lower_bound(a + 1, a + len + 1, x) - a;  // 查詢 x 離散化后對應的編號

同樣地,我們也可以對 vector 進行離散化:

// std::vector<int> a, b; // b 是 a 的一個副本
std::sort(a.begin(), a.end());
a.erase(std::unique(a.begin(), a.end()), a.end());
for (int i = 0; i < n; ++i)
  b[i] = std::lower_bound(a.begin(), a.end(), b[i]) - a.begin();

實際演示:

現在我們有序列 A=[10, 23, 35, 3, -40, 3] 。我們先復制一個同樣的序列:

int C[N];
memcpy(C, A, sizeof(A));

排序,去重:

sort(C, C + n);
int l = unique(C, C + n) - C; // l為不重復元素的數量

std::unique()的返回值是一個迭代器(對於數組來說就是指針了),它表示去重后容器中不重復序列的最后一個元素的下一個元素。所以可以這樣作差求得不重復元素的數量。現在我們有C=[-40, 3, 10, 23, 35]。

再用一個數組,儲存A中每個元素在C中的排名:

int L[MAXN];
for (int i = 0; i < n; ++i)
    L[i] = lower_bound(C, C + l, A[i]) - C + 1; // 二分查找

這樣我們就實現了原序列的離散化。得到 L=[3, 4, 5, 2, 1, 2]

因為排序和n次二分查找的復雜度都是 \(\mathcal{O}(n\ log\ n)\) ,所以離散化的復雜度也是 \(\mathcal{O}(n\ log\ n)\) 。完整代碼很短:

int C[N], L[N];
// 在main函數中...
memcpy(C, A, sizeof(A)); // 復制
sort(C, C + n); // 排序
int l = unique(C, C + n) - C; // 去重
for (int i = 0; i < n; ++i)
    L[i] = lower_bound(C, C + l, A[i]) - C + 1; // 查找

離散化也不一定要從小到大排序,有時候也需要從大到小。這時在排序和查找時相應地加上greater<int>()就可以了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM