Java实现经典七大经典排序算法
利用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实现经典七大经典排序算法的更多相关文章
- Java基础复习笔记基本排序算法
Java基础复习笔记基本排序算法 1. 排序 排序是一个历来都是很多算法家热衷的领域,到现在还有很多数学家兼计算机专家还在研究.而排序是计算机程序开发中常用的一种操作.为何需要排序呢.我们在所有的系统 ...
- 程序兵法:Java String 源码的排序算法(一)
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 <程序兵法:Java Str ...
- Java中的数据结构及排序算法
(明天补充) 主要是3种接口:List Set Map List:ArrayList,LinkedList:顺序表ArrayList,链表LinkedList,堆栈和队列可以使用LinkedList模 ...
- Java数据结构(七)—— 排序算法
排序算法(Sort Algorithm) 排序算法介绍和分类 将一组数据,依指定顺序进行排列 排序的分类 内部排序 指将需要处理的所有数据都加载到内部存储器中进行排序 外部排序 数据量过大,无法全部加 ...
- Java常用的7大排序算法汇总
1.插入排序算法 插入排序的基本思想是在遍历数组的过程中,假设在序号 i 之前的元素即 [0..i-1] 都已经排好序,本趟需要找到 i 对应的元素 x 的正确位置 k ,并且在寻找这个位置 k 的过 ...
- Java常见的几种排序算法-插入、选择、冒泡、快排、堆排等
本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...
- java小程序整理及排序算法
1. 利用循环打印如下图形 ***** **** *** ** * public class Main { public static void main(String[] args) { // TO ...
- 学习Java 以及对几大基本排序算法(对算法笔记书的研究)的一些学习总结(Java对算法的实现持续更新中)
Java排序一,冒泡排序! 刚刚开始学习Java,但是比较有兴趣研究算法.最近看了一本算法笔记,刚开始只是打算随便看看,但是发现这本书非常不错,尤其是对排序算法,以及哈希函数的一些解释,让我非常的感兴 ...
- java泛型中使用的排序算法——归并排序及分析
一.引言 我们知道,java中泛型排序使用归并排序或TimSort.归并排序以O(NlogN)最坏时间运行,下面我们分析归并排序过程及分析证明时间复杂度:也会简述为什么java选择归并排序作为泛型的排 ...
随机推荐
- 利用cublasHgemm来实现cublasHgemv
前几天做half量化时发现cublas竟然没有提供half版本的矩阵-向量乘,也就是half版本的cublasHgemv.自己写一个又太麻烦,重点是精度和耗时不一定比cublas提供的要好,不过cub ...
- 视图相关SQL
前面介绍了视图的概念和作用,接下来简单的用实例SQL来展现视图. 例如:首先,创建表e_information.表e_shareholder: 然后插入表数据等,在此,这简单的部分我就省略了,直接写视 ...
- vs coed的使用(二) 如何运行cpp文件(不用插件比如code runner)
一.前提 1.配置好编译运行的环境,比如系统变量.vs code的settings.json 2.检查配置好的环境没有问题 我配置结果 [环境变量] [系统变量] 确定settings.json里面的 ...
- springcloud ribbon的 @LoadBalanced注解
在使用springcloud ribbon客户端负载均衡的时候,可以给RestTemplate bean 加一个@LoadBalanced注解,就能让这个RestTemplate在请求时拥有客户端负载 ...
- 一个文本框的andriod教程
https://blog.csdn.net/androidmsky/article/details/49870823
- Google免费新书-《构建安全&可靠的系统》
前段时间riusksk在公众号分享的Google安全团队的新书,好书,全英原版,开源免费. 免费下载地址:https://static.googleusercontent.com/media/land ...
- Spring Boot+Socket实现与html页面的长连接,客户端给服务器端发消息,服务器给客户端轮询发送消息,附案例源码
功能介绍 客户端给所有在线用户发送消息 客户端给指定在线用户发送消息 服务器给客户端发送消息(轮询方式) 项目搭建 项目结构图 pom.xml <?xml version="1.0&q ...
- 浅谈NTLM Hash
认识Windows Hash 早期SMB协议在网络上传输明文口令.后来出现LAN Manager 挑战/响应验证机制(LM),其很容易破解,因此微软提出了WindowsNT挑战/响应验证机制(NTLM ...
- 老男孩武老师的Django笔记
武老师的 Django 博客笔记 基础篇 https://www.cnblogs.com/wupeiqi/articles/5237704.html 进阶篇 https://www.cnblogs.c ...
- 设在起始地址为STRING的存储空间存放了一个字符串(该串已存放在内存中,无需输入,且串长不超过99),统计字符串中字符“A”的个数,并将结果显示在屏幕上。
问题 设在起始地址为STRING的存储空间存放了一个字符串(该串已存放在内存中,无需输入,且串长不超过99),统计字符串中字符"A"的个数,并将结果显示在屏幕上. 代码 data ...