大三了,该找实习了。但是大二学的各种算法已经忘完了,在这里复习一下,做个笔记。
我们要解决几个问题:
- 什么是快速排序?
- 快速排序的性能如何?
- 快速排序是怎么实现的?
我们先看第一个问题:
- 什么是快速排序?
快速排序是一种运用了分治思想的排序,是一种内排序(数据存储在内存中的排序)。所谓分治思想,就是分而治之,这类思想在排序算法中拥有很高的使用率,得益于它的时间复杂度。
2. 快速排序的性能如何?
对于包含n个数的输入数组来说,快速排序是一种最坏情况时间复杂度为O(n^2) 的排序算法,而其平均性能为O(nlgn)。此外,它还可以进行“原址排序”,因此在虚存环境下也能很好的工作。
所谓原址排序,就是不需要借助很多辅助空间,即空间复杂度为O(1)常数级。
3. 快速排序是怎么实现的?
-
分解:将数组A[p....r]划分为两个子数组,这两个子数组可以为空。这两个子数组为A[p....q-1],A[q+1....r],且A[q] A[p....q-1],且A[q]A[q+1....r]。
- 解决:通过递归调用快速排序,对子数组进行排序。
- 合并:因为子数组都是原址排序,所以不需要合并操作,即A[p....r]已经有序。
以上三个步骤就是我们要解决的问题。
我们一步一步解决问题。
- 数组划分
首先,将数组划分,需要对数组原址重排,达到如下效果
A[p....q-1],A[q+1....r],且A[q] A[p....q-1],且A[q]A[q+1....r]。
一般来说,我们会找一个“基准数”,在《算法导论》一书中将这个“基准数”叫做“主元”。基准数一般选取原则是最后一个数,即:
baseNumber = A[r];
伪代码:
Partition(A, p, r){
baseNumber = A[r]
slowPointer = p-1 //设置一个慢指针,就是数组的下标,初始值为-1
for j = p to r-1 {
if A[j] <= baseNumber {
slowPointer = slowPointer + 1
swap(A[slowPointer], A[j])
}
}
swap(A[slowPointer + 1], A[r])
return i+1
}
上述思想为:
- 设置基准数baseNumber
- 设置慢指针slowPointer(数组下标)
- 设置指针j,j 初始值为数组首项下标
- j 为指针,不断 + 1,直到找到数组倒数第二项
- 判断条件:当数组当前下标小于等于baseNumber时,令慢指针 slowPointer + 1,并交换A[ slowPointer ]与A[ j ]的值。
- 返回中间值(基准值)指针位置
//C++ 实现:
int partition(int A[], int p, int r){
int baseNumber = A[r];
int slowPointer = p - 1;
for(int j = p; j <= r-1; j++){
if( A[j] <= baseNumber){
slowPointer = slowPointer + 1;
swap(A[slowPointer], A[j]);
}
}
swap(A[slowPointer + 1], A[r]);
return slowPointer+1;
}
实现数组分组有许多种方法,这一种代码是《算法导论》的实现方法,最简洁,但是也比较难以理解。
- 解决:
解决很简单,就是基本的递归。对子数组继续划分子数组,再进行对孙子数组的排序。
伪代码:
QuickSort(A, p, r){
if p < r {
q = Partition(A, p, r)
QuickSort(A, p, q-1)
QuickSort(A, q+1, r)
}
}
//C++ 实现
void quickSort(int A[], int p, int r){
if(p < r){
int q = partition(A, p, q-1);
quickSort(A, p, q-1);
quickSort(A, q+1, r);
}
}
#include <iostream>
#include <algorithm>
using namespace std;
int Partition(int A[], int p, int r){
int baseNumber = A[r];
int slowPointer = p - 1;
for(int j = p; j <= r-1; j++){
if( A[j] <= baseNumber){
slowPointer = slowPointer + 1;
swap(A[slowPointer], A[j]);
}
}
swap(A[slowPointer + 1], A[r]);
return slowPointer+1;
}
void quickSort(int A[], int p, int r){
if(p < r){
int q = 0;
q = Partition(A, p, r);
quickSort(A, p, q-1);
quickSort(A, q+1, r);
}
}
int main(int argc, char *argv[]) {
int A[] = {9,8,7,6,5,4,3,2,1};
int p = 0, r = 8;
quickSort(A,p,r);
for(int i=0;i<9;i++){
cout<<A[i]<<" ";
}
cout<<endl;
return 0;
}