1.6 快速排序

140 阅读3分钟

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。

快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高!它是处理大数据最快的排序算法之一了。虽然 Worst Case 的时间复杂度达到了 O(n²),但是人家就是优秀,在大多数情况下都比平均时间复杂度为 O(n logn) 的排序算法表现要更好,可是这是为什么呢,我也不知道。好在我的强迫症又犯了,查了 N 多资料终于在《算法艺术与信息学竞赛》上找到了满意的答案:

快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。

1. 算法步骤

  1. 从数列中挑出一个元素,称为 "基准"(pivot);
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

2. 动图演示


代码实现

JavaScript

实例

function quickSort(arr, left, right) {  
    var len = arr.length,  
        partitionIndex,  
        left = typeof left != 'number' ? 0 : left,  
        right = typeof right != 'number' ? len - 1 : right;  
  
    if (left < right) {  
        partitionIndex = partition(arr, left, right);  
        quickSort(arr, left, partitionIndex-1);  
        quickSort(arr, partitionIndex+1, right);  
    }  
    return arr;  
}  
  
function partition(arr, left ,right) {     // 分区操作  
    var pivot = left,                      // 设定基准值(pivot)  
        index = pivot + 1;  
    for (var i = index; i <= right; i++) {  
        if (arr[i] < arr[pivot]) {  
            swap(arr, i, index);  
            index++;  
        }          
    }  
    swap(arr, pivot, index - 1);  
    return index-1;  
}  
  
function swap(arr, i, j) {  
    var temp = arr[i];  
    arr[i] = arr[j];  
    arr[j] = temp;  
}  
function partition2(arr, low, high) {  
  let pivot = arr[low];  
  while (low < high) {  
    while (low < high && arr[high] > pivot) {  
      --high;  
    }  
    arr[low] = arr[high];  
    while (low < high && arr[low] <= pivot) {  
      ++low;  
    }  
    arr[high] = arr[low];  
  }  
  arr[low] = pivot;  
  return low;  
}  
  
function quickSort2(arr, low, high) {  
  if (low < high) {  
    let pivot = partition2(arr, low, high);  
    quickSort2(arr, low, pivot - 1);  
    quickSort2(arr, pivot + 1, high);  
  }  
  return arr;  
}  

Python

实例

def quickSort(arr, left=Noneright=None):  
    left = 0 if not isinstance(left,(intfloat)) else left  
    right = len(arr)-1 if not isinstance(right,(intfloat)) else right  
    if left < right:  
        partitionIndex = partition(arr, leftright)  
        quickSort(arr, left, partitionIndex-1)  
        quickSort(arr, partitionIndex+1right)  
    return arr  
  
def partition(arr, leftright):  
    pivot = left  
    index = pivot+1  
    i = index  
    while  i <= right:  
        if arr[i] < arr[pivot]:  
            swap(arr, i, index)  
            index+=1  
        i+=1  
    swap(arr,pivot,index-1)  
    return index-1  
  
def swap(arr, i, j):  
    arr[i], arr[j] = arr[j], arr[i]  

Go

实例

func quickSort(arr []int) []int {  
        return _quickSort(arr, 0, len(arr)-1)  
}  
  
func _quickSort(arr []int, leftright int) []int {  
        if left < right {  
                partitionIndex := partition(arr, left, right)  
                _quickSort(arr, left, partitionIndex-1)  
                _quickSort(arr, partitionIndex+1, right)  
        }  
        return arr  
}  
  
func partition(arr []int, leftright int) int {  
        pivot := left  
        index := pivot + 1  
  
        for i := index; i <= righti++ {  
                if arr[i] < arr[pivot] {  
                        swap(arr, i, index)  
                        index += 1  
                }  
        }  
        swap(arr, pivot, index-1)  
        return index - 1  
}  
  
func swap(arr []int, i, j int) {  
        arr[i], arr[j] = arr[j], arr[i]  
}  

C++

实例

//严蔚敏《数据结构》标准分割函数  
 int Paritition1(int A[], int low, int high) {  
   int pivot = A[low];  
   while (low < high) {  
     while (low < high && A[high] >= pivot) {  
       --high;  
     }  
     A[low] = A[high];  
     while (low < high && A[low] <= pivot) {  
       ++low;  
     }  
     A[high] = A[low];  
   }  
   A[low] = pivot;  
   return low;  
 }  
  
 void QuickSort(int A[], int low, int high) //快排母函数  
 {  
   if (low < high) {  
     int pivot = Paritition1(A, low, high);  
     QuickSort(A, low, pivot - 1);  
     QuickSort(A, pivot + 1, high);  
   }  
 }  

Java

实例

public class QuickSort implements IArraySort {  
  
    @Override  
    public int[] sort(int[] sourceArray) throws Exception {  
        // 对 arr 进行拷贝,不改变参数内容  
        int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);  
  
        return quickSort(arr, 0, arr.length - 1);  
    }  
  
    private int[] quickSort(int[] arr, int left, int right) {  
        if (left < right) {  
            int partitionIndex = partition(arr, left, right);  
            quickSort(arr, left, partitionIndex - 1);  
            quickSort(arr, partitionIndex + 1, right);  
        }  
        return arr;  
    }  
  
    private int partition(int[] arr, int left, int right) {  
        // 设定基准值(pivot)  
        int pivot = left;  
        int index = pivot + 1;  
        for (int i = index; i <= right; i++) {  
            if (arr[i] < arr[pivot]) {  
                swap(arr, i, index);  
                index++;  
            }  
        }  
        swap(arr, pivot, index - 1);  
        return index - 1;  
    }  
  
    private void swap(int[] arr, int i, int j) {  
        int temp = arr[i];  
        arr[i] = arr[j];  
        arr[j] = temp;  
    }  
  
}  

