选择排序
选择排序有简单选择排序,堆排序
简单选择排序:
import java.util.Arrays; import java.util.Random; public class Main { public static void main(String[] args) throws InterruptedException { int[] array = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3}; System.out.println(Arrays.toString(array)); selectionSort(array); System.out.println(Arrays.toString(array)); } //选择排序 public static void selectionSort(int[] array){ int minPoint; //存储最小元素的小标 int len = array.length; int temp; int counter = 1; for(int i=0;i<len-1;i++){ minPoint= i; for(int j=i+1;j<=len-1;j++){ //每完成一轮排序,就确定了一个相对最小元素,下一轮排序只对后面的元素排序 if(array[j]<array[minPoint]){ //如果待排数组中的某个元素比当前元素小,minPoint指向该元素的下标 minPoint= j; } } if(minPoint!=i){ //如果发现了更小的元素,交换位置 temp= array[i]; array[i]= array[minPoint]; array[minPoint]= temp; } System.out.print("第"+counter+"轮排序结果:"); display(array); counter++; } } private static void display(int[] array){ System.out.println(Arrays.toString(array)); } }

[9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3] 第1轮排序结果:[-3, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, 9] 第2轮排序结果:[-3, -2, 7, 6, 5, 4, 3, 2, 1, 0, -1, 8, 9] 第3轮排序结果:[-3, -2, -1, 6, 5, 4, 3, 2, 1, 0, 7, 8, 9] 第4轮排序结果:[-3, -2, -1, 0, 5, 4, 3, 2, 1, 6, 7, 8, 9] 第5轮排序结果:[-3, -2, -1, 0, 1, 4, 3, 2, 5, 6, 7, 8, 9] 第6轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 第7轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 第8轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 第9轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 第10轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 第11轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 第12轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
简单选择排序,就是一次遍历选择最小的,然后与第一位进行交换,然后再剩下的里面再次进行查找最小的,再次交换........
选择排序与冒泡排序一样,需要进行N*(N-1)/2次比较,但是只需要N次交换,当N很大时,交换次数的时间影响力更大,所以选择排序的时间复杂度为O(N2)。
虽然选择排序与冒泡排序在时间复杂度属于同一量级,但是毫无疑问选择排序的效率更高,因为它的交换操作次数更少,而且在交换操作比比较操作的时间级大得多时,选择排序的速度是相当快的。
优化方案:一次遍历查找出最小跟最大值,分别与第一位,最后一位进行交换,然后在剩下的数组里面再次进行查找最大,最小........
import java.util.Arrays; import java.util.Random; public class Main { public static void main(String[] args) throws InterruptedException { int[] array = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3}; System.out.println(Arrays.toString(array)); selectionSort_improvement(array); System.out.println(Arrays.toString(array)); } //选择排序改进版 public static void selectionSort_improvement(int[] array){ int minPoint; //存储最小元素的小标 int maxPoint; //存储最大元素的小标 int len = array.length; int temp; int counter = 1; for(int i=0;i<len/2;i++){ minPoint= i; maxPoint= i; for(int j=i+1;j<=len-1-i;j++){ //每完成一轮排序,就确定了两个最值,下一轮排序时比较范围减少两个元素 if(array[j]<array[minPoint]){ //如果待排数组中的某个元素比当前元素小,minPoint指向该元素的下标 minPoint= j; continue; }else if(array[j]>array[maxPoint]){ //如果待排数组中的某个元素比当前元素大,maxPoint指向该元素的下标 maxPoint= j; } } if(minPoint!=i){ //如果发现了更小的元素,与第一个元素交换位置 temp= array[i]; array[i]= array[minPoint]; array[minPoint]= temp; //原来的第一个元素已经与下标为minPoint的元素交换了位置 //如果之前maxPoint指向的是第一个元素,那么需要将maxPoint重新指向array[minPoint] //因为现在array[minPoint]存放的才是之前第一个元素中的数据 if(maxPoint== i){ maxPoint= minPoint; } } if(maxPoint!=len-1-i){ //如果发现了更大的元素,与最后一个元素交换位置 temp= array[len-1-i]; array[len-1-i]= array[maxPoint]; array[maxPoint]= temp; } System.out.print("第"+counter+"轮排序结果:"); display(array); counter++; } } private static void display(int[] array){ System.out.println(Arrays.toString(array)); } }

