堆排序和快排序,随更快?

bourneli-123 2010-03-17 10:42:32
我使用C++实现了快排序和堆排序,自己试验了一下,发现快排序比堆排序慢很多,不知道为什么。下面是我的代码:

//quick sort
int partition(int* arr,const int left,const int right){
int leIdx=left-1;
for(int i=left;i<=right-1;++i){
if(arr[i]<=arr[right]){
++leIdx;
swap(arr[leIdx],arr[i]);
}
}
swap(arr[leIdx+1],arr[right]);
return leIdx+1;
}

void quickSort(int* arr,const int left,const int right){
if(left<right){
int index=partition(arr,left,right);
quickSort(arr,left,index-1);
quickSort(arr,index+1,right);
}
}

void quickSort(int* arr,const int len){
quickSort(arr,0,len-1);
}


//heap sort
void heapDown(int* arr,const int idx,const int len){
if(idx>=static_cast<int>(len/2)){//该节点是叶子
return;
}

int maxSon=2*idx+1;//初始最大儿子是左儿子
if( maxSon+1<len && arr[maxSon+1]>arr[maxSon]){//如果右儿子存在,并且大于左儿子
++maxSon;
}

if(arr[maxSon]>arr[idx]){
swap(arr[maxSon],arr[idx]);
heapDown(arr,maxSon,len);
}
}

void buildHeap(int* arr,const int len){
for(int i=static_cast<int>(len/2)-1;i>=0;--i){
heapDown(arr,i,len);
}
}

void heapSort(int* arr,const int len){
buildHeap(arr,len);
for(int i=len-1;i>=1;--i){
swap(arr[0],arr[i]);
heapDown(arr,0,i);
}
}


//main 函数
#include "sort.h"
#include <iostream>
#include <string>
#include <ctime>
using namespace std;

int* generateRandom(int len,const int low,const int high){
::srand(time(NULL));
int* arr=new int[len];
for(int i=0;i<len;++i){
arr[i] = low+rand()%(high-low+1);
}
return arr;
}
void testSortFunction(const int* unsorted,int len,SortFunction sf,const string name){
int* arr=new int[len];
for(int i=0;i<len;++i){
arr[i]=unsorted[i];
}

clock_t start=clock();
sf(arr,len);//sort
clock_t end=clock();
cout<<name<<" Count "<<len<<" costs "<<(end-start)/(double)CLOCKS_PER_SEC<<" s"<<endl;

delete [] arr;
}

void main(int argc,char* argv[]){

const int N = 10000000;
int* unsorted = generateRandom(N,0,2000);

cout<<"Random Count: "<<N<<endl;
cout<<"******************************************************"<<endl;
testSortFunction(unsorted,N,quickSort,"Quick Sort");
testSortFunction(unsorted,N,heapSort,"Heap Sort");
cout<<"******************************************************"<<endl;

delete [] unsorted;
system("pause");
}


测试结果:
快排序 53.5秒
堆排序 4.906秒

为什么快速排序比堆排序慢这么多,请哪位算法大侠告诉我原因?
...全文
574 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
ischarles 2010-11-11
  • 打赏
  • 举报
回复
快排在最好和平均情况下比堆排快,堆排在最坏情况下比快排快~~
sztony 2010-08-29
  • 打赏
  • 举报
回复
楼主可能写错了,我以前写过快速排序和堆排序,

快排比堆要快很多,用5000万个记录测试,快速排序大概要快一倍左右。

进一步追踪,堆排序主要是堆调整的时间很耗时,90%的时间耗在堆调整上,

至于快速排序的最坏情况,一般是很难遇到的,每次从中间取一个数作为分割点,不要从第一个取!因为,假设数组是有序的话,每次取第一数做分割点,就有可能遭遇到最坏情况。

记得当时的测试是结果是:

快速排序最快,
其次是归并和希尔排序,
然后是堆排序。



knate 2010-03-29
  • 打赏
  • 举报
回复

// 123.cpp : 定义控制台应用程序的入口点。
//堆排序就没什么用了,这个版本的堆排序太慢了

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <windows.h>
#include <ctime>
#include <algorithm>

