字符串排序
1.低位優先的字符串排序(LSD)
低位優先的字符串排序是從右到左依次檢查鍵中的字符,這種方法適用於鍵的長度都相同的字符串。
假設字符串的長度都為w,那么就從右向左按基數排序的方法排序w遍。
代碼實現:
//低位優先排序
template <typename T>
void LSD(vector<T> &a, int w) //通過前w個字符對a排序
{
int N = a.size(); //N個字符串
int R = 256; //R個字符構成的字母表
vector<T> aux(N); //拷貝數組
for (int d = w - 1; d >= 0; d--)
{
vector<int> count(R + 1);
for (int i = 0; i < N; i++) //計算出現頻率
count[a[i][d] + 1]++;
for (int r = 0; r < R; r++) //將頻率轉換為索引
count[r + 1] += count[r];
for (int i = 0; i < N; i++) //將元素分類
aux[count[a[i][d]]++] = a[i];
for (int i = 0; i < N; i++) //回寫
a[i] = aux[i];
}
}
測試數據:
4PGC938
2IYE230
3CIO720
1ICK750
1OHV845
4JZY524
1ICK750
3CIO720
1OHV845
1OHV845
2RLA629
2RLA629
3ATW723
測試結果:
1ICK750
1ICK750
1OHV845
1OHV845
1OHV845
2IYE230
2RLA629
2RLA629
3ATW723
3CIO720
3CIO720
4JZY524
4PGC938
性能分析:
對於基於R個字符的字母表的N個長為W的字符串為鍵的元素,LSD需要訪問~7WN+3WR次數組,使用的額外空間與N+R成正比。對於常用的應用,R會遠小於N,因此LSD的總運行時間與WN成正比。
2.高位優先的字符串排序(MSD)
高位優先的字符串排序會從左到右,首先查看的是最高位的字符,將最高位的字符按照順序排列之后,再將每個首字母對應的子數組排序。MSD是一種通用的字符串排序。
在MSD的實現中,我們會用插入排序對排序數組較小的時候進行優化,這樣可以大大提高MSD的效率。
代碼實現:
//高位優先排序
class MSD
{
private:
int R = 256; //基數
int M = 3; //小數組的切換閾值
vector<string> aux; //輔助數組
int charAt(string s, int d)
{
return (d < s.size()) ? s[d] : -1;
}
public:
MSD(vector<string> &a)
{
int N = a.size();
aux.resize(N);
sort(a, 0, N - 1, 0);
}
void sort(vector<string> &a, int lo, int hi, int d)
{
if (hi <= lo + M)
{
for (int i = lo; i <= hi; i++) //插入排序
{
string key = a[i];
int j = i - 1;
while (j >= 0 && key < a[j])
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = key;
}
return;
}
vector<int> count(R + 2);
for (int i = lo; i <= hi; i++) //計算頻率
count[charAt(a[i], d) + 2]++;
for (int r = 0; r < R + 1; r++) //將頻率轉換為索引
count[r + 1] += count[r];
for (int i = lo; i <= hi; i++) //數據分類
aux[count[charAt(a[i], d) + 1]++] = a[i];
for (int i = lo; i <= hi; i++) //回寫
a[i] = aux[i - lo];
//遞歸的以每個字符為鍵進行排序
for (int r = 0; r < R; r++)
sort(a, lo + count[r], lo + count[r + 1] - 1, d + 1);
}
};
測試數據:
she
sells
seashells
by
the
seashore
the
shells
she
sells
are
surely
seashells
測試結果:
are
by
seashells
seashells
seashore
sells
sells
she
she
shells
surely
the
the
性能分析:
對於大小為R的字母表的N個字符串排序,高位優先的字符串排序算法訪問次數在8N+3R到~7wN+3wR,w為字符串的平均長度。所需的空間最壞情況下與RW成正比,W為最長字符串的長度。
3.三向字符串快速排序
三向字符串快速排序通過優化MSD,根據鍵的首字母進行三向切分(大於,等於和小於鍵),僅在中間子數組的下一個字符繼續遞歸排序。
代碼實現:
//三向字符串快速排序
class Quick3Srting
{
private:
int charAt(string s, int d)
{
return (d < s.size()) ? s[d] : -1;
}
public:
Quick3Srting(vector<string> &a)
{
sort(a, 0, a.size() - 1, 0);
}
void sort(vector<string> &a, int lo, int hi, int d)
{
if (hi <= lo)
return;
int lt = lo, gt = hi;
int v = charAt(a[lo], d);
int i = lo + 1;
while (i <= gt)
{
int t = charAt(a[i], d);
if (t < v)
swap(a[lt++], a[i++]);
else if (t > v)
swap(a[i], a[gt--]);
else
i++;
}
sort(a, lo, lt - 1, d);
if (v >= 0)
sort(a, lt, gt, d + 1);
sort(a, gt + 1, hi, d);
}
};