快速排序算法是基于分治策略的另一个排序算法。它的基本思想是、:
(1)分解(divide):以数组a[p,r ]中的某一个数a[q]将数组分成三部分:a[1...q-1] a[q] a[q+1...r]。其中a[1...q-1]中的任何一个数都比a[q]小,而a[q+1...r]中的任何一个数都比a[q[]大。下标q在划分过程中确定。
(2) 递归求解(conquer):通过递归调用快速排序算法分别对a[1...q-1]和a[q+1...r]进行排序。
(3) 合并(merge):由于a[1...q-1]和a[q+1...r]的排序是就地进行的,即不需要花费额外的存储空间,即排序好后的结果仍然在a[ ]中。
快速排序的运行时间和每一次的划分是否对称有关,即每次划分所取的q都恰好为中值,即每一次的划分都产生两个大小为n/2的区域,此时,partition的时间复杂度为O(nlogn)。关于几种排序的时间复杂度怎么计算,将在另一篇博客中介绍。
不难想到,快速排序的最坏情况是每一次的划分,产生的是一个长度为1的数组以及一个长度为n-1的数组,这时,类似于冒泡排序,时间复杂度将为n^2。容易看到,快速排序的性能取决于划分的是对称性,通过修改partition函数,可以设计出采用随机选择策略的快速排序算法,当数组还没有被划分之前,可以在a[p,r]中随机选出一个元素作为基准,这样可以使得划分基准的选择是随机的,从而使得从概率上来讲,假设数组很大,则整体上来讲划分是比较对称的。
如何随机得到【a, b】内的整数?(包含a, b):
#include
#include
#include
using namespace std;
int main()
{
int a=0,b=11;
srand((unsigned)time(NULL));
for(int i = 0; i < 10;i++ )
cout << (rand() % (b-a+1))+ a << '\t';
cout << endl;
return 0;
}
全部代码:
#include
#include
#include
using namespace std;
int Random(int left, int right) //随机函数生成[left, righth]之间的一个整数
{
srand((unsigned)time(NULL));
int r = (rand() % (right-left+1))+ left;
return r;
}
int Partition(int a[], int left, int right)
{
int x = a[right]; //将输入数组的第rand个元素作为基准元,用它来对数组进行划分
int i = left - 1; //i为最后一个小于基准元的数的下标
for (int j = left; j < right; j++)//遍历下标由left到right-1的数
{
if (a[j] < x)//如果数小于基准元的话就将i向前挪动一个位置,并且交换j和i所分别指向的数
{
int temp;
i++;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
//经历上面的循环之后下标为从left到i(包括i)的数就均为小于x的数了,现在将主元和i+1位置上面的数进行交换
a[right] = a[i + 1];
a[i + 1] = x;
return i + 1;
}
//经历上面的之后下标为从left到i(包括i)的数就均为小于x的数了,而i+2到right的数则均不小于x
int RandommizedPartition(int a[], int p, int r)
{
int i = Random(p, r);
int temp = a[p];
a[p]=a[i];
a[i]=temp;
return Partition(a,p,r);
}
void RandommizedQuickSort(int a[], int left, int right)
{
if (left < right)
{
int q = RandommizedPartition(a, left, right);
RandommizedQuickSort(a, left, q - 1);
RandommizedQuickSort(a, q + 1, right);
}
}
int main()
{
int a[12];
int i, j, n;
cout<<"输入元素个数n:"<>n;
cout<<"输入n个元素:"<>a[i];
RandommizedQuickSort(a,0,n-1);
for(i=0;i