using namespace std;

//typedef std::vector<int>& VT;
typedef int* VT;

//递归调用次数太多 栈溢出!
void quick_sort_rec(int *a,int low,int high);
//非递归版 --迭代
void quick_sort(int *base,int start,int end);

//int _t;
inline void _swap_kn(int & a,int & b){
int _t;
_t = a;
a = b;
b = _t;
}

inline void _insert_sort_kn(VT v,unsigned int org_beg,unsigned int org_nd){//插入排序
if(org_nd <= org_beg)
return ;
int *p;
p = new int[org_nd - org_beg];
//p[0] = v[org_beg];
for(unsigned int x = 0;x < org_nd - org_beg;++x){
p[x] = v[org_beg + x];
for(unsigned int i = x;i;--i)
if(p[i] < p[i - 1])
_swap_kn(p[i],p[i-1]);
}
for(unsigned int x = 0;x < org_nd - org_beg;++x)
v[org_beg + x] = p[x];
delete [] p;
}

inline void _selet_sort_kn(VT v,unsigned int org_beg,unsigned int org_nd){//选择排序
for(unsigned int beg = org_beg,nd = org_nd;;++ beg,-- nd){
if(nd <= beg + 1 ){//数据长度不大于1 ,则返回
break;
}
if(nd - beg == 2){
if(v[nd - 1] < v[beg])
_swap_kn(v[beg],v[nd - 1]);
break;
}
if(nd - beg == 3){
if(v[beg + 1] < v[beg])//前面两个排序
_swap_kn(v[beg],v[beg + 1]);
if(v[beg + 2] < v[beg + 1])//前后两个排序/确定 v[beg + 2] 最大
_swap_kn(v[beg +1],v[beg + 2]);
if(v[beg + 1] < v[beg])//确定剩下两个
_swap_kn(v[beg],v[beg + 1]);
break ;
}
//beg,beg + 1,nd -2,nd -1 四个数中取极大极小值//beg,beg + x ,nd - 1 - x,nd -1
if(v[nd - 1] < v[beg])
_swap_kn(v[beg],v[nd - 1]);
for(unsigned int x =1;;++x){
if(beg + x < nd - 1 - x){
//cout<<v[beg]<<" "<<v[beg + x]<<" "<<v[nd - 1 - x]<<" "<<v[nd -1]<<endl;
if(v[nd - 1 - x] < v[beg + x])
_swap_kn(v[beg + x],v[nd - 1 - x]);
if(v[beg + x] < v[beg])
_swap_kn(v[beg],v[beg + x]);
if(v[nd - 1] < v[nd -1 - x])
_swap_kn(v[nd - 1 - x],v[nd - 1]);
//cout<<v[beg]<<" "<<v[beg + x]<<" "<<v[nd - 1 - x]<<" "<<v[nd -1]<<endl;
//cout<<endl;
}
else {
if(beg + x == nd - 1 - x){
//cout<<v[beg]<<" "<<v[nd - 1 - x]<<" "<<v[nd -1]<<endl;
if(v[beg + x] < v[beg])
_swap_kn(v[beg],v[beg + x]);
if(v[nd - 1] < v[nd - 1 - x])
_swap_kn(v[nd - 1 - x],v[nd -1]);
if(v[beg + x] < v[beg])
_swap_kn(v[beg],v[beg + x]);
//cout<<v[beg]<<" "<<v[nd - 1 - x]<<" "<<v[nd -1]<<endl;
}
break;
}
}
}
}

