在网上搜索算法的博客,发现一个比较悲剧的现象非常普遍:

  • 原理讲不清,混乱
  • 啰嗦
  • 图和文对不上
  • 不可用,甚至代码还出错

为了不误人子弟耽误时间,推荐看一些靠谱的资源,如【啊哈!算法】系列:

https://www.cnblogs.com/ahalei/p/3568434.html

他是C语言实现,其实都是一样的。

我总结一个清晰不罗嗦版:

原理:

快速排序使用分而治之策略。下面描述递归步骤:

选择一个pivot支点值(在啊哈算法中叫“基准值”)。我们将中间元素的值作为支点值,但是它也可以是任何值,甚至它可以不存在于数组中。

第一次排序:

  • 小于支点值的所有元素都到支点值的左侧
  • 而大于支点值的所有元素都到支点值的右侧
  • 与支点值相等的值保留。

递归,再次以支点两侧排序:对两部分进行排序,将快速排序算法递归地应用到左右部分。数组可以以不相等数量的部分划分。

算法要点:

  • 有两个索引i和j,在算法的第一次排序,i 指向数组中的第一个元素,j 指向最后一个元素。
  • i向前移动,直到找到一个值大于或等于支点值的元素。
  • 索引j向后移动,直到找到一个值小于或等于支点值的元素。
  • 如果i小于j,则它们被交换,然后进入下一个位置(i + 1),j进到前一个(j - 1)。
  • 当大于j时,算法停止。

第一次排序的说明:

在第一轮排序之后,会进入左右的递归。依次类推。

复杂度分析

排序方法 时间复杂度 空间复杂度 稳定性 复杂性
平均情况 最坏情况 最好情况
快速排序 O(nlog2n) O(n2) O(nlog2n) O(log2n) 不稳定 较复杂

用JAVA实现(真实可用):

package Sort;

public class QuickSort {

    public static void main(String[] args) {

        int arr[] = {1, 12, 5, 26, 7, 14, 3, 7, 2};
int n = arr.length; QuickSort ob = new QuickSort();
ob.quickSort(arr, 0, n-1);
//ob.sort(arr, 0, n-1); System.out.println("快速排序结果:");
printArray(arr);
} int partition(int arr[], int left, int right){ int i = left, j = right;
int tmp;
int pivot = arr[(left + right) / 2];
System.out.println("pivot="+pivot+"; left="+left+"; right="+right); while (i <= j) { while (arr[i] < pivot){
System.out.println("跳过,i="+i+"; arr[i]="+arr[i]+", pivot="+pivot);
i++;
} while (arr[j] > pivot){
System.out.println("跳过,j="+j+"; arr[j]="+arr[j]+", pivot="+pivot);
j--;
} if (i <= j) {
System.out.println("交换前,i="+i+", j="+j+"; arr[i]="+arr[i]+", arr[j]="+arr[j]); tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp; System.out.println("交换后,i="+i+", j="+j+"; arr[i]="+arr[i]+", arr[j]="+arr[j]);
System.out.println("---"); i++;
j--; }
}; return i;
} void quickSort(int arr[], int left, int right) { int index = partition(arr, left, right);
if (left < index - 1){
System.out.println("递归 左侧,left="+left+", index="+index);
quickSort(arr, left, index - 1);
} if (index < right){
System.out.println("递归右侧,right="+right+", index="+index);
quickSort(arr, index, right);
}
} static void printArray(int arr[])
{
int n = arr.length;
for (int i=0; i<n; ++i)
System.out.print(arr[i]+" ");
System.out.println();
} //另一种简洁写法
int partition1(int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low-1);
for (int j=low; j<high; j++)
{ if (arr[j] <= pivot)
{
i++; int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp; }
} int temp = arr[i+1];
arr[i+1] = arr[high];
arr[high] = temp; return i+1;
} void sort(int arr[], int low, int high)
{
if (low < high)
{
int pi = partition1(arr, low, high); sort(arr, low, pi-1);
sort(arr, pi+1, high);
}
}
}

调试信息:

pivot=7; left=0; right=8
跳过,i=0; arr[i]=1, pivot=7
交换前,i=1, j=8; arr[i]=12, arr[j]=2
交换后,i=1, j=8; arr[i]=2, arr[j]=12
---
跳过,i=2; arr[i]=5, pivot=7
交换前,i=3, j=7; arr[i]=26, arr[j]=7
交换后,i=3, j=7; arr[i]=7, arr[j]=26
---
交换前,i=4, j=6; arr[i]=7, arr[j]=3
交换后,i=4, j=6; arr[i]=3, arr[j]=7
---
跳过,j=5; arr[j]=14, pivot=7
递归 左侧,left=0, index=5
pivot=5; left=0; right=4
跳过,i=0; arr[i]=1, pivot=5
跳过,i=1; arr[i]=2, pivot=5
交换前,i=2, j=4; arr[i]=5, arr[j]=3
交换后,i=2, j=4; arr[i]=3, arr[j]=5
---
跳过,j=3; arr[j]=7, pivot=5
递归 左侧,left=0, index=3
pivot=2; left=0; right=2
跳过,i=0; arr[i]=1, pivot=2
跳过,j=2; arr[j]=3, pivot=2
交换前,i=1, j=1; arr[i]=2, arr[j]=2
交换后,i=1, j=1; arr[i]=2, arr[j]=2
---
递归 左侧,left=0, index=2
pivot=1; left=0; right=1
跳过,j=1; arr[j]=2, pivot=1
交换前,i=0, j=0; arr[i]=1, arr[j]=1
交换后,i=0, j=0; arr[i]=1, arr[j]=1
---
递归右侧,right=4, index=3
pivot=7; left=3; right=4
交换前,i=3, j=4; arr[i]=7, arr[j]=5
交换后,i=3, j=4; arr[i]=5, arr[j]=7
---
递归右侧,right=8, index=5
pivot=7; left=5; right=8
跳过,j=8; arr[j]=12, pivot=7
跳过,j=7; arr[j]=26, pivot=7
交换前,i=5, j=6; arr[i]=14, arr[j]=7
交换后,i=5, j=6; arr[i]=7, arr[j]=14
---
递归右侧,right=8, index=6
pivot=26; left=6; right=8
跳过,i=6; arr[i]=14, pivot=26
交换前,i=7, j=8; arr[i]=26, arr[j]=12
交换后,i=7, j=8; arr[i]=12, arr[j]=26
---
递归 左侧,left=6, index=8
pivot=14; left=6; right=7
交换前,i=6, j=7; arr[i]=14, arr[j]=12
交换后,i=6, j=7; arr[i]=12, arr[j]=14
---
快速排序
1 2 3 5 7 7 12 14 26

