代码实现以及现象分析
//北航机试2020/3/28
/*
头中尾三位取中
针对不同的数据量
*/
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
using namespace std;
#define MAXN 10000000
int Cutoff = 50;
void Insertion_Sort(int A[],int N)
{
int p,i;
int temp;
for(p = 1;p<N;p++)
{
temp = A[p];
for(i = p;i>=1&&temp<A[i-1];i--)
{
A[i] = A[i-1];
}
A[i] = temp;
}
}
int get_pivot(int A[],int Left,int Right,int op)
{
int pivot;
switch(op){
case 1:
{
/*选取最左边的主元*/
pivot = A[Left];
break;
}
case 2:
{
/*随机选取主元*/
int rand_index = rand()%(Right-Left+1) + Left;
swap(A[Left],A[rand_index]);
pivot = A[Left];
break;
}
case 3:
{
/*三点选中值*/
int center = (Left + Right)/2;
if(A[Left]>A[center])
swap(A[Left],A[center]);
if(A[Left]>A[Right])
swap(A[Left],A[Right]);
if(A[center]>A[Right])
swap(A[center],A[Right]);
swap(A[center],A[Left]);
pivot = A[Left];
break;
}
default:
{
break;
}
}
return pivot;
}
int Partition(int A[],int Left,int Right)
{
/*
int rand_index = rand()%(Right-Left+1) + Left;
swap(A[Left],A[rand_index]);
int pivot = A[Left];
*/
int pivot = get_pivot(A,Left,Right,3);
while(Left < Right)
{
//使用的是元素相等的时候继续移动指针
while(Left < Right && A[Right] >= pivot) --Right;
A[Left] = A[Right];
while(Left < Right && A[Left] <= pivot) ++Left;
A[Right] = A[Left];
}
A[Left] = pivot;
return Left;
}
void Qsort(int A[],int Left,int Right)
{
//if(Left<Right)
if(Cutoff<=Right-Left)//使用Cutoff阈值
{
int pivot_pos = Partition(A,Left,Right);
Qsort(A,Left,pivot_pos-1);
Qsort(A,pivot_pos+1,Right);
}
//
else
{
Insertion_Sort(A+Left,Right-Left+1);
}
}
void Quick_Sort(int A[],int N)
{
Qsort(A,0,N-1);
}
void print(int A[],int N)
{
int i;
for(i = 0;i<N;i++)
{
if(i == N-1)
printf("%d\n",A[i]);
else
printf("%d ",A[i]);
}
}
void test(int A[],int arg_Cutoff)
{
Cutoff = arg_Cutoff;
clock_t start,end;
start = clock();
Quick_Sort(A,MAXN);
end = clock();
printf("执行时间Cutoff=%d %f s\n",Cutoff,(double)(end-start)/CLOCKS_PER_SEC);
}
int A1[MAXN],A2[MAXN],A3[MAXN],A4[MAXN],A5[MAXN],A6[MAXN];
int main()
{
int i;
srand((unsigned)time(NULL));
for(i = 0;i<MAXN;i++)
{
A6[i] = A5[i]=A4[i] = A3[i]=A2[i] = A1[i] = rand();
}
test(A1,50);
test(A2,100);
test(A3,200);
test(A4,300);
test(A5,400);
test(A6,1);
return 0;
}
/*
MAXN 1000000
不同的实现方法
1.选用A[0]做主元
执行时间Cutoff=50 0.138000 s
执行时间Cutoff=100 0.224000 s
执行时间Cutoff=200 0.210000 s
执行时间Cutoff=300 0.228000 s
执行时间Cutoff=400 0.271000 s
执行时间Cutoff=1 0.172000 s
2.选用随机主元
执行时间Cutoff=50 0.149000 s
执行时间Cutoff=100 0.188000 s
执行时间Cutoff=200 0.192000 s
执行时间Cutoff=300 0.226000 s
执行时间Cutoff=400 0.272000 s
执行时间Cutoff=1 0.198000 s
3.使用三点取中值
执行时间Cutoff=50 0.139000 s
执行时间Cutoff=100 0.161000 s
执行时间Cutoff=200 0.187000 s
执行时间Cutoff=300 0.229000 s
执行时间Cutoff=400 0.274000 s
执行时间Cutoff=1 0.171000 s
MAX = 10000000(千万级)
1.选用A[0]做主元
执行时间Cutoff=50 4.392000 s
执行时间Cutoff=100 4.241000 s
执行时间Cutoff=200 3.679000 s
执行时间Cutoff=300 3.048000 s
执行时间Cutoff=400 2.603000 s
执行时间Cutoff=1 4.477000 s
2.选用随机主元*********************
执行时间Cutoff=50 4.754000 s
执行时间Cutoff=100 4.417000 s
执行时间Cutoff=200 3.688000 s
执行时间Cutoff=300 3.020000 s
执行时间Cutoff=400 2.649000 s
执行时间Cutoff=1 4.752000 s
3.使用三点取中值******************
执行时间Cutoff=50 3.838000 s
执行时间Cutoff=100 3.730000 s
执行时间Cutoff=200 3.270000 s
执行时间Cutoff=300 2.814000 s
执行时间Cutoff=400 2.479000 s
执行时间Cutoff=1 3.966000 s
千万级别现象的解释:
你会发现如果序列不是有序或者逆序的话,选用A[0]做主元,的效果还行,比随机函数要好
会发现选用A[0]做主元会比选用随机算法的运行时间节省
使用三点取中值会发现效果比较好,主要使得子集的划分均匀
个人觉着选取主元只是尽量避免最坏情况的产生,以及趋向于最好情况。
*/