排序算法-快速排序

144 阅读3分钟

快速排序(Quick Sort)是一种常用的排序算法,它的核心思想是通过分治法(Divide and Conquer)来实现。它的步骤相对简单,但是能够高效地对数据进行排序。

基本思想

快速排序的基本思想可以概括为:

  1. 分解:选取一个基准元素(pivot),将数组分成两个子数组,左边的子数组中的元素都比基准元素小,右边的子数组中的元素都比基准元素大。
  2. 递归排序:对这两个子数组分别递归地应用快速排序算法。
  3. 合并:将排好序的子数组合并起来,得到最终的排序数组。

具体步骤

  1. 选择基准元素:从数组中选择一个元素作为基准(pivot)。通常选择第一个元素、最后一个元素或者随机选择。

  2. 分区过程:通过一趟排序将待排序的数组分成独立的两部分,其中一部分的所有元素都比基准元素小,另一部分所有元素都比基准元素大。这个过程称为分区(partition)操作。

    • 设置两个指针,左指针指向数组的起始位置,右指针指向数组的末尾。
    • 移动左指针直到找到一个大于等于基准元素的元素,移动右指针直到找到一个小于等于基准元素的元素,然后交换这两个元素。
    • 重复这个过程,直到左指针超过右指针。这时,右指针所在位置就是基准元素的最终位置,将数组分成了两个部分。
  3. 递归排序:对分区后的两个子数组递归地应用上述步骤,直到整个数组变成有序。

  4. 合并结果:当递归处理完所有子数组后,整个数组就变成了有序的。

示例

假设要对数组 [5, 2, 9, 3, 7, 6, 1, 8] 进行快速排序:

  1. 选择 pivot = 5(通常选择第一个元素作为基准)。
  2. 进行分区操作,最终数组可能变成 [3, 2, 1, 5, 7, 6, 9, 8],此时 pivot 的位置在第四个元素 5 处。
  3. 递归对左右两个子数组 [3, 2, 1] 和 [7, 6, 9, 8] 进行同样的操作,直到整个数组有序。

时间复杂度

快速排序的平均时间复杂度为 O(n log n),最坏情况下为 O(n^2)(如数组已经有序或基本有序的情况),空间复杂度为 O(log n)(递归调用的栈空间)。

/**  
* 交换排序-快速排序,O(n²),不稳定  
*  
* @param num  
* @param l 数组起始索引位置  
* @param r 数组末尾索引位置  
* @return  
*/  
public static int[] quickSort(int[] num, int l, int r) {  
    //r为数组元素总个数,last下标等于r-1  
    int first = l, last = r , key = num[first];  
    while (first < last) {  
        // 从右侧开始,跳过比基点大的元素,大的元素无需移动  
        while (first < last && num[last] >= key) {  
            last--;  
        }  
        //如果值小于 key分界值 交换  
        num[first] = num[last];  

        // 从左侧开始,跳过比基准小的元素,小的元素无需移动  
        while (first < last && num[first] < key) {  
            first++;  
        }  
        //如果值大于key分界值 交换  
        num[last] = num[first];  
    }  
    // 左右重合,找到基点位置  
    num[first] = key;  
    //递归左右部分进行快排  
    if (first > l) {  
        num = quickSort(num, l, first);  
    }  
    if (first + 1 < r) {  
        num = quickSort(num, first + 1, r);  
    }  

    return num;  
}

总结

快速排序是一种高效的排序算法,对于大部分数据集合,它的性能非常优秀。理解快速排序的核心在于理解分区过程和递归调用的思想,通过不断分割数组和合并结果,实现整体数组的排序。