《算法导论》学习笔记——快速排序
快速排序
1.快速排序原理
快速排序是一种应用很广泛的排序算法,与归并排序类似,快速排序也采用了分治策略。对于一个待排序的数组A[p...r]进行快速排序,根据分治思想,可以分为如下三个步骤:
- 分解:数组A[p...r]被划分为两个(有可能为空)子数组A[p...q-1]和A[q+1...r],使得A[p...q-1]中的每一个元素都小于等于A[q],而A[q]也小于等于A[q+1...r]中的每一个元素。其中,计算下标q也是划分过程的一部分。
-解决:通过递归调用快速排序,对子数组A[p...q-1]和A[q+1...r]进行快速排序。
-合并:注意到与归并排序不同,快速排序算法中的子数组都是基于原址排序的,所以不需要合并操作,即数组A[p...r]已经排好了顺序。
对于快速排序来说,算法的关键是找到正确的划分q,该过程的伪代码如下:
PARATITION(A, p, r)
x = A[r]
i = p - 1
for j = p to r - 1
if A[j] <= A[r]
i = i + 1
exchange A[i] with A[j]
exchange A[i + 1] with A[r]
return i + 1
下面这张图显示了该过程。
随着算法的执行,数组被划分为4个(可能为空)区域,如下图所示:
1. 若p <= k <= i,则A[k] <= x;
2. 若i+1 <= k <= j-1,则 A[k] >x;
3. 若j < k < r,则A[k]与x的大小关系不明确;
4. 若k = r,则A[k] = r。
2.快速排序的性能
根据上面的分析,快速排序的运行时间依赖于对待排序数组A[p...r]的划分是否平衡,而是否划分平衡依赖于划分元素的选取,如果划分是平衡的,那么快速排序算法性能与归并排序一样;如果划分不平衡,那么快速排序的性能就接近于插入排序了,注意这里是接近,而不是相等!
结论:平均情况下,快速排序的时间复杂度与最好划分情况下数量级一致,均为O(nlogn),注意这里是数量级一致并不意味着时间复杂度相等!
3.快速排序的随机化版本
上述的快速排序在讨论平均性能时我们假设输入数据的所有排列都是等概的。但实际情况可能并非如此,有可能出现元素大小分布极不均衡的情况。可以采用一种称为随机抽样(random sampling)的随机化技术,使主元A[r]是一个随机抽取于数组中的元素,因为主元元素是随机抽取的,我们期望在平均情况下,对输入数组的划分是比较均衡的。采取这样的操作只需要在原来的算法上改动很小的部分即可,伪代码如下:
RANDOMIZED-PARTITION(A, p, r)
i = RANDOM(p, r)
exchange A[r] with A[i]
return PARATITION(A, p, r)
4.代码实现(C/C++,Java,Python)
实现了快速排序最基本算法,没有考虑随机化版本=。=
C
#include <stdio.h>
#include <stdlib.h>
void swap(int* a, int* b) {
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
int partition(int* array, int low, int high) {
int mid, index;
mid = low - 1;
for(index = low; index < high; index++){
if(array[index] <= array[high]) {
mid += 1;
swap(&array[mid], &array[index]);
}
}
swap(&array[mid + 1], &array[high]);
return mid + 1;
}
void quicksort(int* array, int low, int high) {
int mid;
if(low < high){
mid = partition(array, low, high);
quicksort(array, low, mid - 1);
quicksort(array, mid + 1, high);
}
}
int main() {
int *array, length, i;
printf("Enter the length of array: ");
scanf("%d", &length);
array = (int* )malloc(length * sizeof(int));
for(i = 0; i < length; i++)
scanf("%d", &array[i]);
quicksort(array, 0, length - 1);
for(i = 0; i< length; i++)
printf("%d ", array[i]);
free(array);
return 0;
}
C++
#include <iostream>
#include <vector>
using namespace std;
void swap(int* a, int* b) {
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
int partition(vector<int> &array, int low, int high) {
int mid, index;
mid = low - 1;
for(index = low; index < high; index++){
if(array[index] <= array[high]) {
mid += 1;
swap(&array[mid], &array[index]);
}
}
swap(&array[mid + 1], &array[high]);
return mid + 1;
}
void quicksort(vector<int> &array, int low, int high) {
int mid;
if(low < high){
mid = partition(array, low, high);
quicksort(array, low, mid - 1);
quicksort(array, mid + 1, high);
}
}
int main() {
vector<int> array;
int length, element;
cout << "Enter the length of array: ";
cin >> length;
cout << "Enter the element of array: ";
for(int i = 0; i < length; i++){
cin >> element;
array.push_back(element);
}
quicksort(array, 0, length - 1);
for(int i = 0; i< length; i++)
cout << array[i] << " ";
return 0;
}
Java
import java.util.*;
public class QuickSort {
public static void display(Iterator<Integer> it) {
while(it.hasNext()) {
Integer element = it.next();
System.out.print(element + " ");
}
}
public static void main(String[] args) {
ArrayList<Integer> array = new ArrayList<Integer>();
Scanner in = new Scanner(System.in);
System.out.print("Enter the length of array: ");
int length = in.nextInt();
System.out.print("Enter the element of array: ");
for(int i = 0; i < length; i++)
array.add(in.nextInt());
in.close();
Sort sort = new Sort(array);
sort.quickSort(sort.getLow(), sort.getHigh());
display(array.iterator());
}
}
class Sort {
public Sort(ArrayList<Integer> array) {
this.array = array;
}
public int getLow() {
return 0;
}
public int getHigh() {
return array.size() - 1;
}
public void quickSort(int low, int high) {
int mid;
if(low < high) {
mid = partition(low, high);
quickSort(low, mid - 1);
quickSort(mid + 1, high);
}
}
public int partition(int low, int high) {
int index = low - 1;
for(int i = low; i < high; i++) {
if(array.get(i) <= array.get(high)) {
index += 1;
int[] list = swap(array.get(index), array.get(i));
array.set(index, list[0]);
array.set(i, list[1]);
}
}
int[] list = swap(array.get(index + 1), array.get(high));
array.set(index + 1, list[0]);
array.set(high, list[1]);
return index + 1;
}
public int[] swap(int a, int b) {
int[] list = new int[2];
list[0] = b;
list[1] = a;
return list;
}
private ArrayList<Integer> array;
}
Python
quickSort.py
def swap(A, i, j):
tmp = A[j]
A[j] = A[i]
A[i] = tmp
def partition(A, low, high):
mid = low - 1
for i in range(low, high):
if A[i] <= A[high]:
mid += 1
swap(A, mid, i)
swap(A, mid + 1, high)
return mid + 1
def quickSort(A, low, high):
if low < high:
mid = partition(A, low, high)
quickSort(A, low, mid - 1)
quickSort(A, mid + 1, high)
test.py
import quickSort
A = [8, 7, 3, 0, 5, 4, 2, 9, 6, 1, 4]
quickSort.quickSort(A, 0, len(A) - 1)
print A