快速排序

来源:互联网 发布:家用加湿器知乎 编辑:程序博客网 时间:2024/06/09 15:28

        对于包含n个数的输入数组,最坏情况排序运行时间为平方次。虽然快速排序在最坏情况下也是如此,但其平均性能却相当好:期望运行时间为O(n*lgn),因此常作为排序的最佳使用选择。

        下面将实现快速排序,并针对一些特殊情况作出改进。为了使每个头文件单独可用,因此重复编写了一些函数。每种具体实现见头文件注释。

        快速排序一:       

/*************************************************    这个版本的快速排序采用数组的第一个元素作为键值,每次分割以后均以此键值将数组划分为两部分!    这里数组分割是双闭区间,而不是STL的左闭右开~**************************************************/#ifndef Quick_Sort1_H#define Quick_Sort1_H/****************************************************//****************************************************///数组分割部分template <typename Type>int Partition(Type array[],int begin,int end){//键值确定Type key=array[begin];while(begin<end){while(array[begin]<key)++begin;while(array[end]>key)--end;
<span style="white-space:pre"></span>//后面也应该有,但前期写的时候没有注意这个bug
<span style="white-space:pre"></span>if(begin<end)
<span style="white-space:pre"></span>{<span style="white-space:pre"></span>//交换过程<span style="white-space:pre"></span>Type temp=array[begin];<span style="white-space:pre"></span>array[begin]=array[end];<span style="white-space:pre"></span>array[end]=temp;
<span style="white-space:pre"></span>}}//返回的是键值所在元素位置,以此元素位置将数组划分为两部分return begin;}/****************************************************//****************************************************///快速排序部分template <typename Type>void Quick_Sort(Type array[],int begin,int end){if(begin<end){   int middle=Partition(array,begin,end);   Quick_Sort(array,begin,middle-1);   Quick_Sort(array,middle+1,end);}}/****************************************************/#endif

          快速排序二:

/********************************************************    对于Quick_Sort1.h中的排序,由于每次都是使用第一个作为键值,很有可能出现分割不均匀的情况,从而影响排序的性能。    对于数组元素分布比较随机的情况,可以考虑采用随机的方法选取键值,这样在整体性能上会优于Quick_Sort1.h中的排序算法。**********************************************************/#ifndef Quick_Sort2_H#define Quick_Sort2_H/****************************************************//****************************************************///分割数组部分template <typename Type>int Partition(Type array[],int begin,int end){//随机选取一个元素作为键值int r=begin+rand()%(end-begin);Type key=array[r];while(begin<end){while(array[begin]<key)++begin;while(array[end]>key)--end;
<span style="white-space:pre"></span>Type temp=array[begin];array[begin]=array[end];array[end]=temp;}return begin;}/****************************************************//****************************************************///快速排序部分template <typename Type>void Quick_Sort(Type array[],int begin,int end){if(begin<end){   int middle=Partition(array,begin,end);   Quick_Sort(array,begin,middle-1);   Quick_Sort(array,middle+1,end);}}/****************************************************/#endif


        快速排序三: 

/************************************************    在SGI STL中,提供了一种采用三端取键值的方法,即选取头端,尾端和中端的中间值作为键值来进行分割。这样在一般情况下可以取得一个比较平均的性能。************************************************/#ifndef Quick_Sort3_H#define Quick_Sort3_H/***********************************************///选取中值template <typename Type>Type Medium(Type a,Type b,Type c){if(a>b){if(b>c)return b;  //a>b>cif(a>c)return c;  //a>c>belsereturn a;  //c>a>b}else{if(b<c)return b;  //a<b<cif(a<c)return c;  //a<c<belsereturn a;}}/****************************************************//****************************************************///分割数组部分template <typename Type>int Partition(Type array[],int begin,int end){int middle=begin+(end-begin)/2;Type key=Medium(array[begin],array[middle],array[end]);while(begin<end){while(array[begin]<key)++begin;while(array[end]>key)--end;Type temp=array[begin];array[begin]=array[end];array[end]=temp;}return begin;}/****************************************************//****************************************************///快速排序部分template <typename Type>void Quick_Sort(Type array[],int begin,int end){if(begin<end){   int middle=Partition(array,begin,end);   Quick_Sort(array,begin,middle-1);   Quick_Sort(array,middle+1,end);}}/****************************************************/#endif


        快速排序4:

