数据结构--堆排序

        堆是一种特殊的完全二叉树,满足每一个结点的值比左右子树的所有结点都大(大顶堆)/小(小顶堆)。由于是完全二叉树,我们不需要用借助指针来存储树,用一个数组即可。

         如 a = [1,2,3,4,5,6]表示的树:

         a[i] 的左节点为 a[2*i+1],右结点为 a[2*i+2]。所以对一个数组使用堆排序在原数组上进行就可以了。

import java.util.Arrays;

public class HeapSort {

    public static void main(String[] args) {
        int[] a = {2,3,1,5,4,6,9,8};
        HeapSort hs = new HeapSort();
        hs.heapSort(a);
        System.out.println(Arrays.toString(a));
    }

    public void heapSort(int[] a) { 
        int len = a.length;
        for(int i = len/2;i >= 0;i--) {     //i初始指向倒数第二层的最右结点,对每个结点依次进行调整,构造大顶堆
            adjust(a,i,len);
        }
        for(int i = len-1; i > 0;i--) {   //构造出大顶堆后,把堆顶(最大值)与堆尾(数组末尾)元素交换,即把最大值放到数组末尾。然后再构建一次
            swap(a,0,i);
            adjust(a,0,i);  // 每交换一次,就需要调整一次。并堆长度置为i,大于i的下标的元素将不会被作为堆中元素参与调整,不然又乱了
        }
    }

    public  void adjust(int[] a,int i,int len) {  //i表示从哪个结点开始调整,len表示堆的长度,即还没排好的那段数组元素
        int temp = a[i];
        for(int k = 2*i+1;k < len;k = 2*k+1) {    //k指向i的子结点,并且小于堆长度
            if(k+1 < len && a[k] < a[k+1]) {
                k++;                      // k 指向 i 的子结点中最大的那个
            }
            if(a[k] > temp) {        //如果最大的子结点 i 比自身大,则更新i结点的值
                a[i] = a[k];
                i = k;      //i 指向 与自己做了交换的子结点的原位置,即下移一层,为下一次循环比较做准备。i变成新的父结点
            }
            else
                break;       //若子结点没有比自己大的说明此父结点已经满足大顶堆,无需调整

             a[i] = temp;    //若确实更新了父结点,i已经指向了下一层子结点,则需要交换,把子结点值更新为父结点的值
        }
    }

    public void swap(int[] a,int i,int j) {  //交换堆顶堆尾
        a[i] = a[i] + a[j];
        a[j] = a[i] - a[j];
        a[i] = a[i] - a[j];
    }
}
原文地址:https://www.cnblogs.com/shen-qian/p/11431193.html