我眼中的快速排序.

knate 2010-06-20 10:01:03
基本上在这个版块里,每隔一个月,就会有一个讨论排序算法的主题飘上来.
几乎是每个月都来的东西了.
似乎这个月没来,不能破坏这个传统,是吧.
^_^

反正这个我只是当成学习笔记来记的.
喜欢的随便看看吧.

PS:
后面的代码有部分是网上不知道哪里找来的,年代久远了,已经找不到连接的.
只能对原作者说抱歉了.

不废话了,以下是检测函数用的代码.


#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;
}
...全文
210 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
knate 2010-06-26
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 yukuilongqq 的回复:]

用什么编译过的呀 我用dvc++ 怎么编译不过呀?
__asm _emit 0x0F

__asm _emit 0x31
有错呀
[/Quote]
不是无返回,而是返回值已经直接就存放在寄存器上.
这个嵌入了机器码.
详细的 搜索下关键字
__asm _emit 0x0F
估计google有很多很多详细的介绍.
如果出错的话,可能编译器不支持(CPU似乎是奔腾级以后就可以支持了,似乎现在CPU基本都支持),可以直接调用time 来测量时间.
没有本质上的区别.

PS:
顺带回复一下10楼:
这个不是有没有用的问题,而是直接就没有多少用处.
这些排序都是一些不成熟的方案.
离实际应用还有很远很远.
真的,很远很远.
我发这贴的最初目的是想找一些能对快速排序优化的方法.
YUKUILONGQQ 2010-06-24
  • 打赏
  • 举报
回复

inline unsigned __int64 GetCycleCount()//测量时间的计数器,返回的是计数值,不是绝对时间值.

{

__asm _emit 0x0F

__asm _emit 0x31

}


这什么意识呀 ??
__asm _emit 0x0F
__asm _emit 0x31
这两个是什么呀??
没参数 没return 怎么返回值呀?
xinzaiyiqi 2010-06-24
  • 打赏
  • 举报
回复
几种排序方法的用途都是在哪啊?
YUKUILONGQQ 2010-06-24
  • 打赏
  • 举报
回复
用什么编译过的呀 我用dvc++ 怎么编译不过呀?
__asm _emit 0x0F

__asm _emit 0x31
有错呀
knate 2010-06-22
  • 打赏
  • 举报
回复

//非递归方式最方便的就是直接模拟堆栈.
//实质上还是递归,只不过是自己维护堆栈,
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));
}
}
}

ithiker 2010-06-21
  • 打赏
  • 举报
回复
汇编看不太懂
AAA20090987 2010-06-21
  • 打赏
  • 举报
回复
菜鸟来学习一下
knate 2010-06-21
  • 打赏
  • 举报
回复

//在基本快速排序里有个试验,在有大量重复元素时,进行划分出中值,这个是一个合理的方案,
//就这个思路加入剔除和中值相等的元素操作.
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);
}
//晚上考虑递归深度问题.
knate 2010-06-21
  • 打赏
  • 举报
回复

//由于考虑如果直接所使用随机可能出现极坏的情况,因此在选取随机值时用若干个值的中值作为中值.
//我这里选择两个固定点,和一个随机位置.这三个的中值返回.
//我看过标准库,似乎里面选择的是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);
}
knate 2010-06-21
  • 打赏
  • 举报
回复
汇编的大概就是读取一个CPU内部还是哪里的一个计数器,好像叫什么时间戳什么的.似乎是硬件相关的.部分CPU似乎不支持.
反正是一个比较精确的计时器来的.可以达到指令级的

//由于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);
}

knate 2010-06-20
  • 打赏
  • 举报
回复
没什么意思.
只是把自己的一些笔记写上来尔尔.
好玩的话就看看吧.

sort_kn_base
的缺点是明显的,
由于每次划分都取第一个,并不能保证每次都能够划分差不多的大小的两部分.
因此,这次就不都去第一位,而是随机取其中的一个数,然后用他作为中值进行划分.
写成这样

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


超级大笨狼 2010-06-20
  • 打赏
  • 举报
回复
什么意思呢?
knate 2010-06-20
  • 打赏
  • 举报
回复

//////////////////////////////////////////////////////////////////////////排序
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);
}


