一、冒泡排序(Bubble Sort)

基础版

/**
* 遍历数组,依次比较相邻的元素并交换,每次都将最大元素(根据正序还是逆序决定)放到数组末尾
* @param arr 待排序数组
* @return
*/
public static int[] bubbleSort(int[] arr) {
int temp; for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}

优化一

//冒泡排序:优化一
public static int[] bubbleSort1(int[] arr) {
int temp;
//记录数组是否有序
boolean isSorted; for (int i = 0; i < arr.length - 1; i++) {
isSorted = true;
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
//记录本轮排序是否交换了元素,如果交换则置为false
isSorted = false;
}
}
//没有交换证明已经是有序的了,直接终止循环
if (isSorted) {
break;
}
}
return arr;
}

优化二

//冒泡排序:优化二
public static int[] bubbleSort2(int[] arr) {
int temp;
boolean isSorted;
//第一次循环边界
int sortBorder = arr.length - 1;
//记录每轮排序最后一次进行交换的位置
int lastSwapIndex = 0; for (int i = 0; i < arr.length - 1; i++) {
isSorted = true;
for (int j = 0; j < sortBorder; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
isSorted = false;
lastSwapIndex = j;
}
}
sortBorder = lastSwapIndex;
if (isSorted) {
break;
}
}
return arr;
}

二、选择排序(Selection Sort)

/**
* 遍历数组,每次遍历都找到最小的元素,记录其下标,内层循环结束后再根据下标将其与数组头部元素交换
* 与冒泡排序不同的是,冒泡排序每次循环可能交换多次,而选择排序最多交换一次
* @param arr 待排序数组
* @return
*/
public static int[] selectionSort(int[] arr) {
int temp, minIndex;
for (int i = 0; i < arr.length - 1; i++) {
minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
return arr;
}

三、插入排序(Insertion Sort)

/**
* 用一个临时变量存储待插入的值,从后往前找,如果找到比这个值大的元素,则将其前面的元素依次后移,
* 结束后再将带插入的值放到该插入的位置,减去了许多不必要的交换操作
* @param arr
* @return
*/
public static int[] insertionSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
int insertValue = arr[i];//待插入元素
int preIndex = i - 1;
while (preIndex >= 0 && insertValue < arr[preIndex]) {
arr[preIndex + 1] = arr[preIndex];
preIndex--;
}
arr[preIndex + 1] = insertValue;
}
return arr;
}

四、希尔排序(Shell Sort)

/**
* 希尔排序
* 插入排序的升级版,设定步长为数组长度的一半,每次都除以二,直到步长为1
* @param arr
* @return
*/
public static int[] shellSort(int[] arr) {
int len = arr.length;
for (int k = len / 2; k > 0; k /= 2) {
for (int i = k; i < len; i++) {
int temp = arr[i];
int j = i - k;
while (j >= 0 && temp < arr[j]) {
arr[j + k] = arr[j];
j -= k;
}
arr[j + k] = temp;
}
}
return arr;
}

五、归并排序(Merge Sort)

//归并排序
public static int[] mergeSort(int[] arr) {
return mergeSort(arr, 0, arr.length - 1, new int[arr.length]);
} /**
* 归并排序通过递归将数组分解为只有两个元素,按照它们的大小放入到一个临时数组中,直到全部合并
*
* @param arr 待排序数组
* @param left 左索引
* @param right 右索引
* @param temp 临时数组,存储每次合并后的元素
* @return
*/
public static int[] mergeSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) >> 1;
//向左分解
mergeSort(arr, left, mid, temp);
//向右分解
mergeSort(arr, mid + 1, right, temp);
//合并
merge(arr, left, mid, right, temp);
}
return arr;
} //合并
public static int[] merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left, j = mid + 1, k = 0;
//按大小放入临时数组中
while (i <= mid && j <= right) {
if (arr[i] < arr[j]) {
temp[k] = arr[i];
k++;
i++;
} else {
temp[k] = arr[j];
k++;
j++;
}
} //将剩余元素放到temp剩余位置
while (i <= mid) {
temp[k] = arr[i];
k++;
i++;
}
while (j <= right) {
temp[k] = arr[j];
k++;
j++;
} //将排好序的temp数组元素赋值给原数组
k = 0;
int l = left;
while (l <= right) {
arr[l] = temp[k];
k++;
l++;
} return arr;
}

