首页 > 代码库 > 快速排序小结

快速排序小结

  快速排序,正如其名,是在平均情况下速度最快的排序,在平均情况下为2ln2(nlogn),大约为1.39nlogn,在同样复杂度为O(nlogn)的排序算法中,是常系数最小的算法,其最坏情况虽然可以高达O(n^2),但是采用改进的随机化快排算法,可以极大的降低最坏情况的出现概率。不仅如此,快速排序还是一个可以原地运行的算法,其运行时所需要的运算空间只有O(1)。在实际使用中,快速排序的表现大大优于归并排序等其他算法,因此快速排序为迄今为止工业上使用最多的排序算法。

  快速排序采用了分治的思想,将整个排序的问题分解为了若干个子问题,在每个子问题中,我们选取一个轴点pivot(通常选用第一个元素),在经过一次处理之后,我们应该保证轴点左边的元素总是不大于轴点,同时保证右边的元素不小于轴点;于是显然轴点在经过一次处理之后必然是正确的出现在其正确的位置,于是问题就分解为了轴点左侧元素的排序和轴点右侧元素的排序。之后我们运用递归的思想处理剩下的子问题即可。

  在最坏情况下,即元素已经正确的就位或者已经逆序就位,每次划分问题只会得到一个规模为0的子问题和一个规模为n-1的子问题。所以整个问题的时间复杂度呈现一个算术级数,也就是O(n^2)。为了避免这种情况,我们可以在每次处理之前采用随机化选取轴点的策略。具体来说,在每次选取轴点之前,随机选择一个问题中的元素与第一个元素交换位置,之后依然选取第一个元素为轴点即可。

  具体兑换为代码,我们可以定义两个指向当前正在操作元素的指针low和high,让low指向第一个元素,让high指向最后一个元素,之后将第一个元素的值取出备份作为轴点,于是第一个元素的位置就空了出来,之后从最后一个元素开始向前比较,找出第一个不满足轴点右侧元素属性的元素,也即严格小于轴点的元素,将其赋值给轴点所在位置,于是这个位置又空了出来,之后再从轴点所在位置向后进行比较,找到严格大于轴点的元素,并将其赋值给当前空出的位置。如此循环往复,直到当前操作的两个元素指针相等,这时指针low左侧的元素必然不大于轴点,指针high右侧的元素必然不小于轴点,而由于两个元素指针相等,所以其指向的位置必然是空出的,这时只需要将备份出的轴点赋值到这个位置就完成了一次划分算法,之后只要在尾部递归的解决剩下的问题,并将递归基,也即元素指针本来就指向一个元素的情况,加入到算法开头,就完成了我们的快速排序算法。

void quickSort(int* a ,int low,int high) {
    if (high <= low)
        return;
    int first = low;
    int last = high;
    int key = a[first];
    while (low < high) {
        while (low < high&&key <= a[high])
            high--;
        a[low] = a[high];
        while (low < high&&a[low] <= key)
            low++;
        a[high] = a[low];
    }
    a[high] = key;  //轴点就位
    quickSort(a, first, high - 1);    //采用尾递归处理子问题
    quickSort(a, high + 1, last);
}

 

快速排序小结