首家100%开源可定制的房产中介ERP管理系统,手机、电脑、微信、Pad同步使用,内网、外网高级结合,四网合一、一站同步、提高工作效率、安全可靠、操作简单。 详细介绍: 开源可定制房产ERP解决方案: 功能完善的房源客源管理,同时提供完备的办公、财务、决策分析方案,内外一体全面打通;完全开放的源码,您可以自由掌控,任意开发您的专属功能;无店面和用户数限制,一次买断,永久使用;安全掌控您的软件服务器,隐私数据自己掌控,开单大师,为每家中介提供真正属于自己的定制软件。 整合微信平台:接力微信,快速分享。 内网管理ERP:功能全面,使用不同运营需求。 房客源管理:内外网同步,一站打通。 一体化外网同步设计思想:平台上搭建全部业务模块,不论是标准产品还是个性研发都遵循规范要求,包括取数规则,交互方式,界面样式和美工风格都全部有统一化标准。 产品特色: 技术方案成熟稳定,支持各类房产中介业务场景,平台集成内外网平台应用系统,帮您一站式快速搭建专属的房产中介平台。 房源管理:支持网络多门店,多人联网系统工作。中介网站无缝集成和微站无缝集成,提升中介门店服务能力,更高效。 权限和设置:各种角色和权限设置,不限门店,员工数量。可灵活设置每一位经纪人的权限,认证机器,可限制经纪人只能在门店内电脑登录。 全新智能激励辅助运营:根据个人业务动作所占成交比例预知业绩金额,发挥经纪人主观能动性,加速成交进程! 移动端应用:特色移动端应用,方便快捷查询管理。实时数据更新,事件准时提示。让您随心掌握,想改就改。 微信分享:经纪人可对自己的订单进行评价和分享,也可在微商城、圈子等多频道进行分享。 强大的财务报表分析中心:大数据智能分析业绩数据,了解业绩走势。门店损益状况一目了然,让门店运营状况尽在您的眼中! 在线客服:经纪人与客户随时沟通,轻松解决客户疑问,不在受疑难杂症的烦恼。 三大日志辅助运营:三大日志相辅相成,让一切尽在掌握,为您的数据安全提供优质的保护。 定制开发:开单大师为不同的要求,提供最适合的定制化解决方案。 除了以上特性,我们还用心为您准备了更多的贴心功能等待您的发现…… 常见问题: 1、开源可定制是什么意思 软件代码开放,懂技术的可以自己调整或者新增功能,如果自己对技术不太懂可以联系我们公司给您定制您需要的功能 2、房哨只能用于房产运营吗 房哨是针对房产运营开发的版本,可以多中介一起使用客户端,运营端进行管理,也可以单公司使用,除了房哨外还有针对其他房产开发的ERP管理系统,如果您需要其他行业的软件我们也可以给您定制开发 3、房哨如何安装 解压压缩包后有一个名为房哨1.3.6学习版的文件夹,打开文件夹中的1.3.6使用说明,里面有详细的安装步骤 更新日志: 1、清理了无用源码。 2、优化了运营端权限显示的排序。 3、解决了不能用安装时输入的管理员用户密码登录的问题。
首家100%开源可定制的房产中介ERP管理系统,手机、电脑、微信、Pad同步使用,内网、外网高级结合,四网合一、一站同步、提高工作效率、安全可靠、操作简单。详细介绍:开源可定制房产ERP解决方案:功能完善的房源客源管理,同时提供完备的办公、财务、决策分析方案,内外一体全面打通;完全开放的源码,您可以自由掌控,任意开发您的专属功能;无店面和用户数限制,一次买断,永久使用;安全掌控您的软件服务器,隐私数据自己掌控,开单大师,为每家中介提供真正属于自己的定制软件。整合微信平台:接力微信,快速分享。内网管理ERP:功能全面,使用不同运营需求。房客源管理:内外网同步,一站打通。一体化外网同步设计思想:平台上搭建全部业务模块,不论是标准产品还是个性研发都遵循规范要求,包括取数规则,交互方式,界面样式和美工风格都全部有统一化标准。产品特色:技术方案成熟稳定,支持各类房产中介业务场景,平台集成内外网平台应用系统,帮您一站式快速搭建专属的房产中介平台。房源管理:支持网络多门店,多人联网系统工作。中介网站无缝集成和微站无缝集成,提升中介门店服务能力,更高效。权限和设置:各种角色和权限设置,不限门店,员工数量。可灵活设置每一位经纪人的权限,认证机器,可限制经纪人只能在门店内电脑登录。全新智能激励辅助运营:根据个人业务动作所占成交比例预知业绩金额,发挥经纪人主观能动性,加速成交进程!移动端应用:特色移动端应用,方便快捷查询管理。实时数据更新,事件准时提示。让您随心掌握,想改就改。微信分享:经纪人可对自己的订单进行评价和分享,也可在微商城、圈子等多频道进行分享。强大的财务报表分析中心:大数据智能分析业绩数据,了解业绩走势。门店损益状况一目了然,让门店运营状况尽在您的眼中!在线客服:经纪人与客户随时沟通,轻松解决客户疑问,不在受疑难杂症的烦恼。三大日志辅助运营:三大日志相辅相成,让一切尽在掌握,为您的数据安全提供优质的保护。定制开发:开单大师为不同的要求,提供最适合的定制化解决方案。除了以上特性,我们还用心为您准备了更多的贴心功能等待您的发现……常见问题:1、开源可定制是什么意思软件代码开放,懂技术的可以自己调整或者新增功能,如果自己对技术不太懂可以联系我们公司给您定制您需要的功能2、开单大师只能用于房产吗目前开单大师只针对写字楼、商铺、二手房、新楼盘、新房分销等做了不同的版本,包括运营版也是针对房产中介开发的,不过如果您需要其他行业的软件我们也可以给您定制开发3、开单大师如何安装解压压缩包后有一个名为开单大师2.8.8学习版的文件夹,打开文件夹中的2.8.8使用说明,里面有详细的安装步骤更新日志:1、优化了自动开盘。2、删除了链接中的index.php。3、优化了房源打印模板的添加、更新。4、解决了新版列表页选择排序时非纯数字排序有误的问题。

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