六、快速排序(Quick Sort)

//快速排序
public static int[] quickSort(int[] arr) {
return quickSort(arr, 0, arr.length - 1);
} public static int[] quickSort(int[] arr, int startIndex, int endIndex) {
if (startIndex < endIndex) {
//获取基准对应的下标
int pivotIndex = partition1(arr, startIndex, endIndex);
quickSort(arr, startIndex, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, endIndex);
}
return arr;
} /**
* 方式一:双边循环交换
* 先从右边找到比基准元素小的值,再从左边找到比基准元素大的值,然后交换两者
* 直到左右指针相遇,再交换基准和相遇位置的值
*
* @param arr 待排序数组
* @param startIndex 起始索引
* @param endIndex 结束索引
* @return 返回基准索引
*/
public static int partition1(int[] arr, int startIndex, int endIndex) {
//取第一个元素作为基准,也可以取一个随机元素与第一个元素交换
int pivot = arr[startIndex];
int left = startIndex, right = endIndex;
int temp;
while (left != right) {
while (left < right && arr[right] > pivot) {
right--;
}
while (left < right && arr[left] <= pivot) {
left++;
}
//交换左右元素
if (left < right) {
temp = arr[right];
arr[right] = arr[left];
arr[left] = temp;
}
}
//交换重合位置元素和基准
arr[startIndex] = arr[left];
arr[left] = pivot; return left;
} //方式二:单边循环
public static int partition2(int[] arr, int startIndex, int endIndex) {
int pivot = arr[startIndex];
//定义一个mark,数组向右寻找比pivot小的元素,找到后mark+1,然后互相交换
int mark = startIndex;
for (int i = startIndex + 1; i <= endIndex; i++) {
if (arr[i] < pivot) {
mark++;
int temp = arr[i];
arr[i] = arr[mark];
arr[mark] = temp;
}
}
//交换mark位置的值和pivot
arr[startIndex] = arr[mark];
arr[mark] = pivot;
return mark;
}

七、堆排序(Heap Sort)

public static int[] heapSort(int[] arr) {
//以最后一个非叶子结点构建大顶堆
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, arr.length);
}
//此时顶部元素是最大的,交换顶部元素和末端元素
for (int i = arr.length - 1; i > 0; i--) {
swap(arr, 0, i);
//末端元素已经是最大的了,无需考虑排序
adjustHeap(arr, 0, i);
}
return arr;
} /**
* 形成大顶堆
*
* @param arr 数组元素
* @param i 当前结点位置
* @param len 结点个数
*/
public static void adjustHeap(int[] arr, int i, int len) {
//保存当前结点
int temp = arr[i];
//遍历当前结点的左子结点
for (int k = 2 * i + 1; k < len; k = 2 * k + 1) {
//如果右结点存在 且 右结点比左结点大,指向右结点
if (k + 1 < len && arr[k] < arr[k + 1]) {
k++;
}
//判断当前结点和左(右)结点哪个大
if (temp < arr[k]) {
//交换
swap(arr, k, i);
//交换后,下次遍历以该子结点作为根节点的子树就会受到影响,因此需要重新指定下次的根节点
i = k;
} else {
//不用交换,直接终止循环
break;
}
}
} public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}

八、计数排序(Counting Sort)

/**
* 计数排序:
* 将待排序数组的值(或者差值)作为新数组的下标,新数组的值是排序元素在此位置的个数
* 使用max-min+1作为数组长度可以减少空间浪费
*
* @param arr
* @return
*/
public static int[] countingSort(int[] arr){
int max = arr[0];
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if(max < arr[i]){
max = arr[i];
}
if(min > arr[i]){
min = arr[i];
}
}
int[] count = new int[max - min + 1];
//将待排序数组放到count中
for (int value : arr) {
count[value - min]++;
}
//将count放到arr中
int k = 0;
for (int i = 0; i < count.length; i++) {
while(count[i] > 0){
arr[k++] = i;
count[i]--;
}
}
return arr;
}

优化

