快速排序算法详解与其他排序算法的比较

快速排序

属于原地排序,与自顶向下归并类似的是,也是先进行大数组的排序,然后递归到小数组,在进行排序时,先选定一个元素为切分元素,按大小将其他元素放到左右两侧即可

步骤:

  1. 确定切分元素,定义两个位于数组首尾的左右扫描指针
  2. 左指针遇到大于等于切分元素的元素时,停止移动;右指针遇到小于等于切分元素的元素时,停止移动;
  3. 当左右指针都停止时,交换左右指针所在元素
  4. 左右指针继续移动,交换,直到两者重合
  5. 重合后,重合位置元素与切分元素交换位置
  6. 再对切分元素左侧和右侧的元素分别进行快速排序,依次循环进行

动画演示: P为切分元素 L为左标记 R为有标记
在这里插入图片描述

package Sort;
import edu.princeton.cs.algs4.StdRandom;
import static Sort.SortExample.*;
import static edu.princeton.cs.algs4.StdRandom.uniform;
import static edu.princeton.cs.algs4.StdRandom.validateNotNull;
public class QuickSort {
// 主函数
public static void sort(Comparable[] a){
StdRandom.shuffle(a); // 调用了algs4.jar 中的源代码
sort(a, 0, a.length-1);
if(!isSorted(a))
System.out.println("快速排序失败");
}
// 为algs4.jar 中的源代码
// 将数组再次打乱 减少了对输入的依赖
public static void shuffle(Object[] a) {
validateNotNull(a); // 判断数组是否为空
int n = a.length;
for (int i = 0; i < n; i++) {
int r = i + uniform(n-i); // between i and n-1
// 交换位置操作
Object temp = a[i];
a[i] = a[r];
a[r] = temp;
}
}
// 为 algs4.jar 中的源代码
private static void validateNotNull(Object x) {
if (x == null) {
throw new IllegalArgumentException("argument is null");
}
}
private static void sort(Comparable[] a, int lo, int hi){
if(hi <= lo)
return;
int j = partition(a, lo, hi);
sort(a, lo, j-1);
sort(a, j+1, hi);
}
// 将数组分为 a[lo...,i-1] a[i] a[i+1..hi]
private static int partition(Comparable[] a, int lo, int hi){
int i = lo, j = hi+1; // 定义左右扫描指针
Comparable v = a[lo]; // 定义切分元素
// 扫描左右,检查扫描是否结束并交换元素
while (true){
while (less(a[++i], v)) // 左标记不断向右移动,直到有元素>=切分元素
if(i == hi) // 当左标记到达最右端,跳出循环
break;
while (less(v, a[--j])) // 右标记不断向左移动,直到有元素<=切分元素
if(j == lo) // 当右标记到达最左端,跳出循环
break;
if(i >= j) // 当左标记与右标记重合,跳出大循环
break;
exch(a, i, j); // 当左右标记满足条件停止移动时,交换标记所在的元素
}
exch(a, lo, j); // 将 v= a[j] 放入正确的位置
return j; // 返回切分元素索引,此时a[j] 左右两侧完成排序
}
}

特点:

  • 快速排序如同名字一样,在大多数情况下,具有良好的性能优势
  • 大多数编程语言的数组排序内置函数都采用快速排序实现

注意点:

  • 当有元素值与切分元素重复时,需要防止循环意外中断
  • 保持随机性,不依赖输入,尽量将切分元素也进行随机化

时间复杂度:
N l g N NlgN NlgN

四种排序算法的比较

数据来源:algo4 官方提供的 algo4-data.zip 数据包

进行1k数据量的比较:

选择排序,1000个数据,执行时间为:0.0115291 s
插入排序,1000个数据,执行时间为:0.0105386 s
希尔排序,1000个数据,执行时间为:0.0016667 s
自顶向下归并排序,1000个数据,执行时间为:0.0017786 s
自底向上归并排序,1000个数据,执行时间为:6.685E-4 s
快速排序,1000个数据,执行时间为:0.0027377 s

进行32k数据量的比较:

选择排序,32000个数据,执行时间为:4.200542 s
插入排序,32000个数据,执行时间为:2.5466117 s
希尔排序,32000个数据,执行时间为:0.0212745 s
自顶向下归并排序,32000个数据,执行时间为:0.0246908 s
自底向上归并排序,32000个数据,执行时间为:0.0140204 s
快速排序,32000个数据,执行时间为:0.021905 s

其他有关排序算法的文章:
选择排序,插入排序,希尔排序的详解与比较

归并排序详解,与其他排序算法的比较

本文作者:清澈的澈

本文链接:https://www.cnblogs.com/lmc7/p/17531392.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   清澈的澈  阅读(45)  评论(0编辑  收藏  举报  
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示