PHP

实例

function quickSort($arr)  
{  
    if (count($arr) <= 1)  
        return $arr;  
    $middle $arr[0];  
    $leftArray array();  
    $rightArray array();  
  
    for ($i 1$i count($arr); $i++) {  
        if ($arr[$i] > $middle)  
            $rightArray[] = $arr[$i];  
        else  
            $leftArray[] = $arr[$i];  
    }  
    $leftArray quickSort($leftArray);  
    $leftArray[] = $middle;  
  
    $rightArray quickSort($rightArray);  
    return array_merge($leftArray$rightArray);  
}  

C

实例

typedef struct _Range {  
    int start, end;  
} Range;  
  
Range new_Range(int s, int e) {  
    Range r;  
    r.start = s;  
    r.end = e;  
    return r;  
}  
  
void swap(int *x, int *y) {  
    int t = *x;  
    *x = *y;  
    *y = t;  
}  
  
void quick_sort(int arr[], const int len) {  
    if (len <= 0)  
        return; // 避免len等於負值時引發段錯誤(Segment Fault)  
    // r[]模擬列表,p為數量,r[p++]為push,r[--p]為pop且取得元素  
    Range r[len];  
    int p = 0;  
    r[p++] = new_Range(0, len - 1);  
    while (p) {  
        Range range = r[--p];  
        if (range.start >= range.end)  
            continue;  
        int mid = arr[(range.start + range.end) / 2]; // 選取中間點為基準點  
        int left = range.start, right = range.end;  
        do {  
            while (arr[left] < mid) ++left;   // 檢測基準點左側是否符合要求  
            while (arr[right] > mid) --right; //檢測基準點右側是否符合要求  
            if (left <= right) {  
                swap(&arr[left], &arr[right]);  
                left++;  
                right--;               // 移動指針以繼續  
            }  
        } while (left <= right);  
        if (range.start < right) r[p++] = new_Range(range.start, right);  
        if (range.end > left) r[p++] = new_Range(left, range.end);  
    }  
}  

递归法

实例

void swap(int *x, int *y) {  
    int t = *x;  
    *= *y;  
    *= t;  
}  
  
void quick_sort_recursive(int arr[], int startint end) {  
    if (start >= end)  
        return;  
    int mid = arr[end];  
    int left = startright = end - 1;  
    while (left < right) {  
        while (arr[left< mid && left < right)  
            left++;  
        while (arr[right>= mid && left < right)  
            right--;  
        swap(&arr[left], &arr[right]);  
    }  
    if (arr[left>= arr[end])  
        swap(&arr[left], &arr[end]);  
    else  
        left++;  
    if (left)  
        quick_sort_recursive(arr, startleft - 1);  
    quick_sort_recursive(arr, left + 1end);  
}  
  
void quick_sort(int arr[], int len) {  
    quick_sort_recursive(arr, 0, len - 1);  
}  

C++

函数法

sort(a,a + n);// 排序a[0]-a[n-1]的所有数.

迭代法

实例

参考:www.dutor.net/index.php/2…

struct Range {  
    int start, end;  
    Range(int s = 0, int e = 0) {  
        start = s, end = e;  
    }  
};  
template <typename T> // 整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)、"大於"(>)、"不小於"(>=)的運算子功能  
void quick_sort(T arr[], const int len) {  
    if (len <= 0)  
        return; // 避免len等於負值時宣告堆疊陣列當機  
    // r[]模擬堆疊,p為數量,r[p++]為push,r[--p]為pop且取得元素  
    Range r[len];  
    int p = 0;  
    r[p++] = Range(0, len - 1);  
    while (p) {  
        Range range = r[--p];  
        if (range.start >= range.end)  
            continue;  
        T mid = arr[range.end];  
        int left = range.start, right = range.end - 1;  
        while (left < right) {  
            while (arr[left] < mid && left < right) left++;  
            while (arr[right] >= mid && left < right) right--;  
            std::swap(arr[left], arr[right]);  
        }  
        if (arr[left] >= arr[range.end])  
            std::swap(arr[left], arr[range.end]);  
        else  
            left++;  
        r[p++] = Range(range.start, left - 1);  
        r[p++] = Range(left + 1, range.end);  
    }  
}  

递归法

实例

template <typename T>  
void quick_sort_recursive(T arr[], int startint end) {  
    if (start >= end)  
        return;  
    T mid = arr[end];  
    int left = start, right = end - 1;  
    while (left < right) { //在整个范围内搜寻比枢纽元值小或大的元素,然后将左侧元素与右侧元素交换  
        while (arr[left< mid && left < right//试图在左侧找到一个比枢纽元更大的元素  
            left++;  
        while (arr[right>= mid && left < right//试图在右侧找到一个比枢纽元更小的元素  
            right--;  
        std::swap(arr[left], arr[right]); //交换元素  
    }  
    if (arr[left>= arr[end])  
        std::swap(arr[left], arr[end]);  
    else  
        left++;  
    quick_sort_recursive(arr, start, left - 1);  
    quick_sort_recursive(arr, left + 1, end);  
}  
template <typename T> //整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)、"大於"(>)、"不小於"(>=)的運算子功能  
void quick_sort(T arr[], int len) {  
    quick_sort_recursive(arr, 0, len - 1);  
}  

参考地址:

github.com/hustcc/JS-S…

zh.wikipedia.org/wiki/%E5%BF…