• 算法


    要点:将数组作为堆结构,利用大根堆根最大的性质,构建完就将根与未排序部分的末尾交换,逐步实现有序。

      1 import java.util.Random;
      2 
      3 public class HeapSort<T extends Comparable> {
      4 
      5     public void sort(T[] arr) {
      6         printArr(arr, " => 初始数组");
      7         for (int i = arr.length - 1; i > 0; i--) {
      8             // 构建大跟堆
      9             buildHeap(arr, 0, i);
     10             printArr(arr, " => 构建大根堆");
     11             // 最大值依次往后放,进行排序
     12             swap(arr, 0, i);
     13             printSign(0, i);
     14         }
     15     }
     16 
     17     /**
     18      * 从上向下构建大根堆
     19      * 很多大跟堆是从下向上构建的
     20      *
     21      * @param arr 原数组
     22      * @param rootIndex 根坐标
     23      * @param end 堆大小
     24      */
     25     private void buildHeap(T[] arr, int rootIndex, int end) {
     26         // 左子节点
     27         int leftChildIndex = rootIndex * 2 + 1;
     28         // 如果左子节点超出堆的大小就退出
     29         if (leftChildIndex > end) {
     30             return;
     31         }
     32         // 如果根比左子节点小就交换
     33         if (arr[rootIndex].compareTo(arr[leftChildIndex]) < 0) {
     34             swap(arr, rootIndex, leftChildIndex);
     35             // 交换可能会出现规则破坏,回溯一下
     36             backCheck(arr, rootIndex);
     37         }
     38         // 继续构建堆
     39         buildHeap(arr, leftChildIndex, end);
     40         // 右子节点
     41         int rightChildIndex = rootIndex * 2 + 2;
     42         // 如果右子节点超出堆的大小就退出
     43         if (rightChildIndex > end) {
     44             return;
     45         }
     46         // 如果根比右子节点大就交换
     47         if (arr[rootIndex].compareTo(arr[rightChildIndex]) < 0) {
     48             swap(arr, rootIndex, rightChildIndex);
     49             backCheck(arr, rootIndex);
     50         }
     51         // 继续构建堆
     52         buildHeap(arr, rightChildIndex, end);
     53     }
     54 
     55     /**
     56      * 向上追溯,查看是否乱序
     57      * 例:                                     树的坐标规律
     58      * 0,1,2,3,4 => 坐标                            0
     59      * 3,6,7,9,8 => 开始构建大跟堆                   1 2
     60      * 3,6       => 发现6比3大交换                  34 56
     61      * 6,3,9     => 发现9比3大交换
     62      * 6,9,3     => 如果在这里不追溯的话,就会出现不符合大跟堆规律的情况
     63      * 9,6,3     => 追溯发现根节点的父节点比根小,就交换,继续追溯,发现坐标已经为0了,就停下
     64      *
     65      * @param arr       数组
     66      * @param rootIndex 根坐标
     67      */
     68     private void backCheck(T[] arr, int rootIndex) {
     69         if (rootIndex == 0) {
     70             return;
     71         }
     72         int fatherIndex = (rootIndex - 1) / 2;
     73         if (arr[fatherIndex].compareTo(arr[rootIndex]) < 0) {
     74             swap(arr, fatherIndex, rootIndex);
     75         }
     76         backCheck(arr, fatherIndex);
     77     }
     78 
     79     private void swap(T[] arr, int a, int b) {
     80         T temp = arr[a];
     81         arr[a] = arr[b];
     82         arr[b] = temp;
     83     }
     84 
     85     private void printSign(int a, int b) {
     86         String[] arr = new String[]{" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "};
     87         arr[a] = "^";
     88         arr[b] = "^";
     89         for (String n : arr) {
     90             System.out.print(n);
     91         }
     92         System.out.println(" => 交换");
     93     }
     94 
     95     public void printArr(T[] arr, String message) {
     96         for (T n : arr) {
     97             System.out.print(n);
     98         }
     99         System.out.print(message);
    100         System.out.println();
    101     }
    102 
    103     public static void main(String[] args) {
    104         int n = 11;
    105         Integer[] arr = new Integer[n];
    106         for (int i = 0; i < n; i++) {
    107             arr[i] = new Random().nextInt(10);
    108         }
    109         HeapSort hs = new HeapSort();
    110         hs.sort(arr);
    111     }
    112 
    113     /**
    114      * 92134594608 => 初始数组
    115      * 98946152304 => 构建大根堆
    116      * ^         ^ => 交换
    117      * 96844152309 => 构建大根堆
    118      * ^        ^  => 交换
    119      * 84634150299 => 构建大根堆
    120      * ^       ^   => 交换
    121      * 64523140899 => 构建大根堆
    122      * ^      ^    => 交换
    123      * 53402146899 => 构建大根堆
    124      * ^     ^     => 交换
    125      * 43402156899 => 构建大根堆
    126      * ^    ^      => 交换
    127      * 42301456899 => 构建大根堆
    128      * ^   ^       => 交换
    129      * 31204456899 => 构建大根堆
    130      * ^  ^        => 交换
    131      * 20134456899 => 构建大根堆
    132      * ^ ^         => 交换
    133      * 10234456899 => 构建大根堆
    134      * ^^          => 交换
    135      *
    136      * => 遍历次数:log(n) + log(n-1) + log(n-2) + ... + log(1)
    137      * => 时间复杂度:O(nlogn)
    138      * => 稳定性:不稳定
    139      *
    140      * 例:
    141      * 0,1,2,3,5 => 坐标
    142      * 7,1,3,3,2 => 原数组
    143      * 7,1,3     => 3比1大交换
    144      * 7,3,3,1,2 => 交换后的数组 => 3的顺序发生改变,因此不稳定
    145      */
    146 
    147 }
  • 相关阅读:
    Spring RestTemplate详解(转载)
    单点登录之CAS原理和实现(转载)
    Redis集群的原理和搭建(转载)
    50道Kafka面试题和解析(转载)
    阿里P8架构师谈:Restful、SOAP、RPC、SOA、微服务之间的区别(转载)
    定期喝鸡汤
    Cassandra的架构
    Cassandra的数据模型
    Summary of OAuth 2.0
    林森
  • 原文地址:https://www.cnblogs.com/SamNicole1809/p/12803783.html
Copyright © 2020-2023  润新知