用户登录
用户注册

分享至

快速排序简介

  • 作者: 一梦一轮回丶
  • 来源: 51数据库
  • 2022-09-20
导读 快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。

在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

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

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

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

快速排序的最坏运行情况是 O(n2),比如说顺序数列的快排。但它的平摊期望时间是 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=None, right=None):
    left = 0 if not isinstance(left,(int, float)) else left
    right = len(arr)-1 if not isinstance(right,(int, float)) else right
    if left < right:="" partitionindex="partition(arr," left,="" right)="" quicksort(arr,="" left,="" partitionindex-1)="" quicksort(arr,="" partitionindex+1,="" right)="" return="" arr="" def="" partition(arr,="" left,="" right):="" 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],">
Go

实例

func quickSort(arr []int) []int {
        return _quickSort(arr, 0, len(arr)-1)
}

func _quickSort(arr []int, left, right 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,="" left,="" right="" int)="" int="" {="" pivot="" :="left" index="" :="pivot" +="" 1="" for="" i="" :="index;" i=""><= right;="" i++="" {="" 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++

实例

//严蔚敏《数据结构》标准分割函数
 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;
    *x = *y;
    *y = t;
}

void quick_sort_recursive(int arr[], int start, int end) {
    if (start >= end)
        return;
    int 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--;="" swap(&arr[left],="" &arr[right]);="" }="" if="" (arr[left]="">= arr[end])
        swap(&arr[left], &arr[end]);
    else
        left++;
    if (left)
        quick_sort_recursive(arr, start, left - 1);
    quick_sort_recursive(arr, left + 1, end);
}

void quick_sort(int arr[], int len) {
    quick_sort_recursive(arr, 0, len - 1);
}
C++

函数法

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

迭代法

实例

// 参考:http://www.dutor.net/index.php/2011/04/recursive-iterative-quick-sort/
struct Range {
    int start, end;
    Range(int s = 0, int e = 0) {
        start = s, end = e;
    }
};
template  // 整數或浮點數皆可使用,若要使用物件(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 
void quick_sort_recursive(T arr[], int start, int 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  //整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)、"大於"(>)、"不小於"(>=)的運算子功能
void quick_sort(T arr[], int len) {
    quick_sort_recursive(arr, 0, len - 1);
}
软件
前端设计
程序设计
Java相关