//计数排序优化,变为稳定排序
public static int[] countingSort1(int[] arr){
int max = arr[0];
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if(max < arr[i]){
max = arr[i];
}
if(min > arr[i]){
min = arr[i];
}
}
int[] count = new int[max - min + 1];
//将待排序数组放到count中
for (int value : arr) {
count[value - min]++;
}
//当前的元素等于前面的元素加上当前
for (int i = 1; i < count.length; i++) {
count[i] += count[i-1];
} //倒序遍历count
int[] storedArr = new int[arr.length];
for (int i = arr.length - 1; i >= 0; i--) {
storedArr[count[arr[i] - min]-1] = arr[i];
count[arr[i] - min]--;
}
return storedArr;
}

九、桶排序(Bucket Sort)

public class BucketSort {
/**
* 桶排序:
* 将数据分为n个区间,区间的跨度为 (max - min) / (n - 1)
*
* @param arr
* @return
*/
public static int[] bucketSort(int[] arr){
int max = arr[0];
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
if (min > arr[i]) {
min = arr[i];
}
}
int bucketNum = arr.length;//桶个数
int d = max - min;//差值
ArrayList<LinkedList<Integer>> bucketList = new ArrayList<>(bucketNum);//模拟5个桶 //初始化桶
for (int i = 0; i < bucketNum; i++) {
bucketList.add(new LinkedList<>());
} //将待排序元素放到桶中
for (int i = 0; i < arr.length; i++) {
int num = (arr[i] - min) * d / (bucketNum - 1);//应该存入的桶号
bucketList.get(num).add(arr[i]);
} //对每个桶的数据进行排序
for (int i = 0; i < bucketNum; i++) {
//JDK 底层采用了归并排序(1.7之前)或归并的优化版本
Collections.sort(bucketList.get(i));
} //将桶的数据取出
int k = 0;
for (LinkedList<Integer> nums : bucketList) {
for (Integer num : nums) {
arr[k++] = num;
}
} return arr;
}
}

十、基数排序(Radix Sort)

public class RadixSort {
/**
* 基数排序:
* 根据每个数的个位、十位、百位...的值(0~9)放入桶中(规则和计数排序相同),因此需要10个桶
*
* @param arr
* @return
*/
public static int[] radixSort(int[] arr){
//创建并初始化10个桶
ArrayList<LinkedList<Integer>> bucketList = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
bucketList.add(new LinkedList<>());
} //找出数据中最大值
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
} //获取最大值的位数
int maxRadix = (max + "").length();
//从个位开始
for (int i = 0; i < maxRadix; i++) {
//将待排序元素放入桶中
for (int j = 0; j < arr.length; j++) {
//获取数字对应位上的值
int radix = arr[j] / (int) Math.pow(10, i) % 10;
//放入对应的桶中
bucketList.get(radix).add(arr[j]);
}
//将桶中元素放回原数组
int k = 0;
for (int j = 0; j < 10; j++) {
for (Integer number : bucketList.get(j)) {
arr[k++] = number;
}
bucketList.get(j).clear();
}
}
return arr;
}
}

最后:测试

public static void main(String[] args) {
int[] arr = {3, 1, 9, 10, 4, 0, 6, 5, 2, 12, 8, 7, 11};
//[0, 3, 4, 5, 6, 7, 8, 10, 16, 22, 29, 33, 38]
System.out.println("冒泡排序:"+ Arrays.toString(bubbleSort(arr)));
System.out.println("冒泡排序-优化1:"+ Arrays.toString(bubbleSort1(arr)));
System.out.println("冒泡排序-优化2:"+ Arrays.toString(bubbleSort2(arr)));
System.out.println("选择排序:"+ Arrays.toString(selectionSort(arr)));
System.out.println("插入排序:"+ Arrays.toString(insertionSort(arr)));
System.out.println("希尔排序:"+ Arrays.toString(shellSort(arr)));
System.out.println("归并排序:"+ Arrays.toString(mergeSort(arr)));
System.out.println("快速排序:"+ Arrays.toString(quickSort(arr)));
System.out.println("堆排序:"+ Arrays.toString(heapSort(arr)));
System.out.println("计数排序:"+ Arrays.toString(countingSort(arr)));
System.out.println("计数排序-优化1:"+ Arrays.toString(countingSort1(arr)));
System.out.println("桶排序:"+ Arrays.toString(bucketSort(arr)));
System.out.println("基数排序:"+ Arrays.toString(radixSort(arr)));
}

