您的位置:首页 > 其它

三向字符串快速排序

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: