数据结构学习之堆

1.1 堆的定义

**堆是计算机科学中一类特殊的数据结构的统称,堆通常可以被看做是一
棵完全二叉树的数组对象。**

堆的特性

1.它是完全二叉树,除了树的最后一层结点不需要是满的,其它的每一
层从左到右都是满的,如果最后一层结点不是满的,那么要求左满右不
满。
2.它通常用数组来实现。根结点在位置1,如果一个结点的位置为k则
它的父结点的位置为[k/2],而它的两个子结点的位置则分别为2k和
2k+1。
这样,在不使用指针的情况下,我们也可以通过计算数组的索引在树中
上下移动:从a[k]向上一层,就令k等于k/2,向下一层就令k等于2k或
2k+1。
3.每个结点都大于等于它的两个子结点。这里要注意堆中仅仅规定了
每个结点大于等于它的两个子结点,但这两个子结点的顺序并没有做
规定,跟我们之前学习的二叉查找树是有区别的。

堆的实现

public  class Heap<T extends Comparable<T>> {
        private T[] data;
        //堆中元素的个数
        private Integer N;

    public Heap(int capacity) {
        this.data = (T[]) new Comparable[capacity+1];
        this.N = 0;
    }
    //根据堆中元素的索引获得其左孩子节点的索引
    private int leftChild(int index) {
        return index * 2 + 1;
    }

    //根据堆中元素的索引获得其右孩子节点的索引
    private int rightChild(int index) {
        return index * 2 + 2;
    }
    //交换两个元素的值
    private void exch(int i,int j){
        T temp = data[i];
        data[i] = data[j];
        data[j] = temp;
    }
    private boolean less(int i,int j){
        return data[i].compareTo(data[j])<0;
    }
    //上浮算法
    private void siftUp(int k){
        //通过循环,不断的比较当前结点的值和其父结点的值,如果发现父结点的值比当前结点的值小,则交换位置
        while(k>1){
            //比较当前结点和其父结点

            if (less(k/2,k)){
                exch(k/2,k);
            }

            k = k/2;
        }
    }

    public void add(T e) {
        //总是直接插入到堆的末尾处
        data[++N]=e;
        //上浮算法进行排序
        siftUp(N);
    }

    public T delMax(){
        T max = data[1];
        //总是删除的是堆顶的数据
        if(N<= 0){
            return null;
        }

        //交换堆顶和最后一个的数据
        exch(1,N);
        data[N] = null;
        //下沉对堆顶
        N--;
        siftDown(1);
        //元素个数减1

        return max;
    }
    //下沉算法
    public void siftDown(Integer index){
        while (index*2<=N){
            int maxIndex;
            if (index*2+1>N){
                maxIndex = index*2;
            }else{
                //找到左右子节点的值最大的一个
                maxIndex = data[index*2].compareTo(data[index*2+1])<0?index*2+1:index*2;
            }
            if (data[index].compareTo(data[maxIndex])>0){
                break;
            }
            //交换最大索引处的值和当前索引
            exch(index,maxIndex);
            //
            index = maxIndex;
        }

    }

    public static void main(String[] args) {
        Heap<String> heap = new Heap<String>(9);
        heap.add("A");
        heap.add("B");
        heap.add("C");
        heap.add("D");
        heap.add("E");
        heap.add("F");
        heap.add("G");


        //通过循环从堆中删除数据
        String result = null;
        while((result = heap.delMax())!=null){
            System.out.print(result+" ");
        }
    }

思维导图

在这里插入图片描述这个导图,是根据自己的理解画的,所以里面的大白话比较多。

堆排序

实现步骤:
1.构造堆;
2.得到堆顶元素,这个值就是最大值;
3.交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到合适的位置;
4.对堆进行调整,重新让除了最后一个元素的剩余元素中的最大值放到堆顶;
5.重复2~4这个步骤,直到堆中剩一个元素为止。
堆的构造,最直观的想法就是另外再创建一个和新数组数组,然后从左往右遍历原数组,每得到一个元素后,添加
到新数组中,并通过上浮,对堆进行调整,最后新的数组就是一个堆。
上述的方式虽然很直观,也很简单,但是我们可以用更聪明一点的办法完成它。创建一个新数组,把原数组
0length-1的数据拷贝到新数组的1length处,再从新数组长度的一半处开始往1索引处扫描(从右往左),然后
对扫描到的每一个元素做下沉调整即可。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值