数据结构-最大堆最小堆手动实现

Posted mufasa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构-最大堆最小堆手动实现相关的知识,希望对你有一定的参考价值。

0,堆的简介

  数据结构中的堆是一种特殊的二叉树,不同于 Java 内存模型中的堆。

  堆必须符合以下两个条件:

  1. 是一棵完全二叉树。
  2. 任意一个节点的值都大于(或小于)左右子节点的值。

  从第一点可以知道,堆适合用数组来存储。

  第二点中,若父节点都大于等于左右子节点,则被称为大顶堆,反之则为小顶堆

技术图片

图-最大堆及其存储方式

  0.1节点的父、子节点关系

  一个节点【根节点除外】的父节点地址为其地址的二分之一,它的左子节点地址为其地址值的2倍,右子节点地址为其地址2倍加1。

   例如:现在有个节点的地址为3,其数值为5;那么它的父节点地址为3/2=1,父节点的数值为13;左子节点地址为3*2=6,左子节点数值为6;右子节点地址为3*2+1=7,这个最大堆中没有其右节点数据。

  0.2节点的存储、删除操作

  添加新元素的时候,一般先存放到数组的尾部,之后在通过向上重排序的操作,来进行堆化【满足堆数据结构的调整】

  删除元素时【一般默认删除第一个根节点】,现将数组的最后一个元素放到根节点的位置,之后通过向下重排序的操作,来进行堆化处理。

  

1,堆的实现

   主要实现功能:①添加元素-add();②输出极值并清除-poll();③输出极值不清除-peek();

  上面的功能都是是显示的函数,隐形函数有:①扩容dilatate();②向上重排序reSortUp();③向下重排序reSortDown();

package com.cnblogs.mufasa.Solution1;

public class Heap 
    private static final int CAPACITY=16;
    private static final boolean TYPE=true;

    private static int[] nums;
    private int capacity=16;
    int size=0;

    private boolean type=true;//true由小到大,false由大到小
    public Heap()
        this(CAPACITY);
    

    public Heap(int capacity)
        this(capacity,TYPE);
    

    public Heap(boolean type)
        this(CAPACITY,type);
    

    public Heap(int capacity,boolean type)
        this.capacity=capacity;
        this.type=type;
        nums=new int[capacity];
    


    //数据添加
    public void add(int num)
        if(size+1>=capacity)
            dilatate();
        
        nums[size+1]=num;
        reSortUp(size+1);
        size++;
    

    private void reSortUp(int index)
        if(type)//由小到大
            while (index!=1)
                if(nums[index/2]>nums[index])
                    int temp=nums[index];
                    nums[index]=nums[index/2];
                    nums[index/2]=temp;
                    index/=2;
                else if(nums[index/2]==nums[index])
//                    throw new IllegalArgumentException("数据结构-堆不接受重复数据输入");
                    break;
                else 
                    return;
                
            
        else //由大到小
            while (index!=1)
                if(nums[index/2]<nums[index])
                    int temp=nums[index];
                    nums[index]=nums[index/2];
                    nums[index/2]=temp;
                    index/=2;
                else if(nums[index/2]==nums[index])
//                    throw new IllegalArgumentException("数据结构-堆不接受重复数据输入");
                    break;
                else 
                    return;
                
            
        
    

    //数据输出,并且清楚该数据
    public int poll() throws Exception 
        if(size>0)
            int temp=nums[1];
            nums[1]=nums[size];
            reSortDown();
            size--;
            return temp;
        else 
            throw new Exception("数据为空");
        
    

    private void reSortDown()
        int index=1;
        int L,R;
        if(type)//由小到大
            while (index<size)
                L=index*2;
                R=L+1;
                if(R<=size)
                    boolean flag=nums[L]<nums[R];
                    int min=(flag?nums[L]:nums[R]);
                    if(nums[index]>min)
                        if(flag)
                            int temp=nums[index];
                            nums[index]=nums[L];
                            nums[L]=temp;
                            index=L;
                        else 
                            int temp=nums[index];
                            nums[index]=nums[R];
                            nums[R]=temp;
                            index=R;
                        
                    else 
                        return;
                    
                else if(L<=size)
                    if(nums[index]>nums[L])
                        int temp=nums[index];
                        nums[index]=nums[L];
                        nums[L]=temp;
                    
                    return;
                else 
                    return;
                
            
        else //由大到小
            while (index<size)
                L=index*2;
                R=L+1;
                if(R<size)
                    boolean flag=nums[L]<nums[R];
                    int max=(flag?nums[R]:nums[L]);
                    if(nums[index]<max)
                        if(flag)
                            int temp=nums[index];
                            nums[index]=nums[R];
                            nums[R]=temp;
                            index=R;
                        else 
                            int temp=nums[index];
                            nums[index]=nums[L];
                            nums[L]=temp;
                            index=L;
                        
                    else 
                        return;
                    
                else if(L<size)
                    if(nums[index]<nums[L])
                        int temp=nums[index];
                        nums[index]=nums[L];
                        nums[L]=temp;
                    
                    return;
                else 
                    return;
                
            
        
    

    //数据输出,不清除该数据
    public int peek() throws Exception 
        if(size>0)
            return nums[0];
        else 
            throw new Exception("数据为空");
        
    

    //数据扩容,二倍扩容
    private void dilatate()
        capacity=capacity<<1;
        int[] pre=new int[capacity];
        for(int i=1;i<=size;i++)
            pre[i]=nums[i];
        
        nums=pre;
    



class Client
    public static void main(String[] args) throws Exception 
        Heap heap=new Heap(4,true);
//        Heap heap=new Heap(4,false);
        heap.add(5);
        heap.add(3);
        heap.add(3);
        heap.add(7);
        heap.add(1);
        heap.add(0);
        heap.add(8);
        heap.add(8);

        int len=heap.size;
        for(int i=0;i<len;i++)
            System.out.print(heap.poll()+",");
        
    

/*
0,1,3,5,7,8,
8,7,5,3,1,0,
 */

 

2,堆的应用

  3.1 堆排序

  利用堆这种数据结构,来进行数组排序,时间复杂度为O(nlogn)

  3.2 Java容器中的优先队列

  PriorityQueue<Integer> queue=new PriorityQueue<Integer>();

  3.3 求动态集合中位数

  有若干个数据,求其中位数,并且数据还在不断的输入【两个堆数据即可很好的解决问题,一个最大堆,一个最小堆】

技术图片

  3.4 60百分位的数

  这个问题是上面的问题的扩展,本质上也是使用两个对数据结构即可。但是需要控制两个堆中元素个数的比例!

 

以上是关于数据结构-最大堆最小堆手动实现的主要内容,如果未能解决你的问题,请参考以下文章

SPL数据结构2-Heap,最大堆,最小堆

堆排序 最大堆 最小堆 Java实现

数据结构:堆排序

挑战程序设计竞赛(算法和数据结构)——10.3最大堆(最小堆)的JAVA实现

数据结构:堆(Heap)

Java实现堆(最大堆,最小堆)