33,010
社区成员
发帖
与我相关
我的任务
分享
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <ctime>
#include <algorithm>
using namespace std;
typedef unsigned int VT;
typedef unsigned int* pVT;
typedef unsigned int SIZE_T ;
template<class T>
void swap_kn(T & a,T & b){
T _t = a;
a = b;
b = _t;
};
typedef unsigned __int64 CTIME;
inline unsigned __int64 GetCycleCount()//测量时间的计数器,返回的是计数值,不是绝对时间值.
{
__asm _emit 0x0F
__asm _emit 0x31
}
void test_time_funtion(void (* func)(pVT,pVT),pVT pBeg,pVT pEnd ,const string & s,SIZE_T N){
if(pEnd <= pBeg + 1){
cout<<"数据错误,停止测试"<<endl;
return ;
}
CTIME t = GetCycleCount();
const CTIME CPU_FREQUENCY = 2600000;//根据自己CPU频率自己调整
SIZE_T max = N;
for(max /= pEnd - pBeg;max ;max --)
func(pBeg,pEnd);
t = GetCycleCount() - t;
cout<<s<<" 花费时间"<<t / CPU_FREQUENCY<<"毫秒"<<endl;
}
void check(pVT pDest,pVT pBeg,pVT pEnd){
for(;pBeg < pEnd;){
if(* pBeg ++ != * pDest ++){
cout<<"算法不正确"<<endl;
return ;
}
}
cout<<"算法正确"<<endl;
}
void init(pVT pDest,pVT pBeg,pVT pEnd){
for(;pBeg < pEnd;)
* pDest ++ = * pBeg ++;
}
int _tmain(int argc, _TCHAR* argv[])
{
srand((unsigned int) time(NULL));
SIZE_T n = 100000000;
SIZE_T N = 100000000;
pVT v,v1,v2;
v = new VT[n];
v1 = new VT[n];
v2 = new VT[n];
for(SIZE_T x = 0; x < n; ++ x){
v[x] = rand() * 65536 + rand();//随机数据
//v[x] = (rand() * 65536 + rand()) % 1000;//大量重复数据
//v[x] = n - x;//逆序
//v[x] = x;//正序(即已经排序好的)
}
init(v1,v,v + n);
test_time_funtion(sort,v1,v1 + n,"标准库sort",N);
//init(v2,v,v + n);//100000
//test_time_funtion(insert_sort,v2,v2 + n,"insert_sort",N);
//check(v2,v1,v1 + n);
//init(v2,v,v + n);
//test_time_funtion(sort_kn_base,v2,v2 + n,"sort_kn_base",N);
//check(v2,v1,v1 + n);
//init(v2,v,v + n);
//test_time_funtion(sort_kn_base1,v2,v2 + n,"sort_kn_base1",N);
//check(v2,v1,v1 + n);
//init(v2,v,v + n);
//test_time_funtion(sort_kn_base2,v2,v2 + n,"sort_kn_base2",N);
//check(v2,v1,v1 + n);
//init(v2,v,v + n);
//test_time_funtion(sort_kn_base3,v2,v2 + n,"sort_kn_base3",N);
//check(v2,v1,v1 + n);
//init(v2,v,v + n);
//test_time_funtion(sort_kn_1,v2,v2 + n,"sort_kn_1",N);
//check(v2,v1,v1 + n);
init(v2,v,v + n);
test_time_funtion(sort_kn_2,v2,v2 + n,"sort_kn_2",N);
check(v2,v1,v1 + n);
delete v;
delete v1;
delete v2;
return 0;
}
inline unsigned __int64 GetCycleCount()//测量时间的计数器,返回的是计数值,不是绝对时间值.
{
__asm _emit 0x0F
__asm _emit 0x31
}
//非递归方式最方便的就是直接模拟堆栈.
//实质上还是递归,只不过是自己维护堆栈,
void _sort_kn_4(pVT pBeg,SIZE_T n){
vector<pair<pVT,SIZE_T> > v;
v.resize(50);
v.clear();
v.push_back(pair<pVT,SIZE_T> (pBeg,n));
if(n < 2)
return ;
if(n < 32){
_insert_sort(pBeg,n);
return ;
}
for(;v.size();){
pVT pDest = (v.end() - 1)->first;
SIZE_T n = (v.end() - 1)->second;
v.pop_back();
if(n < 2)
continue;
if(n < 32){
_insert_sort(pDest,n);
continue;
}
SIZE_T i = __divide_min(pDest,n,find_rand(pDest,n));
if(i < n / 2){
v.push_back(pair<pVT,SIZE_T>(pDest,i));//缓存数量较小的部分
}
else{
v.push_back(pair<pVT,SIZE_T>(pDest + i + 1,n - i - 1));
}
if(i < n / 2){
SIZE_T t = find_rand(pDest + i + 1,n - i - 1);
if(*(pDest + i) == *(pDest + i + 1 + t))
t = __divide_equal(pDest + i + 1,n - i - 1,t);
else{
t = __divide_min(pDest + i + 1,n - i - 1,t);
v.push_back(pair<pVT,VT>(pDest + i + 1,t));
}
v.push_back(pair<pVT,VT>(pDest + i + 1 + t + 1,n - i - t - 1 - 1));
}
else{
SIZE_T t = __divide_min(pDest,i,find_rand(pDest,i));
v.push_back(pair<pVT,VT>(pDest,t));
v.push_back(pair<pVT,VT>(pDest + t + 1,i - t - 1));
}
}
}
//在基本快速排序里有个试验,在有大量重复元素时,进行划分出中值,这个是一个合理的方案,
//就这个思路加入剔除和中值相等的元素操作.
void _sort_kn_2(pVT pDest,SIZE_T n){
if(n < 2)
return ;
if(n < 32){
_insert_sort(pDest,n);
return ;
}
SIZE_T i = __divide_min(pDest,n,find_rand(pDest,n));
_sort_kn_2(pDest,i);
n -= i;
pDest += i;
if(n < 2)
return ;
if(n < 32){
_insert_sort(pDest,n);
return ;
}
i = find_rand(pDest,n);
if(*pDest == *(pDest + i))
//如果第二次随机值仍然相同,由于是随机值,两次都相同因此大致考虑为和中值相等的值较多,可以考虑剔除相等的.
//如果不同,则看成是对这部分进行了一次划分.
//这里可以注意的,这里随机选值包含了上一次划分剩下的那个中值.
//如果比较相等比较多花销,可以考虑把那个剔除,但程序稍微复杂点.
i = __divide_equal(pDest,n,0);
else{
i = __divide_min(pDest,n,i);
_sort_kn_2(pDest,i);
}
_sort_kn_2(pDest + i + 1,n - i - 1);
}
void sort_kn_2(pVT pBeg,pVT pEnd){
if(pBeg + 1 < pEnd)
_sort_kn_2(pBeg,pEnd - pBeg);
}
//晚上考虑递归深度问题.
//由于考虑如果直接所使用随机可能出现极坏的情况,因此在选取随机值时用若干个值的中值作为中值.
//我这里选择两个固定点,和一个随机位置.这三个的中值返回.
//我看过标准库,似乎里面选择的是9个(分成3组)固定位,这三组的中值再进行选取中值作为返回.
//这里简单起见,只用3个元素,感觉如果3个都用随机位置,开销大点,而且效果似乎差不多.
SIZE_T find_rand(pVT pDest,SIZE_T n){
SIZE_T n1 = n / 4,n2 = n - n/4,n3;
if(n < 256)
n3 = n / 2;
else
n3 = rand() % n;
if(*(pDest + n2) < *(pDest + n1))
swap_kn(*(pDest + n2),*(pDest + n1));
if(*(pDest + n3) < *(pDest + n2))
swap_kn(*(pDest + n3),*(pDest + n2));
if(*(pDest + n2) < *(pDest + n1))
swap_kn(*(pDest + n2),*(pDest + n1));
return n2;
}
void _sort_kn_1(pVT pDest,SIZE_T n){
if(n < 2)
return ;
if(n < 32){//这个考虑到递归层数可能太深,而且数据少时继续用随机排序花销比例就大了
//32是参考标准库的划分的
_insert_sort(pDest,n);
return ;
}
SIZE_T i = __divide_min(pDest,n,find_rand(pDest,n));
_sort_kn_1(pDest,i);
_sort_kn_1(pDest + i + 1,n - i - 1);
}
void sort_kn_1(pVT pBeg,pVT pEnd){
if(pBeg + 1 < pEnd)
_sort_kn_1(pBeg,pEnd - pBeg);
}
//由于sort_kn_base2里有可能出现中值是极大或极小值,从而退化到每次划分只能剔除中值一个值
//因此在这里增加一次划分,直接划分出和比较基准值相同的,看看效果.
void _(pVT pDest,SIZE_T n){
if(n < 2)
return ;
if(n < 32){
_insert_sort(pDest,n);
return ;
}
SIZE_T i = __divide_min(pDest,n,rand() % n);
_sort_kn_base3(pDest,i);
n -= i;
pDest += i;
i = __divide_equal(pDest,n,0);//上面的划分位于i的值必然是val.
_sort_kn_base3(pDest + i,n - i);
}
void sort_kn_base3(pVT pBeg,pVT pEnd){//从测试时3比2慢,可以基本可以看出随便剔除最小值,并不划算.
//注:选用大量重复数据时,效果不错,要比base2快.
//基本的快速排序我的想法基本结束,下面就是围绕如何合理选择随机值 和 插入剔除比较值相等的操作
if(pBeg + 1 < pEnd)
_sort_kn_base3(pBeg,pEnd - pBeg);
}
void _sort_kn_base1(pVT pDest,SIZE_T n){
if(n < 2)
return ;
SIZE_T i = __divide_min(pDest,n,rand() % n);
_sort_kn_base1(pDest,i);
_sort_kn_base1(pDest + i + 1,n - i - 1);
}
void sort_kn_base1(pVT pBeg,pVT pEnd){
if(pBeg + 1 < pEnd)
_sort_kn_base1(pBeg,pEnd - pBeg);
}
//////////////////////////////////////////////////////////////////////////排序
void _insert_sort(pVT pDest,SIZE_T n){
if(n < 2)
return ;
for(SIZE_T x = 1;x < n;++ x){
for(SIZE_T i = x;i;-- i){
if(pDest[i] < pDest[i - 1])
swap_kn(pDest[i],pDest[i - 1]);
else
break;
}
}
}
void insert_sort(pVT pBeg,pVT pEnd){
if(pBeg + 1 < pEnd){
_insert_sort(pBeg,pEnd - pBeg);
}
}
//插入排序
//插入排序是我觉得在初级排序算法里一个比较简单而且在大部分情况都相当高效的
//一个算法.特意保留了下来,而且后面要用到的.
//这个是根据指定的num_val位置的值,划分为小于和不小于两部分.
SIZE_T __divide_min(pVT pDest,SIZE_T n,SIZE_T num_val){
swap_kn(* pDest,*(pDest + num_val));
VT val = *pDest;
SIZE_T i = 0,j = n - 1;
for(;i < j;){
while(i < j && !(*(pDest + j) < val)) -- j;
*(pDest + i) = *(pDest + j);
while(i < j && *(pDest + i) < val) ++ i;
*(pDest + j) = *(pDest + i);
}
*(pDest + i) = val;
return i;
}
//这个类似,划分为相当和大于两部分.(调用前已经确定是最小值了)
//实际上num_val确定是0了,为了统一形式,没取消.
SIZE_T __divide_equal(pVT pDest,SIZE_T n,SIZE_T num_val){
//cout<<"调用相同"<<*(pDest + num_val)<<endl;
swap_kn(* pDest,*(pDest + num_val));
VT val = *pDest;
SIZE_T i = 0,j = n - 1;
for(;i < j;){
while(i < j && val < *(pDest + j)) -- j;
*(pDest + i) = *(pDest + j);
while(i < j && *(pDest + i) == val) ++ i;
*(pDest + j) = *(pDest + i);
}
*(pDest + i) = val;
return i;
}
//典型的基本的快速排序结构.
void _sort_kn_base(pVT pDest,SIZE_T n){
if(n < 2)
return;
SIZE_T i = __divide_min(pDest,n,0);
_sort_kn_base(pDest,i);
_sort_kn_base(pDest + i + 1,n - i - 1);
}
void sort_kn_base(pVT pBeg,pVT pEnd){
if(pBeg + 1 < pEnd)
_sort_kn_base(pBeg,pEnd - pBeg);
}