快速排序算法是一种较为快速的排序算法,其平均时间复杂度为O (n*logn)。其算法思想是在序列中选取参考元素,将比参考元素小的元素都放到参考元素的左边,将比参考元素大的元素都放到参考元素的右面,这就完成了一趟排序。最后应用分治思想分别对参考元素两边的子序列进行排序。算法中一趟排序的步骤描述如下:
1. 选取参考元素,一般情况下以排序序列(设为array[])的第一个元素作为参考元素,设key为参考元素的初始下标,则key=0,参考元素表示为array[key]。
2. 设置头尾指针,头指针(start)指向序列的第一个元素,尾指针(end)指向序列的最后一个元素。
3. 首先从为指针开始,end指针不断前移(即end指针不断自减1),知道array[end]<array[key]或者end == start时,停止前移。交换array[end]与参考元素的值,并且更新参考元素的最新下标。
4. 当第3步完成后,不断后移start指针(即start指针不断自加1),直到出现array[start] >array[key]的值或者start == end时,停止后移。交换array[start]与参考元素的值,并且更新参考元素的下标。
5. 重复第3、4步骤,直到start == end,则一趟排序结束。
例如:对于以下序列进行从小到大的排序
下标 0 1 2 3 4 5 6 7 8
序列A: 2 2 4 9 7 6 3 1 5
初始时, key=0 end=8
start=0
首先,尾指针end不断前移,当移到下标为7处是 A[7] < A[key],所以交换A[7]和A[key]
此时序列变为:
下标 0 1 2 3 4 5 6 7 8
序列A: 1 2 4 9 7 6 3 2 5
s e
k=7
现在 临到头指针s不断后移,直到s=2时,A[2] > A[k],所以交换A[2] 、A[k]的值,交换后序列变为:
下标 0 1 2 3 4 5 6 7 8
序列A: 1 2 2 9 7 6 3 4 5
s e
k=2
现在又临到,尾指针前移了,直到移到e=2处,此时满足s==e,循环退出,一趟排序完成。如下图所示:
从这可以看出,在头指针或尾指针移动的过程中不仅要判断A[start]或A[end]与A[key]之间的大小关系
还要判断start是否小于end,如果是则循环完毕。在上里中如果不判断start是否小于end,则end会一直递减直到0,或者小于0,此时数组会出现越界的情况。
另外,从上面的例子可以看出,快速排序是不稳定的排序算法。
不稳定是指序列中的两个相等元素,在排序后他们的相对位置发生变化的现象。
在一开始是A[0] == A[1] == 2, 但一趟排序完成是,A[0]中的2跑到了A[2]的位置上,由A[1]的前面跑到了A[1]的后面
排序算法的C++实现代码:
void swap(vector<int>& vec,int left, int right)
{
/*用不开辟临时变量的方法交换两个数的值*/
vec[left] = vec[left] + vec[right];
vec[right] = vec[left] - vec[right];
vec[left] = vec[left] - vec[right];
/*使用临时变量的方法交换两个数的值*/
//int tmp = vec[left];
//vec[left] = vec[right];
//vec[right] = tmp;
}
void QuickSort(vector<int>& vec, int left, int right)
{
int key = left;
int r = right;
int l = left;
while (left < right) //此循环控制整个排序算法的结束(包含多趟排序)
{
/*
* 序列尾指针right不断向前移动,直到不满足条件
* 注意: 循环终止条件中的 left < right 是必要的,如果没有此条件,可能会出现
* right一直递减最终小于left的情况
*/
while (vec[right] >= vec[key] && left < right)
right--;
//交换尾指针指向的元素与参考元素的值,并且更新参考元素的小标
//注意:此处应判断while循环是否是因为vec[right] >= vec[key]条件不满足而终止,因为只有这种情况下
//我们才需要交换这两个元素的值
if (left < right)
{
swap(vec,key,right);
key = right;
}
// 序列头指针,不断前移,直到不满足前移条件为止
while (vec[left] <= vec[key] && left < right)
left++;
if (left < right)
{
swap(vec,key,left);
key = left;
}
}
//递归调用,对参考元素的两边的子序列分别进行排序
//注意: 为防止数组下标越界,应该做一些必要的判断
if (key -1 > l)
QuickSort(vec,l,key-1);
if (key + 1 < r)
QuickSort(vec,key+1,r);
}