您的位置:首页 > 其它

排序算法-快速排序

2016-06-27 12:04 260 查看
#include<iostream>

using namespace std;

/*

快速排序的基本思想:随便选择其中一个元素,将它放在排好序时应该在的位置,并且保证它左边的元素都比它小或等于,右边的元素都比它大或等于,然后采用同样的方式,对左边和对右边依次递归进行排序,最后整个数组就排好序了。

可如何做到如上所说的呢,实现的方式有很多种,可以仔细分析一下,看哪种用代码实现起来比较简单;这里介绍其中一个方式,就是每次选择第一个元素作为要排序的元素,然后定义两个标号i和j,分别指向第一个元素和最后一个元素,从数组最后边j开始与选择的元素进行比较,当碰到比它小的元素时,i元素和j元素互换,并开始从前往后遍历,当碰到比它大的元素时i元素和j元素互换,然后再从j的位置往前遍历,依次重复以上步骤,直到i==j,此时,所选择的元素就放到了正确的位置,并且保证了前边都不大于它,后边都不小于它。然后使用递归的方式对前边和后边的元素分别排序。

代码实现要点:

1.首先要把所选择的元素放在合适的位置:

*定义两个指针,分别指向首尾。

*当首指针小于尾指针时,应该持续两头的循环。

*从尾指针开始遍历,如果尾指针小于首指针并且尾指针指向的元素大于等于关键字则应该将尾指针向前移动

*当尾指针碰到比key小的元素就应该交换尾指针和首指针指向的元素。

*并从首指针开始往后遍历,如果尾指针小于首指针并且首指针指向的元素小于等于关键字则应该将首指针向后移动

*当首指针碰到比key大的元素就应该交换尾指针和首指针指向的元素。

*依次进行上述循环,就可将该元素放到合适的位置。

*然后采用递归分别排序左边数组和右边数组。

*/

//代码解析

void QuickSort(int list[],int index1,int index2)

{

if(index1>=index2)//递归的终止条件应该为当要排序的数组中仅有一个或没有元素

return;

int key=list[index1];

int i=index1,j=index2;

while(i<j)//直到首尾指针重合

{

while(list[j]>=key&&i<j)//尾指针向前移动

j--;

list[i]=list[j];

list[j]=key;

while(list[i]<=key&&i<j)//首指针向后移动

i++;

list[j]=list[i];

list[i]=key;

}

QuickSort(list,index1,i-1);//递归排序左边

QuickSort(list,j+1,index2);//递归排序右边

}

//快速排序时间复杂度分析

/*

从以上分析可知,快速排序采用的是分治策略,即将整个数组分成更小的数组进行排序。

那么最好的情况是什么情况呢,应该说每次选取的关键元素在放到合适的位置后能保证左边的元素数和右边的元素数相等或相差不超过1

此时可以仔细分析一下:从整体看来,每次扫描整个数组能把尽可能多的元素放到合适的位置,排序越快。例如第一次扫描整个数组只将一个元素放在了合适的位置

第二次由于采用递归两边分别排序,因此能够将两个元素放在合适的位置,同理第三次应该能将四个放在合适的位置,因此:

1+2+4+8+...+2(k-1)次方=n,求解得k=log2(n+1),因此需要扫描整个数组的次数为log2(n+1)次,又由于每次扫描花费的时间为O(n),因此最好情况下时间复杂度为O(nlog(n))

同理可分析在最坏情况下是每次扫描只能将一个元素放到合适的位置,因此时间复杂度为O(n*n)。

当然,经过以上分析可以看出每次选择关键元素是非常重要的,选择好了当然就能提高效率了。因此在优化快速排序可以从这方面入手。

*/

/*

当然以上是一种比较通俗的理解,也可以通过主定理式证明:T(n) = 2*T(n/2) + n=nlogn

*/

int main()

{

int list[]={5,6,3,2,4,1,9,8,7,7};

QuickSort(list,0,9);

for(int i=0;i<10;i++)

cout<<list[i]<<" ";

cout<<endl;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: