接上一篇,这是将上一篇排序和快速排序结合的用于字符串排序的特殊排序法,比快排理论上要快。
上一篇的问题是当有连续重复前缀的字符串组,会不停的递归,而且会不停的产生辅助数组,当字符值范围不再是 0 - 255 而是 0 - 65535,消耗的辅助空间会过大,导致性能急速下降,作为算法的改善,将不依赖字符的映射数组,本质是快速排序再字符串这种结构的特化算法,因此极为高效。
//三向切分通用字符串排序类(英文)
struct q3StrSort
{
//三向切分快速排序
static void sort(std::vector<std::string> &strVec)
{
sort(strVec, 0, static_cast<int>(strVec.size()) - 1, 0);
}
private:
//获取 word 中 chOrder 位置字符的数值
static auto charAt(const std::string &word, int chOrder) -> int
{
if (chOrder < word.size())
{
return word.at(chOrder);
}
return -1;
}
//递归三分快速排序
static void sort(std::vector<std::string> &strVec, int lo, int hi,
int chOrder)
{
if (hi <= lo)
{
return;
}
// 设置左边界,确定首字符串 chOrder 字符边界
int leftNum = lo;
// 设置右边界,确定首字符串 chOrder 字符边界
int rightNum = hi;
// 确定首字符串 chOrder 字符数值
int firstChNum = charAt(strVec[lo], chOrder);
// 设置游标,用于比较游标指向的字符串 chOrder 字符数值
int otherNum = lo + 1;
// 设置游标指向的字符串 chOrder 字符数值
int otherChNum = 0;
while (otherNum <= rightNum)
{
// 设置游标指向的字符串 chOrder 字符数值
otherChNum = charAt(strVec[otherNum], chOrder);
// 当游标指向的字符串字符小于左边界指向的字符串字符
if (otherChNum < firstChNum)
{
//交换字符串,并自增游标和左边界
std::swap(strVec[leftNum++], strVec[otherNum++]);
}
// 当游标指向的字符串字符大于左边界指向的字符串字符
else if (otherChNum > firstChNum)
{
//交换字符串,并自减右边界
std::swap(strVec[otherNum], strVec[rightNum--]);
}
// 当游标指向的字符串字符等于左边界指向的字符串字符
else
{
//自增游标
otherNum++;
}
}
// strVec[lo..leftNum-1] < firstChNum = strVec[leftNum..rightNum] <
// strVec[rightNum+1..hi]
//递归排序左边界左侧字符串子数组
sort(strVec, lo, leftNum - 1, chOrder);
//如果第一字符串 chOrder 指向字符不为 -1
if (firstChNum >= 0)
{
//递归排序左右边界间的字符串子数组
sort(strVec, leftNum, rightNum, chOrder + 1);
}
//递归排序右边界右侧字符串子数组
sort(strVec, rightNum + 1, hi, chOrder);
}
};