快速排序中带有大量重复关键字的时候,简单的由一个划分元素将元素分成两个子文件的算法效率低。很自然地想到了“荷兰国旗问题”,采用三路划分,将与划分元素相等的元素又区分出来,减少不必要的递归程序。
在快速排序中,当两个运动的指针遇到与划分元素相等的元素时候,将该元素数组的两端:左指针遇到的交换到数组的左端,右指针遇到的交换到数组的右端。需要增加两个指针,指向数组左右端可以存储相等元素的位置。
在快速排序中,当两个运动的指针遇到与划分元素相等的元素时候,将该元素数组的两端:左指针遇到的交换到数组的左端,右指针遇到的交换到数组的右端。需要增加两个指针,指向数组左右端可以存储相等元素的位置。
找到划分元素的位置之后,将相等元素由左右两端交换到划分元素的两边。
void quicksort_triple(Item a[], int l, int r)
{
int i, j, k, p, q;
Item v;
if(r<=l) return;
v = a[r];
i = l-1;
j = r;
p = l-1;
q = r;
for(;;)
{
while(less(a[++i], v));
while(less(v, a[--j]))
{
if(j==l) break; //跳出while循环
}
if(i>=j) break; //跳出for循环
exch(a[i], a[j]);
if(eq(a[i], v))
{
p++;
exch(a[p], a[i]);
}
if(eq(v, a[j]))
{
q--;
exch(a[q], a[j]);
}
}
exch(a[i], a[r]);
//将左右两端与划分元素相等的元素交换到划分元素的两边
i = i-1;
j = i+1;
for(k=l; k<=p; k++, i--)
{
exch(a[k], a[i]);
}
for(k=r-1; k>=q; k--, j++)
{
exch(a[k], a[j]);
}
quicksort_triple(a, l, i);
quicksort_triple(a, j, r);
}
综合三种快速排序的改进方法,实现快速排序如下
void quicksort_smallFile_median_triple(Item a[], int l, int r)
{
int i, j, k, p, q;
Item v;
i = l-1;
j = r;
p = l-1;
q = r;
if(r-l <= M)
{
insertSort(a, l, r);
return; //递归返回条件
}
exch(a[(l+r)/2], a[r-1]); //数组中间值与a[r-1]交换
//三交换法对三个元素进行排序
compexch(a[l], a[r-1]);
compexch(a[l], a[r]);
compexch(a[r-1], a[r]);
v = a[r];
for(;;)
{
while (less(a[++i], v));
while (less(v, a[--j]))
{
if (j==l)
{
break;
}
}
if (i>=j)
{
break;
}
exch(a[i], a[j]);
if (eq(a[i], v))
{
p++;
exch(a[p], a[i]);
}
if (eq(a[j], v))
{
q--;
exch(a[q], a[j]);
}
}
exch(a[i], a[r]);
i = i-1;
j = i+1;
for (k=l; k<=p; k++, i--)
{
exch(a[k], a[i]);
}
for (k=r-1; k>=q; k--, j++)
{
exch(a[k], a[j]);
}
quicksort_smallFile_median_triple(a, l, i);
quicksort_smallFile_median_triple(a, j, r);
}
完整的测试程序
#include <stdio.h>
#include <stdlib.h>
typedef int Item;
#define key(A) (A)
#define less(A, B) (key(A)<key(B))
#define exch(A, B) {Item t = A; A = B; B = t;}
#define compexch(A, B) if(less(B, A)) exch(A, B) //最后A<B
#define eq(A, B) (!less(A, B) && !less(B, A))
#define M 10 //M取值在5~20之间
void insertSort(Item a[], int l, int r)
{
int i, j;
for (i = l+1; i <= r; i++)
{
for(j = i; j > l; j--)
compexch(a[j-1], a[j]);
}
}
void quicksort_smallFile_median_triple(Item a[], int l, int r)
{
int i, j, k, p, q;
Item v;
i = l-1;
j = r;
p = l-1;
q = r;
if(r-l <= M)
{
insertSort(a, l, r);
return; //递归返回条件
}
exch(a[(l+r)/2], a[r-1]); //数组中间值与a[r-1]交换
//三交换法对三个元素进行排序
compexch(a[l], a[r-1]);
compexch(a[l], a[r]);
compexch(a[r-1], a[r]);
v = a[r];
for(;;)
{
while (less(a[++i], v));
while (less(v, a[--j]))
{
if (j==l)
{
break;
}
}
if (i>=j)
{
break;
}
exch(a[i], a[j]);
if (eq(a[i], v))
{
p++;
exch(a[p], a[i]);
}
if (eq(a[j], v))
{
q--;
exch(a[q], a[j]);
}
}
exch(a[i], a[r]);
i = i-1;
j = i+1;
for (k=l; k<=p; k++, i--)
{
exch(a[k], a[i]);
}
for (k=r-1; k>=q; k--, j++)
{
exch(a[k], a[j]);
}
quicksort_smallFile_median_triple(a, l, i);
quicksort_smallFile_median_triple(a, j, r);
}
int main(void)
{
int i, N, sw;
N = 10;
sw = 0;
int *a = (int *)malloc(N*sizeof(int)); //为数据a分配相应的存储空间
if (sw)
{
for(i=0; i<N; i++)
{
a[i] = 1000 * (1.0 * rand()/RAND_MAX);
}
}
else
{
for (i = 0; i < N; i++)
{
scanf("%d", &a[i]);
}
}
puts("排序前");
for(i=0; i<N; i++)
{
printf("%d ", a[i]);
}
quicksort_smallFile_median_triple(a, 0, N-1);
puts("\n排序后");
for(i=0; i<N; i++)
{
printf("%d ", a[i]);
}
printf("\n");
system("pause");
return 0;
}