字符串排序
-
低位优先
-
从最右面开始排序,适合所有字符串长度一样的情况
-
临时数组count大小为全部键的数量加1
- 比如ASCII码全部键的数量为128
- 加1是因为使用字符串某一位字符累加count数组时,不是累加对应的位置,而是加一位
- 原因是当第二遍累加后,count数组的含义为以该字符为键的字符串第一次出现在原数组中的位置,这原本应该是前面的字符串数量加上一,又因为位置从0开始计数,所以就是前面字符串的数量
- 因为计算公式为count[r] += count[r - 1],所以位置r应该是键r-1字符串的数量
-
这是一种线性时间算法
- 由于全部键数R一般远小于待排序字符串数N,因此总时间可以大约正比于WN
- W为字符串宽度
- 由于全部键数R一般远小于待排序字符串数N,因此总时间可以大约正比于WN
-
相关C++知识点
- 临时数组初始化预留空间时必须使用resize而不是reserve,否则只是预留了空间而未初始化元素,只能使用insert或者push_back添加数组,不可使用下标
- vector<string> 类型变量不可使用列表初始化,因为string不是const char*,只能先列表初始化string数组然后用迭代器初始化
//错误 vector<string> v; v.reserve(7); v[1] = "Smith"; //正确 vector<string> v; v.resize(7); v[1] = "Smith"; //错误 vector<string> v = {"armli", "jones", "smith", "white", "brown", "jacks", "ponie"}; //正确 string s[] = {"armli", "jones", "smith", "white", "brown", "jacks", "ponie"}; vector<string> v(s, s + 7);
-
-
高位优先
- 这篇博客有十分详细的解释 https://blog.csdn.net/cook2eat/article/details/54353540
- 稳定排序算法
- 可用来排序 长度不一的字符串,且此时速度快于低位优先
- 随机字符串为亚线性时间,最坏为线性时间
- 当待排序的字符串们有较长的公共部分时,递归次数较多,同时要为count数组分配的额外空间也较多
- 此时应该使用三相字符串快速排序
- 递归编写
- 低位优先无法用递归写,因为从右往左每一次迭代要排序的数据规模不变
- 高位优先可以使用递归,因为高位的大小可以确定相对大小,所以每次迭代数据规模可以缩小
- 由于字符串长度不一,要使用一个函数来替代下标操作符,使得大于该字符串长度的位返回-1,而不是报错
- 同时临时数组要开RANGE + 2长度
- 可以在子字符串小于一定长度时切换到插入排序
-
三相字符串快速排序
- 当存在许多相等的键或者相等前缀的时候,使用该方法比高位优先要快
- 隐含的适用场景为键的取值范围较小时(此时容易出现等键)
- 例如网址排序
- 同时该方法还有一个优势就是不需要额外空间
- 缺点在于不是稳定排序
- 当存在许多相等的键或者相等前缀的时候,使用该方法比高位优先要快
字典树
- 字典树共性
- 每次查找命中所需要的时间与被查找的键长成正比
- 查找未命中则只要检查几个字符
- 用处
- 搜索引擎的关键词自动补充
- R向字典树
- R叉树
- R为字符集合中的字符数,例如ASCII码的R = 128
- R越大则消耗的空间越大
- 适用于键较小且字符集较小的情况
- 树的形状与茶树顺序无关
- R叉树
- 3向字典树
- 3叉树
- 与二叉搜索树一样,树的形状与插入字符串以及插入顺序有关
- 适用于键的首字母分布均匀的情况
- 使用的内存空间小于R向字典树,但是查找速度会慢一点
具体实现代码见:https://github.com/wuwentao1998/Data-Structures-and-Algorithms