快速排序的三路划分法

快速排序中带有大量重复关键字的时候,简单的由一个划分元素将元素分成两个子文件的算法效率低。很自然地想到了“荷兰国旗问题”,采用三路划分,将与划分元素相等的元素又区分出来,减少不必要的递归程序。
在快速排序中,当两个运动的指针遇到与划分元素相等的元素时候,将该元素数组的两端:左指针遇到的交换到数组的左端,右指针遇到的交换到数组的右端。需要增加两个指针,指向数组左右端可以存储相等元素的位置。

找到划分元素的位置之后,将相等元素由左右两端交换到划分元素的两边。

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值