利用Java语言实现七大经典排序算法:冒泡排序、选择排序、插入排序、希尔排序、堆排序、归并排序以及快速排序。

分类
类别 算法
插入排序类 插入排序、希尔排序
选择排序类 选择排序、堆排序
交换排序类 冒泡排序、快速排序
归并排序类 归并排序
复杂度
算法 平均情况 最好情况 最坏情况 辅助空间 稳定性 复杂性
冒泡排序 O(n^2) O(n) O(n^2) O(1) 稳定 简单
选择排序 O(n^2) O(n^2) O(n^2 O(1) 稳定 简单
插入排序 O(n^2) O(n) O(n^2) O(1) 稳定 简单
希尔排序 O(nlogn)~O(n^2) O(n^1.3) O(n^2) O(1) 不稳定 较复杂
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定 较复杂
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定 较复杂
快速排序 O(nlogn) O(nlogn) O(n^2) O(logn)~O(n) 不稳定 较复杂
算法实现:排序算法类Sort
package com.chiaki.demo;

/**
* 排序算法类
* @author Chiaki
*/
public class Sort {
/**
* 工具函数:打印数组
* @param arr 原数组
*/
public static void printArr(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println();
} /**
* 工具函数:交换数组两个下标对应的值
* @param arr 原数组
* @param a 下标a
* @param b 下标b
*/
public static void swap(int[] arr, int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
} /**
* 冒泡排序
* @param arr 原数组
*/
public static void bubbleSort01(int[] arr) {
// i从第1个元素开始
for (int i = 0; i < arr.length - 1; i++) {
// j从倒数第2个元素开始直到与i相遇
for (int j = arr.length - 2; j >= i; j--) {
// 比较倒数第1个元素与倒数第2个元素
if (arr[j] > arr[j + 1]) {
// 满足条件进行交换
swap(arr, j, j + 1);
}
}
}
} /**
* 改进冒泡排序:设置标志减少比较次数
* @param arr 原数组
*/
public static void bubbleSort02(int[] arr) {
boolean flag = true;
// i从第1个元素开始 flag为假时结束循环
for (int i = 0; (i < arr.length) && flag; i++) {
// flag初始化为假 若后续flag不改变为真则结束循环
flag = false;
// j从倒数第1个元素开始直到与i相遇
for (int j = arr.length - 1; j > i; j--) {
// 比较倒数第1个元素和倒数第2个元素
if (arr[j-1] > arr[j]) {
// 满足条件进行交换
swap(arr, j, j - 1);
// 发生交换则更新flag为真
flag = true;
}
}
}
} /**
* 选择排序
* @param arr 原数组
*/
public static void selectSort(int[] arr) {
for (int i=0; i<arr.length - 1; i++){
// 将当前元素指针设置为最小值指针min
int min = i;
// j从i的下一个元素开始
for (int j = i + 1; j < arr.length; j++) {
// 若arr[j]小于arr[min]则更新min
if (arr[min] > arr[j]) {
min = j;
}
}
// 如果min发生了更新就将数组元素值进行交换
if (i != min) {
swap(arr, i, min);
}
}
} /**
* 插入排序
* @param arr 原数组
*/
public static void insertSort(int[] arr) {
// i从第1个元素开始
for (int i = 1; i < arr.length; i++) {
// 将当前arr[i]保存在临时变量temp
int temp = arr[i];
// 设置与temp进行同组比较的索引j
int j = i - 1;
// 同组比较 若temp较小则进行后移操作
while (j >= 0 && arr[j] > temp) {
// 后移1位
arr[j + 1] = arr[j];
j--;
}
// 将temp插入到后移操作后的元素前面
arr[j + 1] = temp;
}
} /**
* 希尔排序
* @param arr 原数组
*/
public static void shellSort(int[] arr) {
// 希尔变量
int delta = arr.length / 2;
// 满足delta>0进行循环
while (delta > 0) {
for (int i = delta; i < arr.length; i++) {
// 将当前arr[i]保存在临时变量temp
int temp = arr[i];
// 设置与temp进行同组比较的索引j
int j = i - delta;
// 同组比较 若temp较小则进行后移操作
while (j >= 0 && arr[j] > temp) {
// 后移delta位
arr[j + delta] = arr[j];
j -= delta;
}
// 将temp插入到后移操作后的元素前面
arr[j + delta] = temp;
}
// 更新希尔增量
delta /= 2;
}
} /**
* 基于数组实现的大顶堆
* @param arr 数组
* @param size 堆大小
* @param index 堆索引
*/
private static void maxHeap(int[] arr, int size, int index) {
// 根据完全二叉树的性质得到左孩子和右孩子的索引
int left = 2 * index + 1;
int right = 2 * index + 2;
// 将当前索引index设置为最大值索引maxindex
int maxIndex = index;
// 若左孩子结点值比最大值索引结点值大则更新maxindex
if (left < size && arr[left] > arr[maxIndex]) {
maxIndex = left;
}
// 若右孩子结点值比最大值索引结点值大则更新maxindex
if (right < size && arr[right] > arr[maxIndex]) {
maxIndex = right;
}
// 若maxIndex发生了更新则进行交换操作
if (maxIndex != index) {
swap(arr, maxIndex, index);
// 递归
maxHeap(arr, size, maxIndex);
}
} /**
* 基于大顶堆的堆排序
* @param arr 原数组
*/
public static void heapSort(int[] arr) {
// 找到最后一个非叶子结点即最后一个叶子结点的父结点的索引作为开始
int parent = arr.length/2 - 1;
// 从parent开始针对原数组构建大顶堆
for (int i=parent; i>=0; i--) {
maxHeap(arr, arr.length, i);
// 打印大顶堆的调整过程
//printArr(arr);
}
// 基于大顶堆的排序
for (int i=arr.length-1; i>0; i--) {
// 将最后一个元素与根结点值进行交换
swap(arr, 0, i);
// 交换完成后重新调整大顶堆
maxHeap(arr, i, 0);
}
} /**
* 2路归并排序算法
* @param arr 原数组
* @param start 左边界
* @param end 右边界
*/
private static void merge(int[] arr, int start, int end) {
// 满足条件进行递归
if (start < end) {
int mid = (end + start) / 2;
// 对左子数组进行归并排序
merge(arr, start, mid);
// 对右子数组进行归并排序
merge(arr, mid + 1, end);
// 合并
int[] temp = new int[end - start + 1];
int i = start, j = mid + 1, k = 0;
while (i <= mid && j <= end) {
temp[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= end) {
temp[k++] = arr[j++];
}
System.arraycopy(temp, 0, arr, start, end - start + 1);
}
} /**
* 调用2路归并排序算法
* @param arr 原数组
*/
public static void mergeSort(int[] arr) {
merge(arr, 0, arr.length - 1);
} /**
* 快速排序
* @param arr 原数组
* @param start 左指针
* @param end 右指针
*/
private static void sort02(int[] arr, int start, int end) {
// 满足条件进行递归
if (start < end) {
// 定义哨兵i和j指向数组头尾
int i = start, j = end;
// 哨兵不相遇则执行循环
while (i < j) {
// 一定是尾部哨兵j先行动
// 若arr[j]>中轴值则进行循环 否则跳出循环
while (i < j && arr[j] > arr[start]) {
j--;
}
// 尾部哨兵j停止行动后头部哨兵i行动
// 若arr[j]<=中轴值则进行循环 否则跳出循环
while (i < j && arr[i] <= arr[start]) {
i++;
}
// 哨兵行动完成后对i和j所在的值进行交换
if (i<j) {
swap(arr, i, j);
}
}
// 将中轴值与i处的值交换
// 保证中轴左边都比它小右边都比它大
swap(arr, start, i);
// 递归对中轴左边的子数组进行快排
sort02(arr, start, i - 1);
// 递归对中轴右边的子数组进行快排
sort02(arr, i + 1, end);
} } /**
* 调用快速排序算法
* @param arr 原数组
*/
public static void quickSort(int[] arr) {
sort02(arr, 0, arr.length-1);
}
}
算法测试:排序测试类SortTest
package com.chiaki.demo;

import org.junit.After;
import org.junit.Before;
import org.junit.Test; import static com.chiaki.demo.Sort.*; /**
* 排序测试类
* @author Chiaki
*/
public class SortTest {
private int[] arr; @Before
public void init() {
arr = new int[]{49, 38, 65, 97, 76, 13, 27, 50, 88};
System.out.print("Before: ");
printArr(arr);
} @After
public void show() {
System.out.print("After : ");
printArr(arr);
} /**
* 冒泡排序01测试结果
* Before: 49 38 65 97 76 13 27 50 88
* After : 13 27 38 49 50 65 76 88 97
*/
@Test
public void bubbleSortTest01() {
bubbleSort01(arr);
} /**
* 冒泡排序02测试结果
* Before: 49 38 65 97 76 13 27 50 88
* After : 13 27 38 49 50 65 76 88 97
*/
@Test
public void bubbleSortTest02() {
bubbleSort02(arr);
} /**
* 选择排序测试结果
* Before: 49 38 65 97 76 13 27 50 88
* After : 13 27 38 49 50 65 76 88 97
*/
@Test
public void selectSortTest() {
selectSort(arr);
} /**
* 插入排序测试结果
* Before: 49 38 65 97 76 13 27 50 88
* After : 13 27 38 49 50 65 76 88 97
*/
@Test
public void insertSortTest() {
insertSort(arr);
} /**
* 希尔排序测试结果
* Before: 49 38 65 97 76 13 27 50 88
* After : 13 27 38 49 50 65 76 88 97
*/
@Test
public void shellSortTest() {
shellSort(arr);
} /**
* 堆排序测试结果
* Before: 49 38 65 97 76 13 27 50 88
* After : 13 27 38 49 50 65 76 88 97
*/
@Test
public void heapSortTest() {
heapSort(arr);
} /**
* 归并排序测试结果
* Before: 49 38 65 97 76 13 27 50 88
* After : 13 27 38 49 50 65 76 88 97
*/
@Test
public void mergeSortTest() {
mergeSort(arr);
} /**
* 快速排序测试结果
* Before: 49 38 65 97 76 13 27 50 88
* After : 13 27 38 49 50 65 76 88 97
*/
@Test
public void quickSortTest() {
quickSort(arr);
}
}

结果显示上述算法均通过测试。

Java实现经典七大经典排序算法的更多相关文章

  1. Java基础复习笔记基本排序算法

    Java基础复习笔记基本排序算法 1. 排序 排序是一个历来都是很多算法家热衷的领域,到现在还有很多数学家兼计算机专家还在研究.而排序是计算机程序开发中常用的一种操作.为何需要排序呢.我们在所有的系统 ...

  2. 程序兵法:Java String 源码的排序算法(一)

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 <程序兵法:Java Str ...

  3. Java中的数据结构及排序算法

    (明天补充) 主要是3种接口:List Set Map List:ArrayList,LinkedList:顺序表ArrayList,链表LinkedList,堆栈和队列可以使用LinkedList模 ...

  4. Java数据结构(七)—— 排序算法

    排序算法(Sort Algorithm) 排序算法介绍和分类 将一组数据,依指定顺序进行排列 排序的分类 内部排序 指将需要处理的所有数据都加载到内部存储器中进行排序 外部排序 数据量过大,无法全部加 ...

  5. Java常用的7大排序算法汇总

    1.插入排序算法 插入排序的基本思想是在遍历数组的过程中,假设在序号 i 之前的元素即 [0..i-1] 都已经排好序,本趟需要找到 i 对应的元素 x 的正确位置 k ,并且在寻找这个位置 k 的过 ...

  6. Java常见的几种排序算法-插入、选择、冒泡、快排、堆排等

    本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...

  7. java小程序整理及排序算法

    1. 利用循环打印如下图形 ***** **** *** ** * public class Main { public static void main(String[] args) { // TO ...

  8. 学习Java 以及对几大基本排序算法(对算法笔记书的研究)的一些学习总结(Java对算法的实现持续更新中)

    Java排序一,冒泡排序! 刚刚开始学习Java,但是比较有兴趣研究算法.最近看了一本算法笔记,刚开始只是打算随便看看,但是发现这本书非常不错,尤其是对排序算法,以及哈希函数的一些解释,让我非常的感兴 ...

  9. java泛型中使用的排序算法——归并排序及分析

    一.引言 我们知道,java中泛型排序使用归并排序或TimSort.归并排序以O(NlogN)最坏时间运行,下面我们分析归并排序过程及分析证明时间复杂度:也会简述为什么java选择归并排序作为泛型的排 ...

随机推荐

  1. 使用Red5-Pro Android官方Demo拆解分析(一)

    一.配置文件 1.导入库文件jniLibs到main文件夹下 2.导入red5streaming.jar 3.在build里到入其他的包,代码如下: dependencies { implementa ...

  2. OSCP Learning Notes - Exploit(8)

    Tools: 3. hydra Hydra v8.9.1 (c) 2019 by van Hauser/THC - Please do not use in military or secret se ...

  3. pyinstall打包资源文件

    相关代码 main.py import sys import os #生成资源文件目录访问路径 #说明: pyinstaller工具打包的可执行文件,运行时sys.frozen会被设置成True # ...

  4. C++语法小记---函数对象

    函数对象 用于替代函数指针 优势:函数对象内部可以保存状态,而不必使用全局变量或静态局部变量 关键:重载"()"操作符 #include<iostream> #incl ...

  5. socket解决半包、粘包问题

    最近项目遇到socket服务端接收报文不全的问题,与其客户端约定的是报文长度+报文体.然而当客户端数据量大的时候,用分包发送,导致服务端报文日志接收不完整,于是想着先读出包体长度,再读出包体,不够就一 ...

  6. 完成的设备扫描项目的几个关键程序,包括activity之间的转换

    module 的 gradle.build最后三行的compile 是关键dependencies { implementation fileTree(dir: 'libs', include: [' ...

  7. PHP入门之类型与运算符

    前言 PHP对于大部分人来说,是比较容易入门的.笔者也是刚学习不久,所以就把自己学习的基础知识进行总结和整理.第一部分是类型与运算符.如果你想学习PHP,可以参考PHP学习手册学习,任何一本教学资料也 ...

  8. python可变与不可变数据类型+深浅拷贝

    转自:https://www.cnblogs.com/miaomiaokaixin/p/11497813.html 一:学习内容 python3中六种数据类型 python赋值 python浅拷贝 p ...

  9. lua中单引号和双引号和/的输出的问题

    lua单引号和双引号的问题 lua 中的 单引号 与 双引号 (" " 与 '') Lua除支持双引号("")表示字符串外, 也支持用单引号('') 注意: 如 ...

  10. 给我半首歌的时间,给你说明白Immutable List

    先看再点赞,给自己一点思考的时间,微信搜索[沉默王二]关注这个靠才华苟且的程序员.本文 GitHub github.com/itwanger 已收录,里面还有一线大厂整理的面试题,以及我的系列文章. ...