堆排序及修改选择排序
选择排序(修改):
针对上篇博客中选着排序的错误进行修改
/** * @author Red Ants * 微信公众号:程序员之路 * 选择排序 */ public class SelectionSort { //为了寻找每次排序中的最小值直接进行的位置交换,既耗时又占用内存 public static int[] selectionSort(int[] ints){ int temp; int runNum = 0; for (int i = 0; i < ints.length; i++) { for (int j = i+1; j < ints.length; j++) { if(ints[j]<ints[i]){ temp = ints[i]; ints[i] = ints[j]; ints[j] = temp; } runNum++; } } System.out.println(String.format("运行次数:%d", runNum)); return ints; } //修改后 //寻找每次排序中的最小值,获取最小者的下标然后用找到下标值的与每次排序的第一个位置值进行交换 public static int[] selectionSort1(int[] ints){ int temp; for (int i = 0; i < ints.length; i++) { int minNum = ints[i]; int currIndex = i; for (int j = i+1; j < ints.length; j++) { if(ints[j]<minNum){ minNum = ints[j]; currIndex = j; } } temp = ints[i]; ints[i] = ints[currIndex]; ints[currIndex] = temp; } return ints; } public static void main(String[] args) { int[] ints = new int[]{8,4,9,13,11,99,2,1,5,3,6}; selectionSort1(ints); System.out.println(Arrays.toString(ints)); } }
堆排序:
堆排序重点就是构建堆结构,堆结构可以看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(最小)的元素。
对完全二叉树不太理解的自己私下补知识点了!
完全二叉树的节点特点:
任意一节点指针 i:父节点:i==0 ? null : (i-1)/2
左孩子:2*i + 1
右孩子:2*i + 2
白话点:
- 所有有子节点的节点:(树节点数-1)/2
- 节点是否有左子节点: 2*节点下标+1 < 树节点数
- 节点是否有右子节点: 左子节点 < 树节点数
/** * @author Red Ants(guangboyuan.cn) * 微信公众号:程序员之路 堆排序 * 1.构建堆结构 (大根堆) * 2.取出最大值,将最小值移动到根位置 * 3.多次循环1,2步,直到全部排序完成 */ public class HeapSort { public static void main(String[] args) { int[] data5 = new int[] { 21, 1, 12, 3, 7, 66, 34, 88, 11 ,11}; print(data5); bigHeapSort(data5); System.out.println("排序后的数组:"); print(data5); } //交换 private static void swap(int[] data, int i, int j) { if(i == j){ return; } int tmp=data[i]; data[i]=data[j]; data[j]=tmp; } public static void bigHeapSort(int[] data) { for (int i = 0; i < data.length; i++) { createMaxdHeap(data, data.length - 1 - i); //构建完成大根堆结构后,收尾节点进行交换 swap(data, 0, data.length - 1 - i); print(data); } } public static void createMaxdHeap(int[] data, int lastIndex) { for (int i = (lastIndex - 1) / 2; i >= 0; i--) {//遍历完全二叉树中所有有子节点的节点 // 保存当前正在判断的节点 int k = i; // 若当前节点的子节点存在 while (2 * k + 1 <= lastIndex) {//判断当前节点是否有子节点 // biggerIndex总是记录较大节点的值,先赋值为当前判断节点的左子节点 int biggerIndex = 2 * k + 1; if (biggerIndex < lastIndex) {//判断是否有右子节点 // 若右子节点存在,否则此时biggerIndex应该等于 lastIndex if (data[biggerIndex] < data[biggerIndex + 1]) { // 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的值 biggerIndex++; } } if (data[k] < data[biggerIndex]) {//节点和最大子节点比较大小 // 若当前节点值比子节点最大值小,则交换2者得值,交换后将biggerIndex值赋值给k swap(data, k, biggerIndex); k = biggerIndex; } else { break; } } } } public static void print(int[] data) { for (int i = 0; i < data.length; i++) { System.out.print(data[i] + "\t"); } System.out.println(); } }