本文将围绕冒泡排序、桶排序、计数排序、堆排序、插入排序、并归排序、快速排序和选择排序,按照描述、时间复杂度(最坏情况)、动态图展示和代码实现来讲解。本文默认排序为从小到大。

本文相关代码已上传至github,欢迎关注https://github.com/zhuzhenke/common-algorithms

公用方法

SortUtils

public class SortUtils {

public static void check(int[] sortingData) {

if (sortingData == null || sortingData.length == 0) {

throw new IllegalArgumentException("sortingData can not be empty!");

}

}

public static void swap(int[] swapArray, int i, int j) {

check(swapArray);

if (i < 0 || i > swapArray.length - 1) {

throw new ArrayIndexOutOfBoundsException("illegal index i:" + i);

}

if (j < 0 || j > swapArray.length - 1) {

throw new ArrayIndexOutOfBoundsException("illegal index j:" + j);

}

int temp = swapArray[i];

swapArray[i] = swapArray[j];

swapArray[j] = temp;

}

public static int getMaxValue(int[] sortingData) {

check(sortingData);

int max = sortingData[0];

for (int value : sortingData) {

if (value < 0) {

throw new IllegalArgumentException("value could not be negative:" + value);

}

if (value > max) {

max = value;

}

}

return max;

}

}

冒泡排序

描述

比较前后两个数的大小,如果前者大于后者,则交换两个数的位置

最大的数字在进行一轮比较和交换后,会出现在数组的最后一个位置

每一轮之后,可减少最大数字的比较。重复上述操作直到没有需要比较的元素为止

时间复杂度

O(n^2)

动态图展示

代码实现

github代码

public int[] sort(int[] sortingData) {

SortUtils.check(sortingData);

for (int j = sortingData.length - 1; j > 0; j--) {

for (int i = 0; i < j; i++) {

if (sortingData[i] > sortingData[i + 1]) {

SortUtils.swap(sortingData, i, i + 1);

}

}

}

return sortingData;

}

桶排序

描述

挑选数组中最大的数字,设置默认分配的桶数,得到每个桶容纳的数字范围。如最大是10,桶是4个,则每个桶最大容纳3个数字。第0个桶放0、1、2、3,第1个桶方4、5、6,第2桶方7,8,9,以此类推

对每个桶内进行冒泡排序或选择排序

遍历所有桶,依次取出每个桶中的元素,得到的就是一个排好序的数组

时间复杂度

O(n^2)

动态图展示

代码实现

github代码

@Override

public int[] sort(int[] sortingData) {

SortUtils.check(sortingData);

int bucketSize = (int) Math.round(Math.sqrt(sortingData.length)) + 1;

int[][] buckets = new int[bucketSize][];

int max = SortUtils.getMaxValue(sortingData);

double avgContain = Math.ceil((double) max / (double) bucketSize);

for (int value : sortingData) {

int bucketIndex = (int) Math.ceil(value / avgContain) - 1;

if (bucketIndex < 0) {

bucketIndex = 0;

}

int[] bucketIndexs = buckets[bucketIndex];

if (bucketIndexs == null || bucketIndexs.length == 0) {

bucketIndexs = new int[1];

bucketIndexs[0] = value;

buckets[bucketIndex] = bucketIndexs;

} else {

int[] newBucketIndexs = new int[bucketIndexs.length + 1];

System.arraycopy(bucketIndexs, 0, newBucketIndexs, 0, bucketIndexs.length);

newBucketIndexs[bucketIndexs.length] = value;

buckets[bucketIndex] = newBucketIndexs;

}

}

Sort sort = new InsertionSort();

for (int a = 0; a < buckets.length; a++) {

int[] bucket = buckets[a];

if (bucket == null || bucket.length == 0) {

continue;

}

bucket = sort.sort(bucket);

buckets[a] = bucket;

}

int[] result = new int[sortingData.length];

int resultIndex = 0;

for (int[] bucket : buckets) {

if (bucket == null || bucket.length == 0) {

continue;

}

for (int bucketValue : bucket) {

result[resultIndex++] = bucketValue;

}

}

return result;

}

