【数据结构和算法】--二叉堆(大顶堆和小顶堆)

一、二叉堆介绍

二叉堆总是一颗完全二叉树;堆的某个节点的值总是不大于或不小于其节点的值。
按照数据的排列方式可以分为两种:最大堆最小堆
最大堆(大顶堆):父结点的键值总是大于或等于任何一个子节点的键值;
最小堆(小顶堆):父结点的键值总是小于或等于任何一个子节点的键值。
----------------【一般堆用于查找、删除、插入操作。完成二叉树是从上到下,都是按照节点拥有度为2的思想添加子节点。因此实际二叉堆加入一个元素,需要时刻调整来保证满足上面的性质。

二叉堆数据结构
使用链表List即可。

二叉堆添加过程思路
数据先放在末尾,然后和其父节点进行比较,以便交换,直到不能交换。

二叉堆删除过程思路
先找到要删除的节点,然后该节点和末尾节点交换【这样删除的节点自动没了】,然后比较交换的节点的两个子节点,按照二叉堆性质进行挪动,直到不能挪动。

二、最大堆

1、添加/删除过程图解

添加元素
在这里插入图片描述

删除元素
在这里插入图片描述

2、最大堆代码实现

满足具体业务的数据对象

public class HeapStructure<T extends Comparable<T>> {
    /**
     *  标识
     */
    private String id;
    /**
     * 具体数据
     */
    private T data;
    public HeapStructure(String id,T data){
        this.id = id;
        this.data = data;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
}

最大堆方法

public class MaxHeap {
    private List<HeapStructure> maxHeapList;
    public MaxHeap(){
        maxHeapList = new ArrayList<>();
    }
    /**
     * 堆大小
     */
    public int size(){
        return maxHeapList.size();
    }
    /**
     * 查询
     */
    public HeapStructure getByIndex(int index){
        return maxHeapList.get(index);
    }
    /**
     * 返回结果
     */
    public List<HeapStructure> getMaxHeapList(){
        return maxHeapList;
    }
    /**
     * 正常添加在list后面,然后和对应父节点进行比较,调整位置
     */
    public void insert(HeapStructure e){
         int oldSize = maxHeapList.size();
         maxHeapList.add(e);
         //向上调整 【由于是从后添加,所以是向上调整】
        filterup(oldSize);
    }

    /**
     * 向上调整
     */
    private void filterup(int start){
        int c = start;
        int p = (c - 1) >> 1;

        while (c > 0){//从第二个节点开始调整
            if(maxHeapList.get(c).getData().compareTo(maxHeapList.get(p).getData()) > 0){
                //需要调整
                HeapStructure temp = maxHeapList.get(p);
                maxHeapList.set(p,maxHeapList.get(c));
                maxHeapList.set(c,temp);
                c = p;
                p = (c - 1) >> 1;
            }else
                break;
        }
    }

    /**
     * start是开始调整位置,end是最终位置
     */
    private void filterDown(int start,int end){
        int c = start;
        int lfIndex = (c << 1) + 1;
        HeapStructure cData = maxHeapList.get(c);
        //虽然新替换的值比原值小,但都比左右节点数据大
        if(cData.getData().compareTo(maxHeapList.get(lfIndex).getData()) >= 0
                && cData.getData().compareTo(maxHeapList.get(lfIndex+1).getData()) >= 0){
           return;
        }
        while (lfIndex <= end){
            //只有左节点,直接比较后是否交换,退出
            if(lfIndex == end){
                if(maxHeapList.get(c).getData().compareTo(maxHeapList.get(lfIndex)) < 0){
                    maxHeapList.set(c,maxHeapList.get(lfIndex));
                    c = lfIndex;
                }
                break;
            }
           //左右节点找到最大的
            if(maxHeapList.get(lfIndex).getData().compareTo(maxHeapList.get(lfIndex+1).getData()) < 0){
                lfIndex ++;
            }
            if(cData.getData().compareTo(maxHeapList.get(lfIndex).getData()) >= 0){
                break;
            }
            //将大的值上移原本替换位置
            maxHeapList.set(c,maxHeapList.get(lfIndex));
            c = lfIndex;
            lfIndex = (c << 1) + 1;
        }
        //最终找到位置
        maxHeapList.set(c,cData);
    }

    /**
     * 找到对应的位置
     */
    private int indexOf(HeapStructure e){
        //根据id去匹配找到对应数据
        int i = -1;
        for (HeapStructure temp : maxHeapList){
            ++i;
            if(e.getId().equals(temp.getId())){
                return i;
            }
        }
        return -1;
    }

    /**
     * 删除节点
     */
    private int remove(HeapStructure e){

        if(maxHeapList.isEmpty()){
            return -1;
        }

        //找到要删除元素位置,和末尾元素交互
        // 如果“替换后元素”比之前元素大,那么一定大于左右子节点;只需要往上调整
        // 如果“替换后元素”比之前元素小,那么需要往下调整
        int endIndex = maxHeapList.size();
        int index = indexOf(e);
        HeapStructure replaceDta = maxHeapList.get(endIndex - 1);
        maxHeapList.set(index,replaceDta);
        maxHeapList.remove(endIndex - 1);
        if(maxHeapList.size() > 0){
            if(replaceDta.getData().compareTo(e.getData()) > 0){
                filterup(index);
            }else
                filterDown(index,maxHeapList.size() - 1);
        }
        return 1;
    }
    /*
   * 替换节点
   /
    public void replace(HeapStructure data){
        maxHeapList.set(0,data);
        if (maxHeapList.size() > 1)
            filterDown(0, maxHeapList.size()-1);
    }

    public static void main(String[] args) {
        int a[] = {90, 80, 30, 75, 50, 25, 29, 60, 62,49,20,24,23,27,26,61};

        MaxHeap maxHeap = new MaxHeap();
        for(int i=0; i<a.length; i++) {
            HeapStructure heapData = new HeapStructure(String.valueOf(i),a[i]);
            maxHeap.insert(heapData);
        }
        HeapStructure heapData = new HeapStructure("2",30);
        maxHeap.remove(heapData);
    }
}

3、应用场景

1、随机输入n个元素【无限大,不知道界限】,只获取前m个最小值元素

可以使用最大堆实现。最大堆的思想是:所有的子节点都要比父节点大于或等于。所以在插入数据时,保证list.get(0)是当前最大堆的最大元素,如果新数据进人,先和list.get(0)比较,比该值大,那么直接抛弃,如果比该值小,那么直接替换list(0)位置的元素,然后向下调整机制。

public class MaxHeapExample1 {
    //最大堆
    private MaxHeap maxHeap;
    //最大容量限制
    private int capacity;

    public MaxHeapExample1(int capacity){
        maxHeap = new MaxHeap();
        this.capacity = capacity;
    }
    //添加
    public boolean insert(HeapStructure e){
        if(capacity <= 0){
            return false;
        }
        if(maxHeap.size() < capacity){
            maxHeap.insert(e);
            return true;
        }
        //新值和min比较 【第一个位置元素】
        HeapStructure currentMin = maxHeap.getByIndex(0);
        if(currentMin.getData().compareTo(e.getData()) > 0){
            //替换新值
            maxHeap.replace(e);
        }
        return true;
    }

    public static void main(String[] args) {
        int a[] = {80, 40, 90, 60, 90, 54,75,71,83,70,70, 10, 50, 20};
        MaxHeapExample1 tree = new MaxHeapExample1(5);
        for(int i=0; i<a.length; i++) {
            HeapStructure temp = new HeapStructure(String.valueOf(i),a[i]);
            tree.insert(temp);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DreamBoy_W.W.Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值