二叉堆

作者: 一个人的飘 | 来源:发表于2018-09-24 22:41 被阅读0次

    二叉堆是一颗完全二叉树(除了最后一层其与节点的子节点都是最大值)

    最大堆,结点越上,越大(二叉堆)

    最小堆,节点越上,越大。

    用数组存储二叉堆

    shiftup

    插入元素,先与i/2(父节点)比,如果父节点小,则调换位置,再与i/2/2(父亲的父亲)比,一直>0(跟节点)比,大于则交换位置。

    shiftdown

    从堆中取出一个元素,取出跟节点元素,将最后一个元素放到第一个元素的位置,数组容量-1,根节点和子节点比较,较大的与根节点调换位置,一直换下去,直到i=i*2>容量为止。


    package bobo.algo;

    import java.util.*;

    import java.lang.*;

    // 在堆的有关操作中,需要比较堆中元素的大小,所以Item需要extends Comparable

    public class MaxHeap {

    protected Item[] data;

        protected int count;

        protected int capacity;

        // 构造函数, 构造一个空堆, 可容纳capacity个元素

        public MaxHeap(int capacity){

    data = (Item[])new Comparable[capacity+1];

            count =0;

            this.capacity = capacity;

        }

    // 返回堆中的元素个数

        public int size(){

    return count;

        }

    // 返回一个布尔值, 表示堆中是否为空

        public boolean isEmpty(){

    return count ==0;

        }

    // 像最大堆中插入一个新的元素item

        public void insert(Item item){

    assert count +1 <= capacity;

            data[count+1] = item;

            count ++;

            shiftUp(count);

        }

    // 从最大堆中取出堆顶元素, 即堆中所存储的最大数据

        public Item extractMax(){

    assert count >0;

            Item ret = data[1];

            swap(1 , count );

            count --;

            shiftDown(1);

            return ret;

        }

    // 获取最大堆中的堆顶元素

        public Item getMax(){

    assert( count >0 );

            return data[1];

        }

    // 交换堆中索引为i和j的两个元素

        private void swap(int i, int j){

    Item t = data[i];

            data[i] = data[j];

            data[j] = t;

        }

    //********************

        //* 最大堆核心辅助函数

        //********************

        private void shiftUp(int k){

    while( k >1 && data[k/2].compareTo(data[k]) <0 ){

    swap(k, k/2);

                k /=2;

            }

    }

    private void shiftDown(int k){

    while(2*k <= count ){

    int j =2*k; // 在此轮循环中,data[k]和data[j]交换位置

                if( j+1 <= count && data[j+1].compareTo(data[j]) >0 )

    j ++;

                // data[j] 是 data[2*k]和data[2*k+1]中的最大值

                if( data[k].compareTo(data[j]) >=0 )break;

                swap(k, j);

                k = j;

            }

    }

    // 测试MaxHeap

        public static void main(String[] args) {

    MaxHeap maxHeap =new MaxHeap(100);

            int N =100; // 堆中元素个数

            int M =100; // 堆中元素取值范围[0, M)

            for(int i =0 ; i < N; i ++ )

    maxHeap.insert(new Integer((int)(Math.random() * M)) );

            Integer[] arr =new Integer[N];

            // 将maxheap中的数据逐渐使用extractMax取出来

            // 取出来的顺序应该是按照从大到小的顺序取出来的

            for(int i =0 ; i < N; i ++ ){

    arr[i] = maxHeap.extractMax();

                System.out.print(arr[i] +" ");

            }

    System.out.println();

            // 确保arr数组是从大到小排列的

            for(int i =1 ; i < N; i ++ )

    assert arr[i-1] >= arr[i];

        }

    }


    堆排序:

    生成一个数组(大小+1),将原数组的每一个元素用insert插入,即完成了排序,再用extractMax();取出即可

    public static void sort(Comparable[] arr){

    int n = arr.length;

        MaxHeap maxHeap =new MaxHeap(n);

        for(int i =0 ; i < n; i ++ )

    maxHeap.insert(arr[i]);

        for(int i = n-1 ; i >=0 ; i -- )

    arr[i] = maxHeap.extractMax();

    }

    堆排序的时间复杂度为nlogn


    第二种堆排序算法

    完全二叉树的第一个非叶子节点=节点数/2

    将所有非叶子节点进行shiftdown即可

    public MaxHeap(Item arr[]){

    int n = arr.length;

        data = (Item[])new Comparable[n+1];

        capacity = n;

        for(int i =0 ; i < n; i ++ )

    data[i+1] = arr[i];

        count = n;

        for(int i = count/2 ; i >=1 ; i -- )

    shiftDown(i);

    }

    public static void sort(Comparable[] arr){

    int n = arr.length;

        MaxHeap maxHeap =new MaxHeap(arr);

        for(int i = n-1 ; i >=0 ; i -- )

    arr[i] = maxHeap.extractMax();

    }

    这一种堆排序比上一种堆排序更快一点,但是堆排序还是比归并排序要慢。


    如果交换的时间耗时过长可以使用索引堆,只是交换索引即可

    相关文章

      网友评论

        本文标题:二叉堆

        本文链接:https://www.haomeiwen.com/subject/bauhoftx.html