计数排序

描述

获取数组中最大的值(这个值需要在可控范围,最好是在10000以内)

创建一个长度为最大值加1的计数数组,

遍历待排序数组,将元素的值落入到计数数组的下标元素,将下标元素的值加1

遍历下标数组,将后一个元素的值标为当前元素值加前一个元素的值(用于排序后的数组下标)。

创建一个长度跟待排序数组大小相同的结果数组

遍历待排序数组,取出待排序元素,对应计数数组的下标元素,并放在计数元素值的前一个位置,并将计数元素值减1

时间复杂度

O(n)

动态图展示

代码实现

github代码

private int[] sort2(int[] sortingData) {

int maxValue = SortUtils.getMaxValue(sortingData);

//get max,check all numbers must be bigger or equal 0

int[] count = new int[maxValue + 1];

//count every number

for (int value : sortingData) {

count[value] = count[value] + 1;

}

for (int i = 1; i < count.length; i++) {

count[i] = count[i] + count[i - 1];

}

//output

int[] result = new int[sortingData.length];

for (int value : sortingData) {

result[count[value] - 1] = value;

count[value] = count[value] - 1;

}

return result;

}

堆排序

描述

为了方便理解,将数组元素映射成二叉树,array[0]对一个根节点,array[1]为根的左节点,array[2]为根的右节点,一次类推

从最后一个元素开始遍历到第一个,让其与父节点比较大小,如果子节点大,则交换位置。(另外一种方式是从中间元素开始比较,得到当前元素和子元素的最大值,这样则遍历深度为logn,这种方式属于推荐方式)

遍历一轮结束后,则最大值已经位于index为0的位置,这时交换index为0和最后一位的位置,则最大值确定。下一轮比较从最大值的前一个index下标元素开始遍历,依次进行遍历

最后全部遍历完成,则得到一个拍好序的数组

时间复杂度

O(nlogn)

动态图展示

代码实现

github代码

public int[] sort(int[] sortingData) {

int highIndex = sortingData.length - 1;

while (highIndex > 0) {

for (int i = 1; i <= highIndex; i++) {

sortBiggestToIndex0(sortingData, i);

}

SortUtils.swap(sortingData, 0, highIndex);

highIndex--;

}

return sortingData;

}

public static void sortBiggestToIndex0(int[] sortingData, int sortIndex) {

while (sortIndex > 0 && sortingData[sortIndex] > sortingData[(sortIndex - 1) / 2]) {

SortUtils.swap(sortingData, sortIndex, (sortIndex - 1) / 2);

sortIndex = (sortIndex - 1) / 2;

}

}

插入排序

描述

插入排序类似于扑克摸牌排序

第一次只有一种牌,牌是有序的。当摸到第二张牌时,则插入到已有的排好序的牌中,此时前两张牌有序

依次进行同样的操作,摸到第n张牌时,前n-1张牌已经有序,进行插入到合适位置即可

时间复杂度

O(n^2)

动态图展示

代码实现

github代码

public int[] sort(int[] sortingData) {

SortUtils.check(sortingData);

for (int i = 1; i < sortingData.length; i++) {

int currentValue = sortingData[i];

int j = i;

while (j - 1 >= 0 && currentValue < sortingData[j - 1]) {

sortingData[j] = sortingData[j - 1];

j--;

}

sortingData[j] = currentValue;

}

return sortingData;

}

并归排序

描述

并归排序利用递归思想,递归思想的核心在于找到一个模式,分解为子模式,子模式又可以分解子模式,则对于最小子模式,可以直接求解。

首先会将待排序数组分为两份,两份分别排好序后进行合并

两份中的每一份,又可以查分为更小的一份,直到每份只有一个元素,则此份为已排好序的子数组。对两个子数组进行合并的排序

时间复杂度