排序算法系列:快速排序算法JAVA版(靠谱、清晰、真实、可用、不罗嗦版)的更多相关文章

  1. JAVA算法系列 快速排序

    java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...

  2. 【排序算法】快速排序算法 Java实现

    快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序.它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod). 基本思想 先从数组中找出一个数作为基 ...

  3. java 合并排序算法、冒泡排序算法、选择排序算法、插入排序算法、快速排序算法的描述

    算法是在有限步骤内求解某一问题所使用的一组定义明确的规则.通俗点说,就是计算机解题的过程.在这个过程中,无论是形成解题思路还是编写程序,都是在实施某种算法.前者是推理实现的算法,后者是操作实现的算法. ...

  4. c#冒泡排序算法和快速排序算法

    依次比较相邻的两个数,将小数放在前面,大数放在后面. 第1趟: 首先比较第1个和第2个数,将小数放前,大数放后.然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放 ...

  5. Java实现 蓝桥杯 算法提高 快速排序

    试题 算法提高 快速排序 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 用递归来实现快速排序(quick sort)算法.快速排序算法的基本思路是:假设要对一个数组a进行排序,且a ...

  6. 快速排序算法(C)

    sort快排函数的基本版,效率n*logn,快排的完全版就是在递归之中夹杂对序列的预判断,最优的选择排序方法,快速排序算法只是其中之一. 简单的说明一下快速排序的思想,对于一个数列,首先选择一个基数( ...

  7. 常用算法1 - 快速排序 & 二分查找

    1. 二分查找法: 二分查找法是对一组有序的数字中进行查找,传递相应的数据,进行比较查找到与原数据相同的数据,查找到了返回对应的数组下标,没有找到返回-1. 二分查找法要求数据为一组有序的序列(大到小 ...

  8. c++ 图解快速排序算法

    第一.算法描述 快速排序由C. A. R. Hoare在1962年提出,该算法是目前实践中使用最频繁,实用高效的最好排序算法, 快速排序算法是采用分治思想的算法,算法分三个步骤 从数组中抽出一个元素作 ...

  9. Algorithms - Quicksort - 快速排序算法

    相关概念 快速排序法 Quicksort 也是一个分治思想的算法. 对一个子数组 A[p: r] 进行快速排序的三步分治过程: 1, 分解. 将数组 A[p : r] 被划分为两个子数组(可能为空) ...

随机推荐

  1. 了解各种不同意义上的new

    问题1:请说明new operator 和 operator  new的差异? 1.new   operator : 一般我们写代码的时候,例如:String *p = new String(&quo ...

  2. 使用ibatis时 sql中 in 的参数赋值(转)

    转:http://www.cnblogs.com/sunzhenchao/archive/2012/12/03/2799365.html 一.问题描述: 1.在使用ibatis执行下面的sql: up ...

  3. GitLab代码行数统计--统计增加与删除行数

    #!/bin/bashmaster_dev='master'date_star='2018-11-01'date_end='2018-11-30'path1=`find /home/gitlab_da ...

  4. effector - 必应词典

    effector - 必应词典 美[ɪ'fektə(r)]英[ɪ'fektə(r)] n.效应物 网络效应器:效果器:受动器 变形复数:effectors:

  5. 算法练习LeetCode初级算法之树

    二叉树的前序遍历 我的解法:利用递归,自底向下逐步添加到list,返回最终的前序遍历list class Solution { public List<Integer> preorderT ...

  6. 298. Binary Tree Longest Consecutive Sequence最长连续序列

    [抄题]: Given a binary tree, find the length of the longest consecutive sequence path. The path refers ...

  7. 贝叶斯---最大似然估计(高翔slam---第六讲 )

    1.贝叶斯---最大似然估计 回顾一下第二讲的经典SLAM模型: 通过传感器(例如IMU)的运动参数u来估计运动(位姿x)[定位],通过相机的照片的观测参数z来估计物体的位置(地图y)[建图],都是有 ...

  8. Python开发——面向对象【类、实例】

    类 # class Chinese(object): class Chinese: ''' 类的说明性文档 ''' pass print(Chinese) # <class '__main__. ...

  9. Eigen子矩阵操作

    1 子矩阵操作简介 子矩阵操作又称块操作,在矩阵运算中,子矩阵的提取和操作应用也十分广泛.因此Eigen中也提供了相关操作的方法.提取的子矩阵在操作过程中既可以用作左值也可以用作右值. 2 块操作的一 ...

  10. 【ZooKeeper】ZooKeeper安装及简单操作

    ZooKeeper介绍 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一 ...