1. 程式人生 > >求N個數中前k個大的數

求N個數中前k個大的數

解題思路:一般思路就是將N個數排序後,取前k個數就ok。但是如果N個數是幾十億個數,載入不到記憶體怎麼辦?這時候就需要利用堆來解決這個問題

具體的思路是:先建一個k個數的小堆,然後從k+1個數往後的值與堆頂元素比較,若此數比堆頂元素大,就將堆頂元素用這個數替換,然後重新調整堆,以此向後重複上述過程,直到將N個數比較完成,那麼此時組成這個堆的k個元素就是前k個大的數。

接下來我們講一下最小堆與最大對堆的思想:

一、堆樹的定義

堆樹的定義如下:

(1)堆樹是一顆完全二叉樹;

(2)堆樹中某個節點的值總是不大於或不小於其孩子節點的值;

(3)堆樹中每個節點的子樹都是堆樹。

當父節點的鍵值總是大於或等於任何一個子節點的鍵值時為最大堆

。 當父節點的鍵值總是小於或等於任何一個子節點的鍵值時為最小堆。如下圖所示,上面的為最大堆,下面的為最小堆。


二、堆樹的操作

以最大堆為例進行講解,最小堆同理。

原始資料為a[] = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7},採用順序儲存方式,對應的完全二叉樹如下圖所示:

(1)構造最大堆

在構造堆的基本思想就是:首先將每個葉子節點視為一個堆,再將每個葉子節點與其父節點一起構造成一個包含更多節點的對。

所以,在構造堆的時候,首先需要找到最後一個節點的父節點,從這個節點開始構造最大堆;直到該節點前面所有分支節點都處理完畢,這樣最大堆就構造完畢了。

假設樹的節點個數為n,以1為下標開始編號,直到n結束。對於節點i,其父節點為i/2;左孩子節點為i*2,右孩子節點為i*2+1。最後一個節點的下標為n,其父節點的下標為n/2。

如下圖所示,最後一個節點為7,其父節點為16,從16這個節點開始構造最大堆;構造完畢之後,轉移到下一個父節點2,直到所有父節點都構造完畢。

最後根據 最大值堆的思想,貼出一份最大堆的實現程式碼:

public class MaxHeap {

private int []heap ;
private int currentSize;
private static int MAXSIZE ;

public MaxHeap(int n){
    heap=new int[n];
    currentSize=0;
    MAXSIZE=n;
}

public boolean insert(int x){
    if(currentSize==MAXSIZE){
        System.out.println("Sorry,this heap is full!");
        return false;
    }
    //如果堆不滿的話
    currentSize++;
    int flag=currentSize-1;
    while(flag>0){
        int parent=(flag-1)/2;
        if(heap[parent]>x){
            heap[flag]=x;
            return true;
        }else{
            heap[flag]=heap[parent];
            flag=parent;
        }
    }
    heap[0]=x;
    return true;
}

public void siftDown(int flag){
    int want=flag;
    int x=heap[flag];

    while(want<currentSize){
        int lChild=2*want+1;
        int rChild=2*want+2;
        int MAXChildNumber;
        if(lChild>currentSize){  //沒有孩子節點
            heap[want]=x;
        }else{                   //有兩個孩子節點
            if(lChild<currentSize){
                MAXChildNumber=heap[lChild]>heap[rChild]?lChild:rChild;
            }else{
                MAXChildNumber=lChild;
            }
            if(heap[MAXChildNumber]<x){
                heap[want]=x;return;
            }else{
                heap[want]=heap[MAXChildNumber];
                want=MAXChildNumber;
            }
        }
    }

}

public int deleteTop(){
    if(currentSize<0){
        System.out.println("Sorry, this heap is empty!");
        return -1;
    }
    int target=heap[0];
    int substitute=heap[currentSize-1];
    this.currentSize--;
    heap[0]=substitute;
    siftDown(0);
    return target;
}

}

public class MaxHeapTest {
	 public static void main(String []args){
	        MaxHeap maxHeap=new MaxHeap(7);
	        for(int i=1;i<=7;i++){
	            maxHeap.insert(i);
	        }
	        for(int i=0;i<7;i++){
	            System.out.print(maxHeap.deleteTop()+"   ");
	        }
	        System.out.println("\n");
	    }
}

執行結果:


相關推薦

N個數中前k大的數

解題思路:一般思路就是將N個數排序後,取前k個數就ok。但是如果N個數是幾十億個數,載入不到記憶體怎麼辦?這時候就需要利用堆來解決這個問題具體的思路是:先建一個k個數的小堆,然後從k+1個數往後的值與堆頂元素比較,若此數比堆頂元素大,就將堆頂元素用這個數替換,然後重新調整堆,

面試題: N個數中前k大的數(大資料)

