/*
在北京工作的时候,接触到改进快速排序的需求.
在网上四处搜寻没有找到太合适的代码,可能是自己搜索的能力有待提升T_T
偶然间在新浪博客看到一篇改进快速排序的思路,苦于没有源码,所以自己按照作者的思路实现了一遍.由于时间过去太久,找不到作者的博客链接了,T_T
*/
//源码如下,仅供参考.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef WINVER
#include <windows.h>
#else
#include <sys/time.h>
#endif
void insert_sort(int a[], int low, int high); //插入排序
void int_swap_(int *a, int *b); //交换两个数
void compare_int_swap(int *a, int *b); // 交换后保证b是最大的
void array_pri(int a[], int low, int high); //数组输出
void quick_sort(int a[], int low, int high); //快排
int tim_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
int main()
{
//1.在堆上开辟空间用来存储数组
int low = 0;
int high = 100000000 - 1;
int *a = (int *)malloc(sizeof(int)*(high + 1));
//2.初始化数组
printf("正在初始化数据。。。\n");
for (int i = low; i <= high; ++i)
{
a[i] = (int)(rand() % ((high + 1)*10));
}
//3.开始计时
#ifdef WINVER
LARGE_INTEGER m_nFreq;
LARGE_INTEGER m_nBeginTime;
LARGE_INTEGER nEndTime;
QueryPerformanceFrequency(&m_nFreq); // 获取时钟周期
QueryPerformanceCounter(&m_nBeginTime); // 获取时钟计数
#else
struct timeval start,stop,diff;
gettimeofday(&start,0);
#endif
//4.执行快排序
printf("开始排序。。。\n");
quick_sort(a, low, high);
//5.快排结束后的系统时间
#ifdef WINVER
QueryPerformanceCounter(&nEndTime);
printf("Total Use:%lfs\n", (double)(nEndTime.QuadPart-m_nBeginTime.QuadPart)*1000/m_nFreq.QuadPart)
#else
gettimeofday(&stop,0);
tim_subtract(&diff,&start,&stop);
printf("Total Use:%d.%ds\n", (int)diff.tv_sec, (int)diff.tv_usec);
#endif
//6.释放堆空间
free(a);
a = NULL;
return 0;
}
void insert_sort(int a[], int low, int high)
{
if (low >= high)
{
return;
}
//1.将最小的元素移动到最左边,下面的循环将会很好些
int posMin = low; //记录最小元素
for (int i = low; i <= high; ++i)
{
if (a[i] < a[posMin])
{
posMin = i;
}
}
int_swap_(&a[low], &a[posMin]);
//2.如果小于三个数返回
if (high - low < 2)
{
return;
}
//3.从第三个数开始插入
for (int i = low + 2; i <= high; ++i)
{
int j = i;
int t = a[i];
while (a[j - 1]>t)
{
a[j] = a[j - 1];
a[j - 1] = t;
--j;
}
}
}
void quick_sort(int a[], int low, int high)
{
if (low >= high)
{
return;
}
//1.数据较小的情况下,用插入法提高效率
if (high - low < 20)
{
insert_sort(a, low, high);
return;
}
//2.采用三值取中 选取哨兵 low (low+high)/2 high
compare_int_swap(&a[low], &a[(low + high) / 2]);
compare_int_swap(&a[low], &a[high]);
compare_int_swap(&a[high], &a[(low + high) / 2]); // a[low]<=a[high] a[high]<=a[(low + high) / 2]
//3.每次分化的时候分为 大于哨兵(stand)的 小于哨兵的 等于哨兵的 //p q i j
// - - - - - - - - - -
// 5 5 2 3 1 8 9 5 5 5
// p i j q stand
int stand = a[high];
int i = low - 1;
int same_low = low - 1;
int j = high;
int same_high = high; // a[high]=stand
while(1)
{
//1.从左开始找第一个比stand大的位置 从右开始找第一个比stand小的位置
while (a[++i] < stand)
{ }
while (a[--j] > stand)
{
if(j == low)
{
break;
}
}
if(i>=j) //如果找不到两个位置
{
break;
}
//交换这两个位置
int_swap_(&a[i], &a[j]);
//如果这两个值有和stand相等的 左边加到最左边 右边加的最右边
if (a[i] == stand)
{
int_swap_(&a[++same_low], &a[i]);
}
if (a[j] == stand)
{
int_swap_(&a[--same_high], &a[j]);
}
}
//将stand放在合适的位置
int_swap_(&a[i], &a[high]);
//将左右两边的相等元素移动到中间来
j = i - 1; //j是stand左边第一个位置
i = i + 1; //i是stand右边第一个位置
int k;
for (k = low; k <= same_low&&j > same_low; ++k, --j)
{
int_swap_(&a[k], &a[j]);
}
j = j - same_low + k - 1;
for (k = high - 1; k >= same_high&&i < same_high; --k, ++i)
{
int_swap_(&a[k], &a[i]);
}
i = i + k - same_high + 1;
quick_sort(a, low, j);
quick_sort(a, i, high);
}
void int_swap_(int *a, int *b)
{
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
void compare_int_swap(int *a, int *b)
{
if (*a > *b)
{
int_swap_(a, b);
}
}
void array_pri(int a[], int low, int high)
{
for (int i = low; i <= high; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
}
int tim_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
{
//形参安全检查
if(x->tv_sec > y->tv_sec)
{
return -1;
}
result->tv_sec = (y->tv_sec - x->tv_sec);
result->tv_usec = (y->tv_usec - x->tv_usec);
if (result->tv_usec<0)
{
result->tv_sec--;
result->tv_usec+=1000000;
}
return 0;
}
/*
* time : 2017年2月16日21:19:24
* loca : BeiJing,China
* auth : GuoRui
* email: corcpp@163.com corcpp@qq.com
*
*/
测试了下,内排序1亿个数,耗时在18秒内. 等有时间在研究下继续改进…..