數據結構-最大堆、最小堆【手動實現】

0,堆的簡介

  數據結構中的堆是一種特殊的二叉樹,不一樣於 Java 內存模型中的堆。數組

  堆必須符合如下兩個條件:數據結構

  1. 是一棵徹底二叉樹。
  2. 任意一個節點的值都大於(或小於)左右子節點的值。

  從第一點能夠知道,堆適合用數組來存儲。函數

  第二點中,若父節點都大於等於左右子節點,則被稱爲大頂堆,反之則爲小頂堆this

圖-最大堆及其存儲方式spa

  0.1節點的父、子節點關係

  一個節點【根節點除外】的父節點地址爲其地址的二分之一,它的左子節點地址爲其地址值的2倍,右子節點地址爲其地址2倍加1。code

   例如:如今有個節點的地址爲3,其數值爲5;那麼它的父節點地址爲3/2=1,父節點的數值爲13;左子節點地址爲3*2=6,左子節點數值爲6;右子節點地址爲3*2+1=7,這個最大堆中沒有其右節點數據。blog

  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百分位的數

  這個問題是上面的問題的擴展,本質上也是使用兩個對數據結構便可。可是須要控制兩個堆中元素個數的比例!

相關文章
相關標籤/搜索