三向字符串快速排序
2015-09-20 22:23
375 查看
#include <stdio.h> #include <stdlib.h> #include <string.h> //三向字符串快速排序 //基于快速排序的思想,依据键值进行比较,划分为小于当前 //键值、等于当前键值、大于当前键值的3个子组,之后采用递 //归方法分别对3个子组再次进行排序。由于等于当前键值的子 //组所有键都已经相同,所以无需再比较当前键值,而选取下 //一列索引字符做为键值。 // //如下示例所示,最初仅有一个排序组,有6个组成员,此时选 //择每组成员的索引0进行排序,当前选择了第1个成员的索引0 //字符h做为比较键进行比较,在第一次排序后,将小于h键的 //成员分为一子组、等于h键的成员分为一子组、大于h键的成 //员分为一子组,之后采用递归方法,分别对每个子组进行排序 //处理,第一个小于h的子组仍然使用索引0为键进行排序,第二 //个等于h的子组,由于已知当前索引0的键都已经相同,所以取 //下一列索引为键进行排序,第三个大于h的子组仍然使用索引 //0为键进行排序。 // // 原始数据: 第一次排序后: // http.hello.com bos.test.com // www.test.com ftp.hello.com // bos.test.com ^ // www.hello.com // ftp.hello.com http.test.com // http.test.com http.hello.com // ^ ^ // // www.test.com // www.hello.com // ^ //查找提指定索引处char的值,如果不存在则返回-1 char charAt(const char *pStr, const int index) { const char *pOldStr = pStr; if ( pStr == NULL ) { return -1; } while ( *pStr != '\0' ) { if ( (pStr-pOldStr) == index ) { return *pStr; } pStr++; } return -1; } //字符串数组成员交换 void arrayExch(char* strArray[], int x, int y) { char *pTmp = strArray[x]; strArray[x] = strArray[y]; strArray[y] = pTmp; } //核心算法 void sort(char* strArray[], int lo, int hi, int d) { // 最终处理完成后的图示: // *******@@@@@@@@@######### // ^ ^ // | | // lt gt/i // //如上图示,lt表示小于比较值的下一个存储索引,在算法 //不断处理过程中,如果找到小于比较值的项,则将该项与 //lt索引所在项进行交换,同时递增lt,从而使得lt索引左 //边的部分一定都小于比较值,而gt表示大于比较值的下一 //存储索引,在算法不断处理过程中,如果找到大于比较值 //的项,则将该项与gt索引所在项进行交换,同时递减gt, //从而使得gt索引右边的部分一定都大于比较值,最终结果 //如示例所示,lt-1左边都小于比较值,gt+1右边都大于比 //较值,lt与gt之间都等于比较值。 int lt = lo; int gt = hi; //同普通快速排序法相同,采用简化方法选择字符串数组第 //开始索引项数据做为比较值。 //当前i为一个游标,i值从左向右移动,依次选择i索引下 //的数据与比较值进行比较,由于当前选择数组开始索引做 //为比较值,所以i的初始取值则是在开始索引上加1 int i = lo + 1; int cmpKey = charAt(strArray[lo], d); //当前为递归函数,这里做为是否继续递归的判断条件。 if ( lo >= hi ) { return; } //i游标从左向右不断移动,当i值与gt相遇时,即表示本轮 //排序比较已经完成。 while ( i <= gt ) { int iKey = charAt(strArray[i], d); //如果发现当前i索引下的字符串KEY小于比较值,则将当 //前值与lt索引值进行交换,即把小于比较值的项都移到 //lt索引的左边,此时将lt向右移动用于存储下一个小于 //比较值的项。i值也继续向右移动,因为i值就是从左向 //右方向移动过来的,所以此时交换过来的lt索引的项信 //息早就知道了(不是小于比较值,就是等于比较值) if ( iKey < cmpKey ) { arrayExch(strArray, i, lt); lt++; i++; } //如果发现当前i索引下的字符串KEY大于比较值,则将当 //前值与gt索引值进行交换,即把大于比较值的项都移到 //gt索引值的右边,此时将gt向左移动用于存储下一个大 //于比较值的项,但i值并不移动,因为i值是从左向右移 //动的,此时把gt索引位置的数据移到i的位置,当前并 //不清楚此时这个i位置的新值与比较值的关系,所以i都 //不能变,需要在下一轮循环中检查该位置的值。 else if ( iKey > cmpKey ) { arrayExch(strArray, i, gt); gt--; } //如果发现当前i索引下的字符串KEY等于比较值,则不需 //要做交换处理,将i向右移动,继续检查下一个索引项 //的值。 else { i++; } } //经过上述排序后,当前字符串组分为了3个子组,lo~lt-1索引 //位置为小于比较值的一组,lt~gt索引位置为等于比较值的一 //组,gt+1~hi索引位置为大于比较值的一组,此时对这3个子组 //进行递归排序处理。 sort(strArray, lo, lt-1, d); //当做为比较值的字符串长度不满足处理时,cmpKey为-1,即该 //字符串查找已经到了末尾,此时必须加此限制,否则会出现死 //循环的情况,如下示例所示,如果比较的两个字符串是相同的, //会出现i值不断后向移动,当i移动到字符c之后时,两个字符串 //的之后cmpKey永远恒等于-1。 // //str1: abc //str2: abc if ( cmpKey >= 0 ) { //当前等于比较值的子组由于键已知都相同,所以选择下一 //列键(d + 1)进行处理,其它2个子组仍然使用原来的键 //进行处理。 sort(strArray, lt, gt, d + 1); } sort(strArray, gt+1, hi, d); } void dumpArray(char *strArray[], int count) { int i = 0; printf("****************************\r\n"); for ( i = 0; i < count; i++ ) { printf("[%02d] %s\r\n", i, strArray[i]); } } int main() { char *strArray[] = { "edu.princeton.cs", "com.apple", "edu.princeton.cs", "com.cnn", "com.goole", "edu.uva.cs", "edu.princeton.cs", "edu.princeton.cs.www", "edu.uva.cs", "edu.uva.cs", "edu.uva.cs", "com.adobe", "edu.princeton.ee" }; int arrayCount = sizeof(strArray) / sizeof(strArray[0]); dumpArray(strArray, arrayCount); sort(strArray, 0, arrayCount-1, 0); dumpArray(strArray, arrayCount); return 0; }
相关文章推荐
- cvc-complex-type.3.2.2: 元素 'ref' 中不允许出现属性 'local'
- 如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上)
- 分割字符串
- static关键字
- 《大道至简》第一章读后感
- redis实现网站最新登录用户功能
- Linux常用命令
- 金额小写转大写方法——好用!我一直在用它!
- 运用BufferedWriter把数据写入文件
- 基于网页内容数据采集 PHP开发学习笔记
- 对于Objective-C新建类的理解
- 算法基础(四)---- 计算数组组合最大和
- 爬虫自动更换代理
- 对象之间的关系
- NSUserDefaults standardUserDefaults的使用
- LINUX系统简介
- [sicily]1007. To and Fro
- 大端(网络字节序)与小端(主机字节序)存储
- 纹理分割(三)纹理分割相关知识
- HDU 5461 2015沈阳网络赛水题 Largest Point