快速排序

快速排序是从冒泡排序演变而来的算法,但是比冒泡排序要高效得多,所以叫做快速排序。

快速排序之所以快速,是因为它使用了分治法,同冒泡排序一样,快速排序也属于交换排序,通过元素之间的比较和交换位置来达到排序的目的。

不同的是,冒泡排序在每一轮只把一个元素冒泡到数列的一端,而快速排序在每一轮挑选一个基准元素,并让其他比它大的元素移动到数列一边,比它小的元素移动到数列的另一边,从而把数列拆解成了两个部分。

image-20210609224738744

基本思想

  • 先从数列中取出一个数作为基准数。

  • 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。

  • 再对左右区间重复第二步,直到各区间只有一个数。

性能

时间复杂度为O(nlgn),与归并排序不同,该算法占用常数级额外存储,在大规模序列排序应用中性能较好。

基准元素如何选择呢?

基准元素,英文pivot,用于在分治过程中以此为中心,把其他元素移动到基准元素的左右两边。

那么基准元素如何选择呢?

最简单的方式是选择数列的第一个元素,但是如果有一个原本逆序的数列,期望排序成顺序数列,那么会出现什么情况:这种极端情况下,快速排序需要进行n轮,时间复杂度退化成了n^2。

递归实现

void quick_sort(vector<int>& nums, int l, int r)
{
    if(l+1 > = r)
    {
        return;
    }

    int first = l, last = r - 1, key = nums[first];
    while(first < last)
    {
        while(first < last && nums[last] >= key)
        {
            --last;
        }
        nums[first] = nums[last];

        while(first < last && num[first] <= key)
        {
            ++first;
        }
        num[last] = num[first];
    }
    nums[first] = key;
    quick_sort(nums, l, first);
    quick_sort(nums, first+1, r);
}

非递归实现

#include<iostream>
#include<stack>
#include<stdlib.h>
using namespace std;
int Partition(int *data, int low, int high)
{
    int temp = data[low];
     while(low < high)
     {
        while(data[j] > temp)
        {
            high--;
        }
        if(low < high)
        {
            data[low] = data[high];
        }
        while(data[i] < temp)
        {
            low++;
        }
        if(low < high)
        {
           data[j] = data[i];
        }       
    }
    data[low] = temp;    //low == high
    return low;
}

void QuickSort(int *data, int len)
{
    if(data == NULL || len <= 0)
    {
        return;
    }
    stack<int> st;
    int low = 0;
    int high = len -1;
    st.push(low);
    st.push(high);
    while(!st.empty())
    {
        high = st.top();st.pop();
        low = st.top();st.pop();
        int par = Partition(data, low, high);
        if(low < par - 1)
        {
            st.push(low);
            st.push(par - 1);
        }
        if(high > par + 1)
        {
            st.push(par + 1);
            st.push(high);   
        }
    }
}