十大排序算法(Java实现)的更多相关文章

  1. 十大排序算法总结(Python3实现)

    十大排序算法总结(Python3实现) 本文链接:https://blog.csdn.net/aiya_aiya_/article/details/79846380 目录 一.概述 二.算法简介及代码 ...

  2. Algorithm --> 十大排序算法

    十大排序算法 主要排序法有:  一.冒泡( Bubble)排序—— 相邻交换  二.选择排序 ——每次最小/ 大排在相应的位置  三.插入排序 ——将下一个插入已排好的序列中  四.壳( Shell) ...

  3. [ 转载 ] js十大排序算法:冒泡排序

    js十大排序算法:冒泡排序  http://www.cnblogs.com/beli/p/6297741.html

  4. 十大排序算法JavaScript实现总结

    花费了几周的时间断断续续的练习和模仿与使用JavaScript代码实现了十大排序算法. 里面有每种算法的动图和静态图片演示,看到图片可以自己先按照图片的思路实现一下. github中正文链接,点击查看 ...

  5. 一篇夯实一个知识点系列--python实现十大排序算法

    写在前面 排序是查找是算法中最重要的两个概念,我们大多数情况下都在进行查找和排序.科学家们穷尽努力,想使得排序和查找能够更加快速.本篇文章用Python实现十大排序算法. 干货儿 排序算法从不同维度可 ...

  6. 使用 js 实现十大排序算法: 快速排序

    使用 js 实现十大排序算法: 快速排序 QuickSort 快速排序 /** * * @author xgqfrms * @license MIT * @copyright xgqfrms * @c ...

  7. 使用 js 实现十大排序算法: 桶排序

    使用 js 实现十大排序算法: 桶排序 桶排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  8. 使用 js 实现十大排序算法: 计数排序

    使用 js 实现十大排序算法: 计数排序 计数排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  9. 使用 js 实现十大排序算法: 基数排序

    使用 js 实现十大排序算法: 基数排序 基数排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  10. 使用 js 实现十大排序算法: 冒泡排序

    使用 js 实现十大排序算法: 冒泡排序 冒泡排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

随机推荐

  1. linux进程 阻塞和非阻塞操作

    在我们看全功能的 read 和 write 方法的实现之前, 我们触及的最后一点是决定何时使 进程睡眠. 有时实现正确的 unix 语义要求一个操作不阻塞, 即便它不能完全地进行下去. 有时还有调用进 ...

  2. Delta Lake基础操作和原理

    目录 Delta Lake 特性 maven依赖 使用aws s3文件系统快速启动 基础表操作 merge操作 delta lake更改现有数据的具体过程 delta表schema 事务日志 delt ...

  3. TCPIP四层模型和OSI七层模型对应表

  4. 用postman验证接口是否可掉通

    1.结合fidder抓包工具 2.打开postman 3.点击Launchpad右边“+” 4.选择postman,url粘贴fidder抓出来的数据 5.Header中粘贴fidder抓出来的KEY ...

  5. shelve模块、re模块

    在模糊匹配时使用 1

  6. 【时区问题】SpringBoot+mybatis查询mysql的datetime类型数据时间差14小时

    [时区问题]MyBatis查询MySQL的datetime类型数据时间差14小时 故障解决方式 与数据库连接时,定义时区,避免mybatis框架从mysql获取时区.在连接上加上 serverTime ...

  7. 多线程之美7一ReentrantReadWriteLock源码分析

    目录 前言 在多线程环境下,为了保证线程安全, 我们通常会对共享资源加锁操作,我们常用Synchronized关键字或者ReentrantLock 来实现,这两者加锁方式都是排他锁,即同一时刻最多允许 ...

  8. 给你的 ASP.NET Core 程序插上 Feature Flag 的翅膀

    前言 我们知道,目前大多数应用程序在正式发布到生产环境之前都会经历多个不同的测试环境,通过让应用程序在多个不同的环境中运行来及时发现并解决问题,避免在线上发生不必要的损失.这是对于整个软件的发布流程来 ...

  9. 【题解】LOJ6060 Set(线性基)

    [题解]LOJ6060 Set(线性基) orz gql 设所有数的异或和为\(S\),答案是在\(\max (x_1+S\and x_1)\)的前提下\(\min x_1\)输出\(x_1\) 转换 ...

  10. MyBatis原理-延迟加载,一级缓存,二级缓存设置

    一.延迟加载 resultMap中的association和collection标签具有延迟加载的功能. 延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息.使用关联信息时再去加载关联信息. ...