解題思路:一般思路就是將N個數排序後,取前k個數就ok。但是如果N個數是幾十億個數,載入不到記憶體怎麼辦?這就需要另外一種思路了,那就是利用堆。 具體的思路是:先建一個k個數的小堆,然後從k+1個數往

[USACO12FEB]牛的IDCow IDs 一題多解(二進位制中有k1 ,第n大的數)

題目: FJ給他的奶牛用二進位制進行編號,每個編號恰好包含K 個"1" (1 <= K <= 10),且必須是1開頭。FJ按升序編號,第一個編號是由K個"1"組成。 請問第N(1 <= N <= 10^7)個編號是什麼。   不同尋常的暴力: 樣例是升序的第7個,我

hdu 3915 Game N個數中取若干數字使得它們的異或值為0的方法數 高斯消元(mod2)

Problem Description   Mr.Frost is a child who is too simple, sometimes naive, always plays some simple but interesting games with his fri

分治演算法N個數中第K小(大)的數

這個學期開演算法課,跟著進度寫寫程式碼就好。這周講分治,說到了求N個數中第K小(大)數的問題,寫寫看。 分治演算法的複雜度是O(n),用到了快速排序的思路:先選取一個參考數進行一次快排,拿升序來說的話,快排之後左邊所有數<參考數,右邊所有數>參考數,然後根據左右

我的第六C++上機報告(個數中的最大數和最小數)

/* * Copyright (c) 2011, 煙臺大學計算機學院 * All rights reserved. * 作 者:王昕彤 * 完成日期:2012 年 10月 11日 * 版 本 號:v1.0 * * 輸入描述:四個數 * 問題描述:給定四個數,求出其中

逆序(n個數中m逆序)

.com light ostream size 逆序對數 逆序對 std ios pac 逆序對數列 對於一個數列{ai},如果有i<j且ai>aj,那麽我們稱ai與aj為一對逆序對數。若對於任意一個由1~n自然數組成的 數列,可以很容易求出有多少個逆序對數

【單調棧】個數組第一比他小的數的位置

type 技術分享 bit esp alt log lap while play 【AC】 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int

埃氏篩法(n以內有多少素數)

cin algorithm memset fin lse mod pre 判斷 end 題目大意:給定整數n,請問n以內有多少個素數 思路:想必要判斷一個數是否是素數,大家都會了,並且可以在O(根號n)的復雜度求出答案,那麽求n以內的素數呢,那樣求就顯得有點復雜了,下面看一

n個數的排列

如果給定N個不同字元,將這N個字元全排列,最終的結果將會是N!種。如:給定 A、B、C三個不同的字元,則結果為:ABC、ACB、BAC、BCA、CAB、CBA一共3!=3*2=6種情況。 public class Test6 { //設定總數 private static int count =0;pub

演算法 n個數的中位數 C

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

YTUOJ——函式模板--n個數的和

題目描述 利用函式模板求4個數的和。 部分程式碼已給定如下,只需要提交缺失的程式碼。 輸入 第一行4個字元 第二行4個整數 第三行4個小數 輸出 第一行4個字元ascii的和 第二行4個整數的和 第三行4個小數的和 樣例輸入 abcd 1 2 3 4 1.1 2.2

個數哪兩最接近c++程式碼

int main() { int a[MAXN]; int i = 0; int minus =0, abso = 0; int n1 = 0, n2 = 1; while (scanf_s(“%d”, &

n個數的最小公倍數

騰訊2018秋招筆試題(研發類),程式設計題第一題: 輸入:n m為離n最近的整數,且m要滿足: {n+1,n+2,...,m}的最小公倍數和{1,2,3,...,m}的最小公倍數相同。 輸出:m import java.util.Arrays; import ja

若干個數裡的最大數!!!

執行環境:win10  vs2013 題目一:求10 個整數中最大值。         這個問題我們可以才用陣列來解決問題,10個數我們需要定義一個長度為10的陣列,由於賦給的值是整數,因此陣列可以

C/C++ 個數中的最大數(簡單方法,一步到位)

#include <iostream> using namespace std; int max_3(int a, int b, int c) { return a > b ? (

演算法 - n個數的中位數(C++)

  //**************************************************************************************************** // // 求n個數的中位數 - C++ - by Chimomo // //

N個數的階乘相乘素因子個數總和

#include <bits/stdc++.h> using namespace std; bool vis[10000004]; vector<long long>prim; long long maxprim[10000004];//最大素因子 long long num

C語言10個數中的最大數

#include <stdio.h> int main() { int max; int a[10]={1,20,3,4,5,6,7,8,9,10}; max=a[0]; for(int i=1;i<10;i++)  { &

個數中的最大數

找最大數 任意輸入三個整型的數,找出其中最大的數,並輸出 輸入: 3 8 6 輸出: 8 #include <stdio.h> #include <stdlib.h>