• 算法


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

      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 }
  • 相关阅读:
    HDU 2089 不要62
    HDU 5038 Grade(分级)
    FZU 2105 Digits Count(位数计算)
    FZU 2218 Simple String Problem(简单字符串问题)
    FZU 2221 RunningMan(跑男)
    FZU 2216 The Longest Straight(最长直道)
    FZU 2212 Super Mobile Charger(超级充电宝)
    FZU 2219 StarCraft(星际争霸)
    FZU 2213 Common Tangents(公切线)
    FZU 2215 Simple Polynomial Problem(简单多项式问题)
  • 原文地址:https://www.cnblogs.com/SamNicole1809/p/12803783.html
Copyright © 2020-2023  润新知