inline void _sort_kn(VT v,unsigned int org_beg,unsigned int org_nd){
if(org_nd <= org_beg)
return;
//无效数据,直接返回

if(org_nd - org_beg <= 32){
//insert_sort_kn(v,org_beg,org_nd);
_selet_sort_kn(v,org_beg,org_nd);
return ;
}
//
/*
if(org_nd - org_beg == 1)
return ;
if(org_nd - org_beg == 2){
if(v[org_beg + 1] < v[org_beg])
_swap_kn(v[org_beg +1],v[org_beg]);
return ;
}
if(org_nd - org_beg == 3){
if(v[org_beg + 1] < v[org_beg])
_swap_kn(v[org_beg + 1],v[org_beg ]);
if(v[org_beg + 2] < v[org_beg])
_swap_kn(v[org_beg + 2],v[org_beg]);
if(v[org_beg + 2] < v[org_beg + 1])
_swap_kn(v[org_beg + 2],v[org_beg + 1]);
return ;
}
*/
int iVal = v[rand()%(org_nd - org_beg) + org_beg];
unsigned int min_top,max_beg;
//min_top = 0;
for(unsigned int x = org_beg,y = org_nd;;){
while(x < y)//x 不可能大于org_nd,不需要这个边界
if(v[x] < iVal) ++x;
else
break;
//这里返回相等,说明x左边的数都是小于iVal的

while(x < y)//y - 1 不可能小于org_beg,不需要这个边界,y - 1 == x 是有可能的的.
if(!(v[y -1] < iVal)) -- y;
else
break;
//这里返回相等,则说明剩余的数都不小于iVal的,这时末端迭代器y - 1之后的应该都是不小于iVal的
//y - 1指向的应该是x的前一个,即 y-1 == x - 1即x== y
//即当x == y时, x 是min的末端迭代器,y - 1是不小于的末端迭代器,即y是指向最开始一个不小于iVal的数
if(x == y){//如果是由于在剩余范围内没有了不小于iVal的数据,即确定min_top边界为此时的x
min_top = x;
break;
}
// x y-1 不可能取等值,一个数步可能同时小于又不小于一个数.
// if(x < y - 1 && 1 < y){//1<y 即 y - 1 > 0 ,保证y - 1 是有效值 ,x < y - 1 即不小于值在左边,不小于值在右边,该数据有效
//前面已经保证了迭代器指向是必然有效的,因此 条件判断取消
_swap_kn(v[x],v[y-1]);


}
//max_beg = org_nd;
for(unsigned int x = min_top,y = org_nd;x != org_nd;){
while(x < y)
if(v[x] == iVal) ++ x;//查找最开始一个不等于iVal的数.
else
break;
//(x == y)说明剩余的都是相等
//x返回的是第一个不相等的数,如果后面没有了数据,则返回末端迭代器

while (x < y)
if(v[y -1] != iVal) -- y;//查找最后一个等于iVal的数
else
break;

if(x == y){//如果返回相等的末端迭代器,则确定max_beg边界.
max_beg = x;
break;
}
_swap_kn(v[x],v[y-1]);
}
_sort_kn(v,org_beg,min_top);
_sort_kn(v,max_beg,org_nd);
}

void sort_kn(VT v,unsigned int n){
_sort_kn(v,0,n);
}

class HEAP{
vector<int> v;
public:
HEAP(){v.resize(1);};
HEAP(const HEAP& source){v = source.v;};
HEAP(int n){v.resize(2);v[1] = n;};
void push_back(int );
int pop_back();
unsigned int size(){return v.size() - 1;};
~HEAP(){};
};

void HEAP::push_back(int val){
unsigned int n = v.size();
v.push_back(val);
;//有效数据起始的编号为1,0为无效标号,目的是为了表达式简便.
while(n > 1){
if(v[n] < v[n/2]){
_swap_kn(v[n],v[n/2]);
n /= 2;
}
else
break;
}
};

int HEAP::pop_back(){
if( !size())
return -1;//实际应该返回异常.

v[0] = v[1];
v[1] = *(v.rbegin());
if(size() == 1){
v.pop_back();
return v[0];
}
v.pop_back();
unsigned int n = 1;
for(;n < v.size();){ //v.size() == size() + 1//含义是编号起始为1开始的.
unsigned int x = n + n + 1;
if( x < v.size()){//还是满二叉树,应该原则上应该是 x <= size();
if(v[x - 1] < v[x])
-- x;//如果左子树最小,则选取左子树 x = n + n,否则选择右子树,x = n + n + 1;
if(v[x] < v[n]){
_swap_kn(v[n],v[x]);//如果根比子树还大,
n = x;
continue;
}
else
break;
}
else{//不是满二叉树,则只需要判断比较 可能还有的左叉树即可.返回
x = n + n;
if(x < v.size()){//左叉树还在.
if(v[x] < v[n])
_swap_kn(v[n],v[x]);
}
//已经没有给n赋值的必要了
//左叉树也没有.
break;
}
}

return v[0];;
};

