优化后的快速排序代码

经典的快速排序是以第一的数为pivot来划分每次的标准的,优化过程可以使用三数取中,小段数字插排,重复pivot合并等方法来进行操作。这里先给出一个经典的快排代码,以任意非数字结束输入。

//快速排序以及进阶操作
// pivot: the key
// 不能排序负数
#include"stdio.h"
#define INT_MIN -2147483648
void qst(int*,int,int);
int get()
{
	int judge;
	int q;
	if (judge = scanf("%d", &q))
		return q;
	else
		return INT_MIN;
}
void swap(int* a, int* b)
{
	int box;
	box = *a;
	*a = *b;
	*b = box;
}

int main()
{
	int s[100000]={0};
	int i = 0,n;
	while ((n = get())!= INT_MIN)
	{
		s[i] = n;
		i++;
	}
	qst(s,0,i-1);
	while(i--)
	{
		printf("%d ",s[i]);
	}
	puts("");
	return 0;
}
//以#结束输入
void qst(int* que,int begin,int end)
{
	if (begin>end)
		return;
	int pivot;
	int start = begin,last=end;
	pivot = que[begin];
	while (begin != end)
	{
		while (que[end] >= pivot && begin != end)
			end--;
		if (begin!=end)
			swap(&que[begin], &que[end]);
		while (que[begin] <= pivot && begin != end)
			begin++;
		if (begin != end)
			swap(&que[begin], &que[end]);
	}
	qst(que, start,begin-1);
	qst(que, begin+1,last);
}

然后这里再给出一个优化后的快排代码,运算速度接近STL中的sort函数。

其中我使用的三数取中的方法比较笨,必须要标记pivot 的所在位置,不然在进入下一级排序时标志会乱,导致排序失败。加了三数取中后的排序方法后比较关键的一个变化就是pivot的位置决定了在进入下一级前需要和谁换位置(不知道可以这样理解不),这也是这个优化的关键操作。

后面还加入了一个去重的优化,这个该怎么实现呢?在看了一些实践的方式后我决定使用一个O(n)的算法使排序后的数组中的重复数字集中在pivot左右,这样子下一次只需要处理重复pivot的两端数组即可。例如:79 89 5 79 79 99 32 66 79 99.在一次处理中为:1.(三数取中找pivot)pivot=79,2.交换:79 66 5 79 79 32 99 89 79 99(begin停在了32的位置),3.去重:先交换79与32;79 66 5 79 99 32 79 89 79 99,然后去重:(围绕begin=6进行去重)32 66 5 99 79 79 79 79 89 99,同理,其他的过程类似,这就是我给出的一个优化快排的完整版代码,欢迎各位dl纠正。

#include"stdio.h"
void qst(int*, int, int);
void swap(int* a, int* b)
{
	int box;
	box = *a;
	*a = *b;
	*b = box;
}
int median(int a, int b, int c)//三数取中优化法
{
	if (a <= b && a >= c)
		return 1;
	else if (b <= a && b >= c)
		return 2;
	else
		return 3;
}
void InsertSort(int* q, int a, int b)
{
	int now;
	for (int i = a + 1; i <= b; i++)
	{
		if (q[i] < q[i - 1])
		{
			now = i;
			while (q[now] < q[now - 1] && now>0)
			{
				swap(&q[now], &q[now - 1]);
				now--;
			}
		}
	}
}
void qst(int* que, int begin, int end)
{
	if (begin > end)
		return;
	if (end - begin < 10)
	{
		InsertSort(que, begin, end);
		return;
	}
	int pivot, j;
	int start = begin, last = end;
	pivot = median(que[begin], que[end], que[(begin + end) / 2]);
	if (pivot == 1)
	{
		pivot = que[begin];
		j = begin;
	}
	else if (pivot == 2)
	{
		pivot = que[end];
		j = end;
	}
	else
	{
		pivot = que[(begin + end) / 2];
		j = (begin + end) / 2;
	}
	while (begin != end)
	{
		while (que[end] >= pivot && begin != end)
			end--;
		while (que[begin] <= pivot && begin != end)
			begin++;
		if (begin != end)
		{
			swap(&que[begin], &que[end]);
		}
	}
	//理解为什么需要换位置...... 
	//delete repeated elements......
	int s = start, e = last;
	if (j <= begin)
	{
		int left = begin - 1, right = begin + 1;
		que[j] = que[begin];
		que[begin] = pivot;
		for (; s <= left; s++)
		{
			if (que[s] == pivot)
			{
				swap(&que[s], &que[left]);
				left--;
			}
		}
		for (; e >= right; e--)
		{
			if (que[e] == pivot)
			{
				swap(&que[e], &que[right]);
				right++;
			}
		}
		qst(que, start, left);
		qst(que, right, last);
	}
	else if (j > begin)
	{
		int left = begin, right = begin + 2;
		que[j] = que[begin + 1];//交换位置的顺序不能错......
		que[begin + 1] = pivot;
		for (; s <= left; s++)
		{
			if (que[s] == pivot)
			{
				swap(&que[s], &que[left]);
				left--;
			}
		}
		for (; e >= right; e--)
		{
			if (que[e] == pivot)
			{
				swap(&que[e], &que[right]);
				right++;
			}
		}
		
		qst(que, start, left);
		qst(que, right, last);
	}

}
int main()
{
	int s[100001] = { 0 };
	int i = 0, n;
	scanf("%d", &n);
	for (i = 0; i < n; i++)
	{
		scanf("%d", &s[i]);
	}
	qst(s, 0, i - 1);
	for (n = 0; n < i; n++)
	{
		if (n < i - 1)
			printf("%d ", s[n]);
		else
			printf("%d", s[n]);
	}
	puts("");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值