java中的8大排序算法
1.背景
排序算法经常在面试中问到.....
2.排序算法
2.1.冒泡排序
package com.ldp.structure.demo02; import org.junit.Test; import java.util.Arrays; /** * @create 04/15 7:17 * @description <p> * 冒泡排序 * </p> */ public class Test01BubblingSort { @Test public void test01() { // int[] array = {7, 20, 2, 3, 8, 12, 11}; int[] array = {8, 2, 1, 3, 7, 10, -1}; // int[] array = {8, 2, 1, 3, 7}; bubblingSort(array); } /** * 冒泡排序,相邻之间比较 * * @param array */ public void bubblingSort(int[] array) { System.out.printf("\n 第:0 轮,array=%s", Arrays.toString(array)); int length = array.length; int temp; boolean flag = false; for (int i = 0; i < length - 1; i++) { for (int j = 0; j < length - 1 - i; j++) { if (array[j] > array[j + 1]) { flag = true; temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; } } System.out.printf("\n 第:%d 轮,array=%s", (i), Arrays.toString(array)); // 如果没有发送交换,则说明已经排好了,结束循环 if (!flag) { break; } else { // 初始化 flag = false; } } } }
2.2.选择排序
package com.ldp.structure.demo02; import org.junit.Test; import java.util.Arrays; /** * @create 04/15 7:17 * @description <p> * 冒泡排序 * </p> */ public class Test02SelectSort { @Test public void test01() { // int[] array = {7, 20, 2, 3, 8, 12, 11}; int[] array = {8, 2, 1, 3, 7, 10, -1}; selectSort(array); // selectSort2(array); } /** * 选择排序 * * @param array */ public void selectSort(int[] array) { int length = array.length; int temp; for (int i = 0; i < length - 1; i++) { for (int j = i + 1; j < length; j++) { if (array[i] > array[j]) { temp = array[i]; array[i] = array[j]; array[j] = temp; } } System.out.printf("\n 第:%d 轮,array=%s", (i + 1), Arrays.toString(array)); } } /** * 选择排序(减少交换次数) * * @param array */ public void selectSort2(int[] array) { int length = array.length; int temp; for (int i = 0; i < length - 1; i++) { int minIndex = i; int minNum = array[i]; for (int j = i + 1; j < length; j++) { if (minNum > array[j]) { // 循环找到最小值 minNum = array[j]; minIndex = j; } } // 检查是否有交换 if (i != minIndex) { array[minIndex] = array[i]; array[i] = minNum; } System.out.printf("\n 第:%d 轮,array=%s", (i + 1), Arrays.toString(array)); } } }
2.3.插入排序
package com.ldp.structure.demo02; import org.junit.Test; import java.util.Arrays; /** * @create 04/16 8:30 * @description <p> * 插入排序 * 思维:与打扑克.摸牌的思维一样 * </p> */ public class Test03InsertSort { /** * 测试排序入口 */ @Test public void insertSort() { int[] array = {100, 80, 60, 70, -1}; System.out.printf("\n 第 %d 轮排序:%s ", 0, Arrays.toString(array)); int length = array.length; for (int i = 1; i < length; i++) { int insertData = array[i];// insertData 表示待插入的值 int insertIndex = i - 1;// insertIndex 表示待插入的下标 // array[insertIndex] : 表示待插入下标的值 while (insertIndex >= 0 && insertData < array[insertIndex]) { // 如果待插入下标的值(array[insertIndex])比待插入的值(insertData)大,这把待插入位置的值往前移动 array[insertIndex + 1] = array[insertIndex]; insertIndex--; // 检查下一个下标值 } if (insertIndex != (i - 1)) { array[insertIndex + 1] = insertData; // 为什么要加1,因为while执行完成前-1了 } System.out.printf("\n 第 %d 轮排序:%s ", i, Arrays.toString(array)); } } /** * 插入排序思路分析 */ @Test public void insertSortAnalysis() { int[] array = {100, 80, 60, 70, -1}; System.out.printf("\n 第 0 轮排序: " + Arrays.toString(array)); // 第 1 轮排序: {100}(80, 60, 70, -1) 把80找到一个合适的位置 int insertData = array[1];// insertData 表示待插入的值 int insertIndex = 1 - 1;// insertIndex 表示待插入的下标 // array[insertIndex] : 表示待插入下标的值 while (insertIndex >= 0 && insertData < array[insertIndex]) { // 如果待插入下标的值(array[insertIndex])比待插入的值(insertData)大,这把待插入位置的值往前移动 array[insertIndex + 1] = array[insertIndex]; insertIndex--; // 检查下一个下标值 } if (insertIndex != (1 - 1)) { array[insertIndex + 1] = insertData; // 为什么要加1,因为while执行完成前-1了 } System.out.printf("\n 第 1 轮排序: " + Arrays.toString(array)); // 第 2 轮排序: {80,100}(60, 70, -1) 把60找到一个合适的位置 insertData = array[2];// insertData 表示待插入的值 insertIndex = 2 - 1;// insertIndex 表示待插入的下标 // array[insertIndex] : 表示待插入下标的值 while (insertIndex >= 0 && insertData < array[insertIndex]) { // 如果待插入下标的值(array[insertIndex])比待插入的值(insertData)大,这把待插入位置的值往前移动 array[insertIndex + 1] = array[insertIndex]; insertIndex--; // 检查下一个下标值 } if (insertIndex != (2 - 1)) { array[insertIndex + 1] = insertData; // 为什么要加1,因为while执行完成前-1了 } System.out.printf("\n 第 2 轮排序: " + Arrays.toString(array)); // 第 3 轮排序: {100,80, 60}( 70, -1) 把70找到一个合适的位置 insertData = array[3];// insertData 表示待插入的值 insertIndex = 3 - 1;// insertIndex 表示待插入的下标 // array[insertIndex] : 表示待插入下标的值 while (insertIndex >= 0 && insertData < array[insertIndex]) { // 如果待插入下标的值(array[insertIndex])比待插入的值(insertData)大,这把待插入位置的值往前移动 array[insertIndex + 1] = array[insertIndex]; insertIndex--; // 检查下一个下标值 } if (insertIndex != (3 - 1)) { array[insertIndex + 1] = insertData; // 为什么要加1,因为while执行完成前-1了 } System.out.printf("\n 第 3 轮排序: " + Arrays.toString(array)); // 第 4 轮排序: {100,80, 60, 70}( -1) 把-1找到一个合适的位置 insertData = array[4];// insertData 表示待插入的值 insertIndex = 4 - 1;// insertIndex 表示待插入的下标 // array[insertIndex] : 表示待插入下标的值 while (insertIndex >= 0 && insertData < array[insertIndex]) { // 如果待插入下标的值(array[insertIndex])比待插入的值(insertData)大,这把待插入位置的值往前移动 array[insertIndex + 1] = array[insertIndex]; insertIndex--; // 检查下一个下标值 } if (insertIndex != (4 - 1)) { array[insertIndex + 1] = insertData; // 为什么要加1,因为while执行完成前-1了 } System.out.printf("\n 第 4 轮排序: " + Arrays.toString(array)); } }
2.4.希尔排序
package com.ldp.structure.demo02; import org.junit.Test; import java.util.Arrays; /** * @create 04/16 11:12 * @description 希尔排序 */ public class Test04ShellSort { /** * 逐步分析 * 算法推导 */ @Test public void test01() { int[] array = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0}; System.out.printf("\n 第 %d 轮排序:%s ", 0, Arrays.toString(array)); int length = array.length; for (int i = 5; i < length; i++) { for (int j = i - 5; j >= 0; j -= 5) { // 相当于对分组后的每一组排序 if (array[j] > array[j + 5]) {// 左边的比右边的大,就交换位置 int temp = array[j]; array[j] = array[j + 5]; array[j + 5] = temp; } } } System.out.printf("\n 第 %d 轮排序:%s ", 1, Arrays.toString(array));//第 1 轮排序:[3, 5, 1, 6, 0, 8, 9, 4, 7, 2] for (int i = 2; i < length; i++) { for (int j = i - 2; j >= 0; j -= 2) { // 相当于对分组后的每一组排序 if (array[j] > array[j + 2]) {// 左边的比右边的大,就交换位置 int temp = array[j]; array[j] = array[j + 2]; array[j + 2] = temp; } } } System.out.printf("\n 第 %d 轮排序:%s ", 2, Arrays.toString(array));//第 2 轮排序:[0, 2, 1, 4, 3, 5, 7, 6, 9, 8] for (int i = 1; i < length; i++) { for (int j = i - 1; j >= 0; j -= 1) { // 相当于对分组后的每一组排序 if (array[j] > array[j + 1]) {// 左边的比右边的大,就交换位置 int temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; } } } System.out.printf("\n 第 %d 轮排序:%s ", 3, Arrays.toString(array));//第 2 轮排序:[0, 2, 1, 4, 3, 5, 7, 6, 9, 8] } /** * 希尔排序 * 分组+冒泡的方式 */ @Test public void test02() { //int[] array = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0}; int[] array = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0, -10, 18, 17, 7}; System.out.printf("\n 第 %d 轮排序:%s ", 0, Arrays.toString(array)); int length = array.length; int count = 0; for (int step = length / 2; step > 0; step /= 2) { for (int i = step; i < length; i++) { for (int j = i - step; j >= 0; j -= step) { // 相当于对分组后的每一组排序 if (array[j] > array[j + step]) {// 左边的比右边的大,就交换位置 int temp = array[j]; array[j] = array[j + step]; array[j + step] = temp; } } } System.out.printf("\n 第 %d 轮排序:%s ", (++count), Arrays.toString(array));//第 1 轮排序:[3, 5, 1, 6, 0, 8, 9, 4, 7, 2] } } /** * 希尔排序 * 分组+插入的方式 */ @Test public void test03() { // int[] array = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0}; int[] array = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0, -10, 18, 17, 7}; System.out.printf("\n 第 %d 轮排序:%s ", 0, Arrays.toString(array)); int length = array.length; int count = 0; for (int step = length / 2; step > 0; step /= 2) { for (int i = step; i < length; i++) { // 内部是插入排序的思维 int insertData = array[i];// insertData 表示待插入的值 int insertIndex = i - step;// insertIndex 表示待插入的下标 while (insertIndex >= 0 && insertData < array[insertIndex]) { array[insertIndex + step] = array[insertIndex]; insertIndex = insertIndex - step; } array[insertIndex + step] = insertData; } System.out.printf("\n 第 %d 轮排序:%s ", (++count), Arrays.toString(array));//第 1 轮排序:[3, 5, 1, 6, 0, 8, 9, 4, 7, 2] } } }
2.5.快速排序
package com.ldp.structure.demo02; import org.junit.Test; import java.util.Arrays; /** * @create 04/16 5:48 * @description <p> * 快速排序 * </p> */ public class Test05FastSort { @Test public void test01() { int[] array = {80, -9, 1, 0, 30, -5, 4}; fastSort(array, 0, array.length - 1); } /** * 快速排序 * * @param array 需要排序的数组 * @param leftIndex 最左边的下标 * @param rightIndex 最右边的下标 */ public void fastSort(int[] array, int leftIndex, int rightIndex) { // 临时值 int leftTempIndex = leftIndex; int rightTempIndex = rightIndex; // 中心下标的值 int centerValue = array[(leftIndex + rightIndex) / 2]; // 0 // 用于交换的临时变量 int temp; // 将比中心值小的放到左边,比中心值大的放到右边 // 左下标-->>> 中心 <<<---右下标 while (leftTempIndex < rightTempIndex) { // 在中心值左边找,如果比中心值大就退出,说明该值不应在左边 {80, -9, 1, 0, 30, -5, 4} 当leftTempIndex=0时退出循环 while (array[leftTempIndex] < centerValue) { leftTempIndex++; } //在中心值右边找,如果右边的值小于中心值,说明该值不应在右边 {80, -9, 1, 0, 30, -5, 4} 当rightTempIndex=1时退出循环 while (array[rightTempIndex] > centerValue) { rightTempIndex--; } // 当leftTempIndex>=rightTempIndex,说明大于中心值的都已经在右边了,小于中心值的都已经在左边了 if (leftTempIndex >= rightTempIndex) { break; } // 交换 temp = array[leftTempIndex]; array[leftTempIndex] = array[rightTempIndex]; array[rightTempIndex] = temp; // 如果交换完成后,array[leftTempIndex]==centerValue,右下标左移动一下 if (array[leftTempIndex] == centerValue) { rightTempIndex--; } // 如果交换完成后,array[rightTempIndex]==centerValue,左下标右移动一下 if (array[rightTempIndex] == centerValue) { leftTempIndex++; } } // 循环完成后,左边的都是小于中心值的,右边的都是大于中心值的 System.out.println("左右是否以分开==>" + Arrays.toString(array)); // 始终保持,左右下标不相等 if (leftTempIndex == rightTempIndex) { leftTempIndex++; rightTempIndex--; } // 递归左侧 ,若leftIndex<leftTempIndex,说明上面的执行中左下标发生了右移动 if (leftIndex < rightTempIndex) { fastSort(array, leftIndex, rightTempIndex); } // 递归右侧 if (rightIndex > leftTempIndex) { fastSort(array, leftTempIndex, rightIndex); } } }
2.6.归并排序
package com.ldp.structure.demo02; import org.junit.Test; import java.util.Arrays; /** * @create 04/16 10:06 * @description <p> * 归并排序 * </p> */ public class Test06MergeSort { // 统计 int count = 0; @Test public void test01() { int[] array = {9, 5, 6, 8, 2, 4, 7, 3}; int[] tempArray = new int[array.length]; branchToMerge(array, 0, array.length - 1, tempArray); System.out.println("==>" + Arrays.toString(array)); } /** * 拆分+合并数组 * * @param array * @param left * @param right * @param tempArray */ public void branchToMerge(int[] array, int left, int right, int[] tempArray) { if (left < right) { int middle = (left + right) / 2; // 递归左边 branchToMerge(array, left, middle, tempArray); // 递归右边 branchToMerge(array, middle + 1, right, tempArray); // 合并 merge(array, left, middle, right, tempArray); } } /** * 按顺序合并数组 * * @param array 排序的数组 * @param left 左边下标 * @param middle 中间下标 * @param right 右侧下标 * @param tempArray 临时中间数组 */ public void merge(int[] array, int left, int middle, int right, int[] tempArray) { int i = left;// 左侧初始化下标 int j = middle + 1;// 右侧初始化下标 int t = 0;// 临时数组下标 //1. 按顺序把数组中的左右两边数据填充到临时数组中 while (i <= middle && j <= right) { if (array[i] <= array[j]) { // 如果左边数小,就把左边的数填充到临时数组 tempArray[t] = array[i]; i++; t++; } else { // 否则将右侧数组填充到临时数组 tempArray[t] = array[j]; t++; j++; } } //2. 把剩下的数组中的数字填充到临时数组中 while (i <= middle) {// 拷贝左边 tempArray[t] = array[i]; t++; i++; } while (j <= right) { tempArray[t] = array[j]; t++; j++; } //3. 把已经排序好的临时数组中数组依次复制到原来的数组中 t = 0; int tempLeftIndex = left; while (tempLeftIndex <= right) { array[tempLeftIndex] = tempArray[t]; t++; tempLeftIndex++; } } }
2.7.基数排序
package com.ldp.structure.demo02; import org.junit.Test; import java.util.Arrays; /** * @create 04/17 7:56 * @description <p> * 基数排序 * </p> */ public class Test07BaseSort { @Test public void test01() { int[] array = {80, 2, 108, 20, 148, 10, 527, 7, 45}; // baseSortAnalysis(array); baseSort(array); } /** * 基数排序 推导 * * @param array */ public void baseSortAnalysis(int[] array) { System.out.println("第 0 轮:" + Arrays.toString(array)); int length = array.length; // 循环将数据放入桶中 // 定义10个桶 int[][] bucketArray = new int[10][length]; // 定义一个记录桶中放入了多少个数的数组 // bucketCountArray[0]=X,表示第一个桶放入了X个数据,bucketCountArray[1]=Y,表示第二个桶放入了Y个数据 int[] bucketCountArray = new int[10]; // 第一轮存放 for (int i = 0; i < length; i++) { // 取个位数 int n = array[i] % 10; bucketArray[n][bucketCountArray[n]] = array[i]; // 统计数据量加一 bucketCountArray[n]++; } int t = 0; // 第一轮取 for (int i = 0; i < 10; i++) { // 判断桶中是否有数据 for (int j = 0; j < bucketCountArray[i]; j++) { array[t] = bucketArray[i][j]; t++; } // 将统计数量的桶中计算置为0 bucketCountArray[i] = 0; } System.out.println("第 1 轮:" + Arrays.toString(array)); // 第二轮存放 for (int i = 0; i < length; i++) { // 取个位数 int n = array[i] / 10 % 10; bucketArray[n][bucketCountArray[n]] = array[i]; // 统计数据量加一 bucketCountArray[n]++; } t = 0; // 取 for (int i = 0; i < 10; i++) { // 判断桶中是否有数据 for (int j = 0; j < bucketCountArray[i]; j++) { array[t] = bucketArray[i][j]; t++; } // 将统计数量的桶中计算置为0 bucketCountArray[i] = 0; } System.out.println("第 2 轮:" + Arrays.toString(array)); // 第三轮存放 for (int i = 0; i < length; i++) { // 取个位数 int n = array[i] / 100 % 10; bucketArray[n][bucketCountArray[n]] = array[i]; // 统计数据量加一 bucketCountArray[n]++; } t = 0; // 取 for (int i = 0; i < 10; i++) { // 判断桶中是否有数据 for (int j = 0; j < bucketCountArray[i]; j++) { array[t] = bucketArray[i][j]; t++; } // 将统计数量的桶中计算置为0 bucketCountArray[i] = 0; } System.out.println("第 3 轮:" + Arrays.toString(array)); } /** * 基数排序 * * @param array */ public void baseSort(int[] array) { System.out.println("第 0 轮:" + Arrays.toString(array)); // 1.寻找最大值 int length = array.length; int max = array[0]; for (int i = 1; i < length; i++) { if (array[i] > max) { max = array[i]; } } // 2.求最大值的长度 int maxLength = (max + "").length(); // 3.循环将数据放入桶中 // 定义10个桶 int[][] bucketArray = new int[10][length]; // 定义一个记录桶中放入了多少个数的数组 // bucketCountArray[0]=X,表示第一个桶放入了X个数据,bucketCountArray[1]=Y,表示第二个桶放入了Y个数据 int[] bucketCountArray = new int[10]; // m表示个,十,百每一轮的循环 // s是一个辅助取个,十,百数字的值, int n = array[i] / s % 10; for (int m = 0, s = 1; m < maxLength; m++, s *= 10) { for (int i = 0; i < length; i++) { // 取个,十,百位数 int n = array[i] / s % 10; bucketArray[n][bucketCountArray[n]] = array[i]; // 统计数据量加一 bucketCountArray[n]++; } int t = 0; // 第一轮取 for (int i = 0; i < 10; i++) { // 判断桶中是否有数据 for (int j = 0; j < bucketCountArray[i]; j++) { array[t] = bucketArray[i][j]; t++; } // 将统计数量的桶中计算置为0 bucketCountArray[i] = 0; } System.out.println("第 " + (m + 1) + " 轮:" + Arrays.toString(array)); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器