void heap_sort(VT v,unsigned int n){
HEAP cHeap;
for(unsigned int x = 0;x < n;++x)
cHeap.push_back(v[x]);
for(unsigned int x = 0;x < n;++x)
v[x] = cHeap.pop_back();
}

int _tmain(int argc, _TCHAR* argv[])
{
Sleep(10);
srand((unsigned int) time(NULL));
const unsigned int n = 10000000;

//cin >>n;
vector<int> a;
a.resize(n);

int *b = new int[n];
int *c = new int[n];
int *d = new int[n];

for(unsigned int x = 0;x < n;++x)
a[x] = rand();
for(unsigned int x = 0;x < n;++x){
b[x] = a[x];
c[x] = a[x];
d[x] = a[x];
}

time_t t;
//for(unsigned int x = 0;x < n;++x)
// cout<<a[x]<<" ";
//cout<<endl;
for(unsigned int x = 0;x < n; ++x){
if(b[x] != d[x]){
cout<<"原始数据部正确"<<endl;
break;
}
}
t = clock();
//for(unsigned int x = 0;x < 100;++x)
sort(b,b + n );
//sort(b.begin(),b.end());
cout<<"STL sort花费时间"<<clock() - t<<endl;
//cout<<"STL sort"<<endl;
//for(unsigned int x = 0;x < n;++x)
// cout<<b[x]<<" ";
//cout<<endl;
t = clock();
//for(unsigned int x = 0;x < 100;++x)
//sort(b,b+n);
sort_kn(c,n);
cout<<"sort_kn花费时间"<<clock() - t<<endl;

// for(unsigned int x = 0;x < n;++x)
// cout<<a[x]<<" ";
// cout<<endl;
t = clock();
heap_sort(d,n);
cout<<"heap_sort花费时间"<<clock() - t<<endl;
// for(unsigned int x = 0;x < n;++x)
// cout<<a[x]<<" ";
// cout<<endl;
for(unsigned int x = 0;x < n;++x)
if(b[x] !=d[x]){
cout<<"算法不正确"<<endl;
cout<<"STL sort"<<endl;
for(unsigned int x = 0;x < n;++x)
cout<<b[x]<<" ";
cout<<endl;
cout<<"测试程序"<<endl;
for(unsigned int x = 0;x < n;++x)
cout<<d[x]<<" ";
cout<<endl;
break;
}
delete [] b;
delete [] c;
delete [] d;
return 0;
}




michael122 2010-03-26
  • 打赏
  • 举报
回复
做这种测试,你不能只生成一组数据,这样不可靠
你可以生成n组数据,求平均时间
即使是快排,也有不擅长的输入
ShineShineRedStar 2010-03-25
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 shineshineredstar 的回复:]

请问lz SortFunction 是怎么定义的?
[/Quote]
typedef void (*SortFunction)(int*, int);
jbz001 2010-03-25
  • 打赏
  • 举报
回复
你还是重新看看排序算法吧~!
ShineShineRedStar 2010-03-25
  • 打赏
  • 举报
回复
请问lz SortFunction 是怎么定义的?
knate 2010-03-24
  • 打赏
  • 举报
回复
一般来讲,感觉堆排序要比快速排序要慢几倍.
虽然说都是nlgn算法,
但是
快速排序的系数很小.堆排序次之,并归排序比较大.
但快速排序是不稳定的,并归是稳定的,堆排序要看具体实现.
michael122 2010-03-24
  • 打赏
  • 举报
回复
输入够随机的话,绝对是快排快啦,不然都对不起这个名字。。
zhongyijun159 2010-03-24
  • 打赏
  • 举报
回复
那是你的快速排序实现不好!!!经过良好设计的快速排序,一般情况下要比堆排序快2倍!!!其实,C/C++都无法体现它们两个的差别,想更深入比较,请看《The Art of Computer Programming》中对快速排序和堆排序的分析,那才是原子级别的比较。