/************************************************    在数组基本有序的情况下,采用直接插入排序会比继续进行快速排序可能具有更好的性能,主要在于函数调用是一种比较昂贵的操作。    因此本算法在快速排序使得数组已经基本有序的情况下,进行直接插入排序来代替快速排序,从而在一定程度上提高排序的速度。************************************************/#ifndef Quick_Sort4_H#define Quick_Sort4_H/***********************************************///直接插入排序template <typename Type>void Insert_Sort(Type array[],int size){for(int i=1;i<size;++i){Type temp=array[i];while(true){if(array[i-1]>temp){array[i]=array[i-1];     --i;}elsebreak;}array[i]=temp;}}/***********************************************///数组分割,采用随机选取键值的方法template <typename Type>int Partition(Type array[],int begin,int end){//随机选取一个元素作为键值int r=begin+rand()%(end-begin);Type key=array[r];while(begin<end){while(array[begin]<key)++begin;while(array[end]>key)--end;Type temp=array[begin];array[begin]=array[end];array[end]=temp;}return begin;}/****************************************************//****************************************************///快速排序部分,此部分仅供内部使用template <typename Type>void _Quick_Sort(Type array[],int begin,int end){if(end-begin>5){int middle=Partition(array,begin,end);_Quick_Sort(array,begin,middle-1);_Quick_Sort(array,middle+1,end);}}/***********************************************///真正的快速排序过程,在基本有序的情况下采用直接//插入排序template <typename Type>void Quick_Sort(Type array[],int begin,int end){_Quick_Sort(array,begin,end);Insert_Sort(array,end-begin+1);}#endif/***********************************************/


    快速排序五:   

/*************************************************    函数调用是一种比较昂贵的操作,对于快速排序来说,如果每次划分都是出现存在一个分组只有一个元素的情况,那么其性能将会变得很差。    因此,另一种改进的方式是跟踪递归的层次,如果出现递归层次过深的情况,则采用性能稍高的堆排序算法进行排序。**************************************************/#ifndef Quick_Sort5_H#define Quick_Sort5_Hconst int DEPTH=5;int depth=0;/****************************************************/int Log(int x){int n=0;int sum=0;int temp=1;while(sum<x){++n;temp*=2;sum+=temp;}return n;}/****************************************************///堆排序template <typename Type>void Adjust_Heap(Type array[],int size,int i){int left=2*i+1;int right=left+1;while(right<size){//节点值已经大于左右节点值if(array[i]>array[left]&&array[i]>array[right])return;//右节点值较大if(array[left]<array[right]){Type temp=array[i];array[i]=array[right];array[right]=temp;i=right;}//左节点值较大else{Type temp=array[i];array[i]=array[left];array[left]=temp;i=left;}left=2*i+1;right=left+1;}//只有左子树的情况if(left<size){if(array[left]>array[i]){Type temp=array[i];array[i]=array[left];array[left]=temp;}}}//堆排序过程template <typename Type>void Sort_Heap(Type array[],int size){//建堆过程for(int i=size-1;i>=0;i--)Adjust_Heap(array,size,i);//排序过程for(int i=size-1;i>=0;i--){Type temp=array[0];array[0]=array[i];array[i]=temp;Adjust_Heap(array,i,0);}}/****************************************************//****************************************************///分割数组部分template <typename Type>int Partition(Type array[],int begin,int end){//随机选取一个元素作为键值int r=begin+rand()%(end-begin);Type key=array[r];while(begin<end){while(array[begin]<key)++begin;while(array[end]>key)--end;Type temp=array[begin];array[begin]=array[end];array[end]=temp;}return begin;}/****************************************************//****************************************************///快速排序部分template <typename Type>void Quick_Sort(Type array[],int begin,int end){++depth;if(Log(depth)>DEPTH){Sort_Heap(array,end-begin+1);return;}if(begin<end){   int middle=Partition(array,begin,end);   Quick_Sort(array,begin,middle-1);   Quick_Sort(array,middle+1,end);}}/****************************************************/#endif


        结合上述排序三、四和五,其实就是SGI STL中sort函数的实现方法,该方法采用三端法取键值,在数组基本有序的情况下采用直接插入排序来避免递归所付出的代价,而对于递归层次过深的情况(由于分割不均所造成),则采用相对较稳定的堆排序算法。当然,快速排序并非放之四海而皆准,实际应用中要根据数据的情况来选择合适的排序算法。

0 0
原创粉丝点击