最近因为项目需要,研究AI相关的东西,主要是算法相关的。

有感触,所以决定,来一个系列的博文,可能会耗时很久,那就是要完成算法系列。起点,从最常用最基本的排序开始。后续会跟进其他类型的,比如树,图等领域的。希望各位博友读者监督

今天,将开启排序算法中的快速排序。

先来一点小历史插曲:

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。

快速排序的思想:

将输入的待排序的数字序列(数组),找到一个基准值(往往是待排数组的第一个元素),在这个数组中,将其他数与这个基准数进行比较,将待排序数组的所有元素分成两部分,一部分的元素都比基准数小(比如左边),一部分都比基准数大(比如右边)。

上述思想,转化为编程实现的步骤,可以概述为下面的几步:

1. 从给定的待排序数组中找一个基准数(通常取数组的第一个元素)

2. 数组划界,将待排序的数组的元素与1中找到的基准数进行比较,将比这个基准数大的划分到右边,比这个基准数小的划分左边

3. 重复上述1,2的操作(例如递归),直到待排序的子数组中的元素不需要排序(只有一个元素)

思路和步骤都阐述清楚了,若还是没有完全理解,就可以结合代码实现过程来帮助理解了。在看代码之前,我想强调一点的是,快速排序算法中,重点是步骤2的数组划界,将待排序输入数组分成两部分,找到这个划界的分界点,或者说是数组的分隔下标。这个过程,有点像数学理论中的夹逼理论,两边向中间某个位置逼近,可能会出现小幅度的震荡,但是最终会收敛(找到划界线)。

下面上算法实现代码(JAVA)

 /**
* @author "shihuc"
* @date 2017年1月17日
*/
package quickSort; import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner; /**
* @author chengsh05
*
*/
public class QuickSortDemo { /**
* @param args
*/
public static void main(String[] args) {
File file = new File("./src/quickSort/sample.txt");
Scanner sc = null;
try {
sc = new Scanner(file);
//获取测试例的个数
int T = sc.nextInt();
for(int i=; i<T; i++){
//获取每个测试例的元素个数
int N = sc.nextInt(); int A[] = new int[N];
for(int j=; j<N; j++){
A[j] = sc.nextInt();
}
quickSort(A, , A.length - );
printResult(i, A);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if(sc != null){
sc.close();
}
}
} /**
* 采用类似两边夹逼的方式,向输入数组的中间某个位置夹逼,将原输入数组进行分割成两部分,左边的部分全都小于某个值,
* 右边的部分全都大于某个值。
*
* 快排算法的核心部分。
*
* @param src 待排序数组
* @param start 数组的起点索引
* @param end 数组的终点索引
* @return 中值索引
*/
private static int middle(int src[], int start, int end){
int middleValue = src[start];
while(start < end){
//找到右半部分都比middleValue大的分界点
while(src[end] >= middleValue && start < end){
end--;
}
//当遇到比middleValue小的时候或者start不再小于end,将比较的起点值替换为新的最小值起点
src[start] = src[end];
//找到左半部分都比middleValue小的分界点
while(src[start] <= middleValue && start < end){
start++;
}
//当遇到比middleValue大的时候或者start不再小于end,将比较的起点值替换为新的终值起点
src[end] = src[start];
}
//当找到了分界点后,将比较的中值进行交换,将中值放在start与end之间的分界点上,完成一次对原数组分解,左边都小于middleValue,右边都大于middleValue
src[start] = middleValue;
return start;
} /**
* 通过递归的方式,对原始输入数组,进行快速排序。
*
* @param src 待排序的数组
* @param st 数组的起点索引
* @param nd 数组的终点索引
*/
public static void quickSort(int src[], int st, int nd){ if(st > nd){
return;
}
int middleIdx = middle(src, st, nd);
//将分隔后的数组左边部分进行快排
quickSort(src, st, middleIdx - );
//将分隔后的数组右半部分进行快排
quickSort(src, middleIdx + , nd);
} /**
* 打印最终的输出结果
*
* @param idx 测试例的编号
* @param B 待输出数组
*/
private static void printResult(int idx, int B[]){
System.out.print(idx + "--> ");
for(int i=; i<B.length; i++){
System.out.print(B[i] + " ");
}
System.out.println();
}
}

下面附上程序中用于测试的案例:


