大頂堆和小頂堆-java

1、大頂堆和小頂堆的原理

一、大頂堆

  • 根結點(亦稱爲堆頂)的關鍵字是堆裏全部結點關鍵字中最大者,稱爲大頂堆。大根堆要求根節點的關鍵字既大於或等於左子樹的關鍵字值,又大於或等於右子樹的關鍵字值。

二、小頂堆

  • 根結點(亦稱爲堆頂)的關鍵字是堆裏全部結點關鍵字中最小者,稱爲小頂堆。小根堆要求根節點的關鍵字既小於或等於左子樹的關鍵字值,又小於或等於右子樹的關鍵字值。

三、大頂堆和小頂堆對比圖

四、大頂推和小頂堆的實現

public class MaxHeap {
    public static void main(String[] args) {
        //原始數組內容
        int i,size,data[]={0,5,6,10,8,3,2,19,9,11};

        size=data.length;

        System.out.print("原始數組:");

        for(i=1;i<size;i++)
            System.out.print("["+data[i]+"] ");

        System.out.println("");
        //創建堆積樹
        MaxHeap.heap(data,size);
    }
    public static void heap(int data[] ,int size)
    {
        int i,j,tmp;
        //創建堆積樹節點
        for(i=(size/2);i>0;i--)
            MaxHeap.ad_heap(data,i,size-1);
        System.out.print("\n堆積內容:");
        //原始堆積樹內容
        for(i=1;i<size;i++)
            System.out.print("["+data[i]+"] ");
    }

    public static void ad_heap(int data[],int i,int size){
        int j,tmp,post;
        j=2*i;
        tmp=data[i];
        post=0;
        while(j<=size && post==0)
        {
            if(j<size)
            {
                //小頂堆的比較           
                //if(data[j]>data[j+1])  
                //找出兩個子節點最大值
                if(data[j]<data[j+1])  
                    j++;
            }
            //小頂堆的比較
            //if(tmp<=data[j])   
            //若樹根較大,結束比較過程
            if(tmp>=data[j])    {
                post=1;  
            } else {
                //若樹根較小,則繼續比較,這裏將最大子節點賦值給父節點
                data[j/2]=data[j];     
                j=2*j;
            }
        }
        //指定樹根爲父節點
        data[j/2]=tmp;                
    }
}
複製代碼

2、小頂堆的應用

一、求最大的k個數

  • 一、求10億個數中的最大的前10個數,時時構建只有10個元素的小頂堆,若是比堆頂小,則不處理;若是比堆頂大,則替換堆頂,而後依次下沉到適當的位置。 詳細講解請看公衆號:碼農有道
  • 二、選擇最大的K個數
public class findTopK {
    //用PriorityQueue默認是天然順序排序,要選擇最大的k個數,構造小頂堆,每次取數組中剩餘數與堆頂的元素進行比較,若是新數比堆頂元素大,則刪除堆頂元素,並添加這個新數到堆中。
    //找出前k個最大數,採用小頂堆實現
    public static int[] findKMax(int[] nums, int k) {
        //隊列默認天然順序排列,小頂堆,沒必要重寫compare
        PriorityQueue<Integer> pq = new PriorityQueue<>(k);
        
        for (int num : nums) {
            if (pq.size() < k) {
                pq.offer(num);
                //若是堆頂元素 < 新數,則刪除堆頂,加入新數入堆
            } else if (pq.peek() < num) {
                pq.poll();
                pq.offer(num);
            }
        }
        
        int[] result = new int[k];
        for (int i = 0; i < k&&!pq.isEmpty(); i++) {
            result[i] = pq.poll();
        }
        return result;
    }

 public static void main(String[] args) {
        int[]arr=new int[]{1, 6, 2, 3, 5, 4, 8, 7, 9};
        System.out.println(Arrays.toString(findKMax( arr,5)));
    }
}
複製代碼

二、數組中的第K個最大元素

// 小頂堆
  PriorityQueue<Integer> pq = new PriorityQueue<>();
    for (int val : nums) {
        pq.add(val);
        // 維護堆的大小爲 K
        if (pq.size() > k) {
        //彈出最頂端的數,並刪除
             pq.poll();
        }
    }
    //取最頂端的數
    return pq.peek();
    }
複製代碼

3、大頂堆的應用

  • PriorityQueue經過傳入自定義的compara函數能夠實現大頂堆android

一、要選擇最小的K個數使用大頂堆,每次取數組中剩餘數與堆頂的元素進行比較,若是新數比堆頂元素小,則刪除堆頂元素,並添加這個新數到堆中。

public static int[] findKMin(int[] nums,int k ){
        PriorityQueue<Integer> pq = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int num:nums){
            if (pq.size() <k){
                pq.offer(num);
                //若是堆頂元素 > 新數,則刪除堆頂,加入新數入堆
            }else if(pq.peek() > num){
                pq.poll();
                pq.offer(num);

            }
        }
        int[] result = new int[k];
        for (int i = 0;i<k&&!pq.isEmpty();i++){
            result[i] = pq.poll();
        }
        return result;
    }

    public static void main(String[] args) {
        int[]arr=new int[]{1, 6, 2, 3, 5, 4, 8, 7, 9};
        System.out.println(Arrays.toString(findKMin( arr,5)));
    }

複製代碼

二、數組中的第K個最小元素

public static int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> pq = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int val : nums) {
            pq.add(val);
            // 維護堆的大小爲 K
            if (pq.size() > k) {
                pq.poll();
            }
        }
        return pq.peek();
    }
複製代碼
相關文章
相關標籤/搜索