O(nlogn)

动态图展示

代码实现

github代码

@Override

public int[] sort(int[] sortingData) {

SortUtils.check(sortingData);

splitDate(sortingData, 0, sortingData.length - 1);

return sortingData;

}

private void splitDate(int[] sortingData, int start, int end) {

if (end - start < 1) {

return;

}

int middle = (start + end) / 2;

splitDate(sortingData, start, middle);

splitDate(sortingData, middle + 1, end);

mergeData(sortingData, start, middle, end);

}

private void mergeData(int[] sortingData, int start, int middle, int end) {

int[] left = Arrays.copyOfRange(sortingData, start, middle + 1);

int[] right = Arrays.copyOfRange(sortingData, middle + 1, end + 1);

int i = 0;

int j = 0;

for (int k = start; k <= end; k++) {

if (i < left.length && j < right.length) {

if (left[i] <= right[j]) {

sortingData[k] = left[i];

i++;

} else {

sortingData[k] = right[j];

j++;

}

} else {

if (i >= left.length) {

sortingData[k] = right[j];

j++;

} else if (j >= right.length) {

sortingData[k] = left[i];

i++;

}

}

}

}

快速排序

描述

选择待排序数组的中元元素,一般选择第一个或最后一个元素,将数组拆分为两部分,左边部分元素小于等于中元元素,右边部分元素大于中元元素

继续将子数组按中元元素进行拆分,直到全部排好序位置

时间复杂度

O(n^2)

动态图展示

代码实现

github代码

@Override

public int[] sort(int[] sortingData) {

SortUtils.check(sortingData);

quickSort(sortingData, 0, sortingData.length - 1);

return sortingData;

}

private void quickSort(int[] sortingData, int start, int end) {

if (start > end) {

return;

}

int middle = getQuickSortMiddle(sortingData, start, end);

quickSort(sortingData, start, middle - 1);

quickSort(sortingData, middle + 1, end);

}

/**

* one side

*/

public int getQuickSortMiddle(int[] sortingData, int start, int end) {

int i = start;

int pivot = end;

for (int j = start; j < end; j++) {

if (sortingData[j] < sortingData[pivot]) {

SortUtils.swap(sortingData, i, j);

i++;

}

}

SortUtils.swap(sortingData, i, pivot);

return i;

}

选择排序

描述

从第一个元素开始遍历,记录最小值和对应元素下标,遍历一轮则可以得到最小值,将这个值与下标为0的元素交换,则完成第一轮最小值输出

从第2个进行同样的遍历操作,遍历取剩余元素的最小值,将这个值与下标为1的元素交换

从第index个开始进行遍历操作,遍历取剩余元素的最小值,将这个值与下标为index的元素交换

遍历直到最后一个元素位置,得到一个排好序的数组

时间复杂度

O(n^2)

动态图展示

代码实现

github代码

public int[] sort(int[] sortingData) {

SortUtils.check(sortingData);

for (int index = 0; index < sortingData.length; index++) {

int smallestIndex = index;

int smallestValue = sortingData[index];

for (int j = index; j < sortingData.length; j++) {

if (sortingData[j] < smallestValue) {

smallestValue = sortingData[j];

smallestIndex = j;

}

}

sortingData[smallestIndex] = sortingData[index];

sortingData[index] = smallestValue;

}

return sortingData;

}

