快速排序简说与实现

大三了,该找实习了。但是大二学的各种算法已经忘完了,在这里复习一下,做个笔记。

 


我们要解决几个问题:

  1. 什么是快速排序?
  2. 快速排序的性能如何?
  3. 快速排序是怎么实现的?

我们先看第一个问题:

  1. 什么是快速排序?

       快速排序是一种运用了分治思想的排序,是一种内排序(数据存储在内存中的排序)。所谓分治思想,就是分而治之,这类思想在排序算法中拥有很高的使用率,得益于它的时间复杂度。

     2. 快速排序的性能如何?

       对于包含n个数的输入数组来说,快速排序是一种最坏情况时间复杂度为O(n^2) 的排序算法,而其平均性能为O(nlgn)。此外,它还可以进行“原址排序”,因此在虚存环境下也能很好的工作。       

       所谓原址排序,就是不需要借助很多辅助空间,即空间复杂度为O(1)常数级。

      3. 快速排序是怎么实现的?

  • 分解:将数组A[p....r]划分为两个子数组,这两个子数组可以为空。这两个子数组为A[p....q-1],A[q+1....r],且A[q] \geqA[p....q-1],且A[q]\leqA[q+1....r]。

  • 解决:通过递归调用快速排序,对子数组进行排序。
  • 合并:因为子数组都是原址排序,所以不需要合并操作,即A[p....r]已经有序。

     以上三个步骤就是我们要解决的问题。


我们一步一步解决问题。

  • 数组划分

首先,将数组划分,需要对数组原址重排,达到如下效果

A[p....q-1],A[q+1....r],且A[q] \geqA[p....q-1],且A[q]\leqA[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
}

 上述思想为:

  1.  设置基准数baseNumber
  2. 设置慢指针slowPointer(数组下标)
  3. 设置指针j,j 初始值为数组首项下标
  4. j 为指针,不断 + 1,直到找到数组倒数第二项
  5. 判断条件:当数组当前下标小于等于baseNumber时,令慢指针 slowPointer + 1,并交换A[ slowPointer ]与A[ j ]的值。
  6. 返回中间值(基准值)指针位置
//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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值