想更好地实现快速排序,请参考:

1.《Quicksort》,by C.A.R. Hoare.
2.《Introduction to Algorithms》,中文《算法导论》,By Thomas H. Cormen,Charles E. Leiserson,Ronald L. Rivest,Clifford Stein.
3.《The Art of Computer Programming》,Volum3.Sorting and Searching.
by Ronald E. Knuth.
4.《Implementing quicksort programs》,by Robert Sedgewick.
5.《Algoritms》,by Robert Sedgewick.
6.《Algorithms in C, Parts 1-4: Fundamentals, Data Structures, Sorting, Searching (3rd Edition) (Pts. 1-4)》.by Robert Sedgewick.
7.《An Introduction to the Analysis of Algorithms》,by Robert Sedgewick.

还有几篇Robert Sedgewick关于快速排序的论文,忘记了,你可以搜搜。。。。

Robert Sedgewick是研究快速排序的集大成者,想很好的实现,他的文献不要错过。。。
ShineShineRedStar 2010-03-24
  • 打赏
  • 举报
回复
mark
knate 2010-03-23
  • 打赏
  • 举报
回复

void map_sort(VT v,unsigned int n){
map<int,int> vDest;
vDest.clear();

for(unsigned int x = 0;x < n;++x)
vDest[v[x]] ++;
unsigned int i = 0;

for(map<int,int>::iterator p = vDest.begin();p != vDest.end();++ p){
int temp = p->first;
for(int x = 0;x < p->second;++ x)
v[i++] = temp;
}
}
偷偷懒,调用一下现成的,
估计比楼主的堆排序要快.
如果不用模板的话.估计还要快.
yymt168 2010-03-19
  • 打赏
  • 举报
回复
小数据量排序,用冒泡,选择等排序比快排快

因为快排,堆栈比较费时。
yymt168 2010-03-19
  • 打赏
  • 举报
回复
比较的话,用抽象的数学方式比较才有意义
因为同一个算法,实现的人不同,效率不一样,测试数据不一样,差别也大
一个人实现不同的算法也有差异,擅长的算法,实现的往往效率高些,
kuzalid 2010-03-19
  • 打赏
  • 举报
回复
LZ要周全地考虑各种情况,堆排序的时间复杂为O(logn),即使在最坏情况~~
而快速排序在最坏情况下会达到O(N^2),当然也有优化的方法~
除非处理特别特别大数据量时用堆排序,一般情况下还是快排的好~
建议LZ试一下C库中的qsort()函数,看下时间如何,(stdlib.h)
troj2007 2010-03-19
  • 打赏
  • 举报
回复
学习了 哈哈
bourneli-123 2010-03-19
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 wizardoz 的回复:]
LZ怎么把已经排序的数据再给堆排序排啊?
堆排序在 buildHeap的时候就占了很大优势了。
[/Quote]
没有呀,我在testSortFunction方法中,都是将随机数组拷贝了一份,所以快排序和堆排序之间是没有影响的,现在发现满的原因是我的排序没有做优化。
bourneli-123 2010-03-19
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 raphaelcheung 的回复:]
应该是快排更快,你算法写错了
[/Quote]
我的快排没有做优化,所以导致很慢。
bourneli-123 2010-03-19
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 kuzalid 的回复:]
LZ要周全地考虑各种情况,堆排序的时间复杂为O(logn),即使在最坏情况~~
而快速排序在最坏情况下会达到O(N^2),当然也有优化的方法~
除非处理特别特别大数据量时用堆排序,一般情况下还是快排的好~
建议LZ试一下C库中的qsort()函数,看下时间如何,(stdlib.h)
[/Quote]
我用C++标准库的sort方法,发现的确比自己的堆排序快。估计,我自己只是实现了一个简单的快排序,没有考虑到优化部分,所以会比自己的堆排序慢很多。
谢谢你的提醒!
V68V6 2010-03-18
  • 打赏
  • 举报
回复
先弄清楚各个算法的适用场合

再考虑别的
加载更多回复(7)

33,008

社区成员

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

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