 -   - -    

最后附上测试结果:

 -->
-->
-->
--> - - -
-->

另外,要说一点的是,这里的快速排序算法实现,其实还有可以优化的空间,主要是middle函数的实现。

快速排序,多数情况下的时间复杂度都是O(N*logN)。

下面,附上我从网络上找来的辅助理解快速排序的演示动画图片。

排序算法<No.2>【快速排序】的更多相关文章

  1. Java常用排序算法+程序员必须掌握的8大排序算法+二分法查找法

    Java 常用排序算法/程序员必须掌握的 8大排序算法 本文由网络资料整理转载而来,如有问题,欢迎指正! 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排 ...

  2. Java 常用排序算法/程序员必须掌握的 8大排序算法

    Java 常用排序算法/程序员必须掌握的 8大排序算法 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配 ...

  3. Java八大排序算法

    Java八大排序算法: package sort; import java.util.ArrayList; import java.util.Arrays; import java.util.List ...

  4. Java常用排序算法及性能测试集合

    测试报告: Array length: 20000 bubbleSort : 573 ms bubbleSortAdvanced : 596 ms bubbleSortAdvanced2 : 583 ...

  5. Java各种排序算法

      Java各种排序算法详解 排序大的分类可以分为两种:内排序和外排序.在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序.下面讲的排序都是属于内排序. 内排序有 ...

  6. java:高速排序算法与冒泡排序算法

     Java:高速排序算法与冒泡算法 首先看下,冒泡排序算法与高速排序算法的效率: 例如以下的是main方法: /**   *  * @Description:  * @author:cuiyaon ...

  7. Java常见排序算法之快速排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

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

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

  9. 我的Java开发学习之旅------>Java经典排序算法之快速排序

    一.算法思想     快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序.它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod).(1) 分治法的 ...

  10. Java各种排序算法详解

    排序大的分类可以分为两种:内排序和外排序.在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序.下面讲的排序都是属于内排序. 内排序有可以分为以下几类: (1).插 ...

随机推荐

  1. ES6 class的继承-学习笔记

    1.简介 Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多. 子类必须在constructor方法中调用super方法,否则新建实例时会报错. ...

  2. 2.33 定位的坑:class属性有空格

    2.33 定位的坑:class属性有空格 前言有些class属性中间有空格,如果直接复制过来定位是会报错的InvalidSelectorException: Message:The given sel ...

  3. WPA2 Key Reinstallation 漏洞

    漏洞形成: 必要条件1:WPA2 协议存在一个消息重放漏洞,导致多组相同数据被使用了相同的密钥加密. ciphertext = plaintext xor AES(key, IV||counter) ...

  4. 剑指offer-面试题1:赋值运算符函数

    如下为类型CMyString的声明,请为该类型添加赋值运算符函数. 解析:给一个类进行运算符重载. 关键部分代码: CMyString& CMyString::operator =(const ...

  5. c++函数参数类型-引用、指针、值

    c++函数参数类型-引用.指针.值 https://www.cnblogs.com/lidabo/archive/2012/05/30/2525837.html

  6. Python之路,第十四篇:Python入门与基础14

    python3    模块2 标准模块 随机模块random 假设导入 import  random  as  R 函数: R.random()    返回一个[0 ,1) 之间的随机数 R.getr ...

  7. Thread_run()方法

    cas 1: package threadTest; public class ThreadTest { public static void main(String[] args) { Thread ...

  8. 浅谈STM32L071硬件I2C挂死

    STM32的IIC问题一直存在,在网上也被很多人吐槽,然而FAE告诉我,硬件IIC的问题在F1,F3,F4系列单片机存在,而在L0上已经解决了,然而这几天调试加密芯片和显示芯片,都是IIC芯片,却再一 ...

  9. python文件处理复习

    1.创建文件 >>> file('test.txt','w')   -->在当前路径下创建文件 test.txt是文件名 w是打开文件的方式,r是读,w是写,a是追加,如果当前 ...

  10. js判断是否是闰年

    JavaScript判断值是否是闰年: 判断是否闰年公式:(year%4==0 && year%100 !=0) ||(year%400 ==0) var year = prompt( ...