导读 | 快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 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. 算法步骤
- 从数列中挑出一个元素,称为 "基准"(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
- 递归地(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); } }=>)、"大於"(>
递归法
实例
templatevoid 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); })、"大於"(>