[9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3] 第1轮排序结果:[-3, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, 9] 第2轮排序结果:[-3, -2, 7, 6, 5, 4, 3, 2, 1, 0, -1, 8, 9] 第3轮排序结果:[-3, -2, -1, 6, 5, 4, 3, 2, 1, 0, 7, 8, 9] 第4轮排序结果:[-3, -2, -1, 0, 5, 4, 3, 2, 1, 6, 7, 8, 9] 第5轮排序结果:[-3, -2, -1, 0, 1, 4, 3, 2, 5, 6, 7, 8, 9] 第6轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
堆排序:
这个版本感觉不太好

import java.util.Arrays; import java.util.Random; public class Main { static int[] array = {7, 8, 9, 6, 1, 4, 3, 2, 5, 0, -1, -2,10,-3}; public static void main(String[] args) throws InterruptedException { System.out.println(Arrays.toString(array)); heapSort(); System.out.println(Arrays.toString(array)); } //堆排序 public static void heapSort(){ buildHeap(); System.out.println("建堆:"); printTree(array.length); int lastIndex = array.length-1; while(lastIndex>0){ swap(0,lastIndex); //取出堆顶元素,将堆底放入堆顶。其实就是交换下标为0与lastIndex的数据 if(--lastIndex == 0) break; //只有一个元素时就不用调整堆了,排序结束 adjustHeap(0,lastIndex); //调整堆 System.out.println("调整堆:"); printTree(lastIndex+1); } } /** * 用数组中的元素建堆 */ private static void buildHeap(){ int lastIndex = array.length-1; for(int i= (lastIndex-1)/2;i>=0;i--){ //(lastIndex-1)/2就是最后一个元素的根节点的下标,依次调整每棵子树 adjustHeap(i,lastIndex); //调整以下标i的元素为根的子树 } } /** * 调整以下标是rootIndex的元素为根的子树 *@param rootIndex 根的下标 *@param lastIndex 堆中最后一个元素的下标 */ private static void adjustHeap(int rootIndex,int lastIndex){ int biggerIndex = rootIndex; int leftChildIndex = 2*rootIndex+1; int rightChildIndex = 2*rootIndex+2; if(rightChildIndex<=lastIndex){ //存在右子节点,则必存在左子节点 if(array[rootIndex]<array[leftChildIndex] || array[rootIndex]<array[rightChildIndex]){ //子节点中存在比根更大的元素 biggerIndex = array[leftChildIndex]<array[rightChildIndex] ? rightChildIndex :leftChildIndex; } }else if(leftChildIndex<=lastIndex){ //只存在左子节点 if(array[leftChildIndex]>array[rootIndex]){ //左子节点更大 biggerIndex = leftChildIndex; } } if(biggerIndex != rootIndex){ //找到了比根更大的子节点 swap(rootIndex,biggerIndex); //交换位置后可能会破坏子树,将焦点转向交换了位置的子节点,调整以它为根的子树 adjustHeap(biggerIndex,lastIndex); } } /** * 将数组按照完全二叉树的形式打印出来 */ private static void printTree(int len){ int layers = (int)Math.floor(Math.log((double)len)/Math.log((double)2))+1; //树的层数 int maxWidth = (int)Math.pow(2,layers)-1; //树的最大宽度 int endSpacing = maxWidth; int spacing; int numberOfThisLayer; for(int i=1;i<=layers;i++){ //从第一层开始,逐层打印 endSpacing = endSpacing/2; //每层打印之前需要打印的空格数 spacing = 2*endSpacing+1; //元素之间应该打印的空格数 numberOfThisLayer = (int)Math.pow(2, i-1); //该层要打印的元素总数 int j; for(j=0;j<endSpacing;j++){ System.out.print(" "); } int beginIndex = (int)Math.pow(2,i-1)-1; //该层第一个元素对应的数组下标 for(j=1;j<=numberOfThisLayer;j++){ System.out.print(array[beginIndex++]+""); for(int k=0;k<spacing;k++){ //打印元素之间的空格 System.out.print(" "); } if(beginIndex == len){ //已打印到最后一个元素 break; } } System.out.println(); } System.out.println(); } private static void swap(int low,int high){ int temp = array[high]; array[high] = array[low]; array[low] = temp; } }

[7, 8, 9, 6, 1, 4, 3, 2, 5, 0, -1, -2, 10, -3] 建堆: 10 8 9 6 1 7 3 2 5 0 -1 -2 4 -3 调整堆: 9 8 7 6 1 4 3 2 5 0 -1 -2 -3 调整堆: 8 6 7 5 1 4 3 2 -3 0 -1 -2 调整堆: 7 6 4 5 1 -2 3 2 -3 0 -1 调整堆: 6 5 4 2 1 -2 3 -1 -3 0 调整堆: 5 2 4 0 1 -2 3 -1 -3 调整堆: 4 2 3 0 1 -2 -3 -1 调整堆: 3 2 -1 0 1 -2 -3 调整堆: 2 1 -1 0 -3 -2 调整堆: 1 0 -1 -2 -3 调整堆: 0 -2 -1 -3 调整堆: -1 -2 -3 调整堆: -2 -3 [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
堆排序的特性:
一个长度为n的数组,可以看成是一个array[0,......,n-1]的完全二叉树。
子节点索引为n-1的二叉树,其父节点的索引为(n-2)/2。
父节点索引为i的二叉树,其子节点的索引分别为2*i+1和2*i+2。
模板:
import java.util.Arrays; public class Main { static int[] array = {7, 8, 9, 6, 1, 4, 3, 2, 5, 0, -1, -2,10,-3}; public static void main(String[] args) throws InterruptedException { System.out.println(Arrays.toString(array)); heapSort(array); System.out.println(Arrays.toString(array)); } //堆排序 public static int[] heapSort(int[] array){ array = buildMaxHeap(array); //初始建堆,array[0]为第一趟值最大的元素 for(int i=array.length-1;i>1;i--){ int temp = array[0]; //将堆顶元素和堆低元素交换,即得到当前最大元素正确的排序位置 array[0] = array[i]; array[i] = temp; adjustDownToUp(array, 0,i); //整理,将剩余的元素整理成堆 } return array; } //构建大根堆:将array看成完全二叉树的顺序存储结构 private static int[] buildMaxHeap(int[] array){ //从最后一个节点array.length-1的父节点(array.length-1-1)/2开始,直到根节点0,反复调整堆 for(int i=(array.length-2)/2;i>=0;i--){ adjustDownToUp(array, i,array.length); } return array; } //将元素array[k]自下往上逐步调整树形结构 private static void adjustDownToUp(int[] array,int k,int length){ int temp = array[k]; for(int i=2*k+1; i<length-1; i=2*i+1){ //i为初始化为节点k的左孩子,沿节点较大的子节点向下调整(即选择节点i中较大的子节点的左孩子为新的i,有点绕) if(i<length && array[i]<array[i+1]){ //取节点较大的子节点的下标 i++; //如果节点的右孩子>左孩子,则取右孩子节点的下标 } if(temp>=array[i]){ //根节点 >=左右子女中关键字较大者,调整结束 break; }else{ //根节点 <左右子女中关键字较大者 array[k] = array[i]; //将左右子结点中较大值array[i]调整到双亲节点上 k = i; //【关键】修改k值,以便继续向下调整 } } array[k] = temp; //被调整的结点的值放人最终位置 } }

[7, 8, 9, 6, 1, 4, 3, 2, 5, 0, -1, -2, 10, -3]
[-2, -3, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
看堆时,发现最大的k个数,肯定在堆的前k排,比如第二大的数,肯定在第二排,不是根节点的左孩子,就是根节点的右孩子,按这种方式,可以发现堆排序有很大的优化空间。
http://blog.csdn.net/u012152619/article/details/47306053
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2013-12-13 JavaScript:Function/Object/prototype/__proto__