java快速排序直观演示代码,排序算法总结(含动图演示和Java代码实现)相关推荐

  1. 一文读懂Python版的十大经典排序算法(附动图演示)

    来源:大数据DT 本文约5200字,建议阅读10分钟 排序算法是<数据结构与算法>中最基本的算法之一.本文介绍10种常见的内部排序算法,及如何用Python实现. 排序算法可以分为内部排序 ...

  2. 【排序算法】冒泡排序(动图演示) - 保姆级详解

    冒泡排序(Bubble Sort)也是一种简单直观的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来. 算法步骤 比较相邻的元素.如果第一个比第二个大,就交换 ...

  3. 超详细八大排序+基数排序(图文并茂+动图演示+C语言代码演示)

    超详细八大排序+基数排序(图文并茂+动图演示+C语言代码演示) 插入排序-直接插入排序 插入排序-希尔排序 选择排序-直接选择排序 选择排序-堆排序 交换排序-冒泡排序 交换排序-快速排序-三种方法( ...

  4. 十大经典排序C++实现及动图演示

    0.算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序. 非比较类排序: ...

  5. C语言八大排序算法,附动图和详细代码解释!

    文章来源:电子工程专辑.C语言与程序设计.竹雨听闲 一.前言 如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功. 想写出精炼.优秀的代码,不通过不断的锤炼,是很难做到的. 二. ...

  6. 硬核!C语言八大排序算法,附动图和详细代码解释!

    来源 :C语言与程序设计.竹雨听闲等 一 前言 如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功. 想写出精炼.优秀的代码,不通过不断的锤炼,是很难做到的. 二 八大排序算法 ...

  7. 排序算法——冒泡排序原理动图详解及实现

    主要涉及的是内部排序  交换排序   => 冒泡排序   快速排序  选择排序   直接选择排序   堆排序  插入排序   直接插入排序   希尔排序  归并排序 冒泡排序 1. 简介 冒泡排 ...

  8. 排序算法-冒泡排序(可视化动图)

    冒泡排序 冒泡排序(Bubble Sort) 最为简单的一种排序,通过重复走完数组的所有元素,通过打擂台的方式两个两个比较,直到没有数可以交换的时候结束这个数,再到下个数,直到整个数组排好顺序.因一个 ...

  9. 数据结构与算法--经典10大排序算法(动图演示)【建议收藏】

    十大经典排序算法总结(动图演示) 算法分类 十大常见排序算法可分为两大类: 比较排序算法:通过比较来决定元素的位置,由于时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序 非比较类型排 ...

最新文章

  1. c语言map函数k v都是int,Go语言sync.Map(在并发环境中使用的map)
  2. 面向对象PHP之静态延迟绑定
  3. DNS高级部署使用RSYNC部署搭建DNS view主从服务
  4. 除了要求app随手机壳颜色变之外,产品还要求....
  5. 源码0501-07-GCD的基本使用
  6. 2.2_queue_队列
  7. charles抓包显示乱码解决方法
  8. 手把手教你强化学习 (九) 强化学习中策略梯度算法
  9. JS控制文本框内键盘上下左右键的焦点
  10. Flash网站的优缺点
  11. vscode: Code Runner直接运行多文件C++程序
  12. GIT统计代码量及IDEA Statistic统计解析
  13. IPad 如何使用蓝牙鼠标
  14. 设计模式之状态机模式
  15. Axure 9 实战案例,动态面板的应用 5,官网首页自动轮播广告
  16. python中占位符解释
  17. 云栖大会·南京峰会落下帷幕,阿里云都干了些什么?
  18. oracle 11g 硬件需求,ORACLE 11g R2数据库装配硬件环境要求
  19. Facebook将推出“虚拟约会”功能视频聊天室
  20. 解决安装黑苹果出现提示应用程序副本已损坏,不能用来安装macOS的解决方法

热门文章

  1. php常用代码(一)
  2. android使用menu需要重写的方法,Android – 正确使用invalidateOptionsMenu()
  3. centos7 zookeeper3.5.6单点部署
  4. maya python 创建求_如何使用python在Maya中创建列表
  5. 【Git、GitHub、GitLab】四 Git文件重命名的简单方法以及使用git log查看版本演变历史
  6. [Swift通天遁地]七、数据与安全-(12)使用Instruments Leaks工具检测内存泄露
  7. SSM项目中整合WebService
  8. 微信公众平台-杂项:小程序导航
  9. 2018年湘潭大学程序设计竞赛 G又见斐波那契
  10. Memory及其controller芯片整体测试方案(上篇)