1. 程式人生 > >Java 堆排序 Top K

Java 堆排序 Top K

1.堆

  堆實際上是一棵完全二叉樹,其任何一非葉節點滿足性質:

  Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key[i]>=key[2i+2]

  即任何一非葉節點的關鍵字不大於或者不小於其左右孩子節點的關鍵字。

  堆分為大頂堆和小頂堆,滿足Key[i]>=Key[2i+1]&&key>=key[2i+2]稱為大頂堆,滿足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]稱為小頂堆。由上述性質可知大頂堆的堆頂的關鍵字肯定是所有關鍵字中最大的,小頂堆的堆頂的關鍵字是所有關鍵字中最小的。

2.堆排序的思想

   利用大頂堆(小頂堆)堆頂記錄的是最大關鍵字(最小關鍵字)這一特性,使得每次從無序中選擇最大記錄(最小記錄)變得簡單。

    其基本思想為(大頂堆):

    1)將初始待排序關鍵字序列(R1,R2....Rn)構建成大頂堆,此堆為初始的無序區;

    2)將堆頂元素R[1]與最後一個元素R[n]交換,此時得到新的無序區(R1,R2,......Rn-1)和新的有序區(Rn),且滿足R[1,2...n-1]<=R[n]; 

    3)由於交換後新的堆頂R[1]可能違反堆的性質,因此需要對當前無序區(R1,R2,......Rn-1)調整為新堆,然後再次將R[1]與無序區最後一個元素交換,得到新的無序區(R1,R2....Rn-2)和新的有序區(Rn-1,Rn)。不斷重複此過程直到有序區的元素個數為n-1,則整個排序過程完成。

    操作過程如下:

     1)初始化堆:將R[1..n]構造為堆;

     2)將當前無序區的堆頂元素R[1]同該區間的最後一個記錄交換,然後將新的無序區調整為新的堆。

    因此對於堆排序,最重要的兩個操作就是構造初始堆和調整堆,其實構造初始堆事實上也是調整堆的過程,只不過構造初始堆是對所有的非葉節點都進行調整。

    下面舉例說明:

     給定一個整形陣列a[]={16,7,3,20,17,8},對其進行堆排序。

    首先根據該陣列元素構建一個完全二叉樹,得到

 然後需要構造初始堆,則從最後一個非葉節點開始調整,調整過程如下:

20和16交換後導致16不滿足堆的性質,因此需重新調整

這樣就得到了初始堆。

即每次調整都是從父節點、左孩子節點、右孩子節點三者中選擇最大者跟父節點進行交換(交換之後可能造成被交換的孩子節點不滿足堆的性質,因此每次交換之後要重新對被交換的孩子節點進行調整)。有了初始堆之後就可以進行排序了。

此時3位於堆頂不滿堆的性質,則需調整繼續調整

 這樣整個區間便已經有序了。     從上述過程可知,堆排序其實也是一種選擇排序,是一種樹形選擇排序。只不過直接選擇排序中,為了從R[1...n]中選擇最大記錄,需比較n-1次,然後從R[1...n-2]中選擇最大記錄需比較n-2次。事實上這n-2次比較中有很多已經在前面的n-1次比較中已經做過,而樹形選擇排序恰好利用樹形的特點儲存了部分前面的比較結果,因此可以減少比較次數。對於n個關鍵字序列,最壞情況下每個節點需比較log2(n)次,因此其最壞情況下時間複雜度為nlogn。堆排序為不穩定排序,不適合記錄較少的排序。 /*堆排序(大頂堆)*/ 

#include <iostream>
#include<algorithm>
using namespace std;

void HeapAdjust(int *a,int i,int size)  //調整堆 
{
    int lchild=2*i;       //i的左孩子節點序號 
    int rchild=2*i+1;     //i的右孩子節點序號 
    int max=i;            //臨時變數 
    if(i<=size/2)          //如果i是葉節點就不用進行調整 
    {
        if(lchild<=size&&a[lchild]>a[max])
        {
            max=lchild;
        }    
        if(rchild<=size&&a[rchild]>a[max])
        {
            max=rchild;
        }
        if(max!=i)
        {
            swap(a[i],a[max]);
            HeapAdjust(a,max,size);    //避免調整之後以max為父節點的子樹不是堆 
        }
    }        
}


void BuildHeap(int *a,int size)    //建立堆 
{
    int i;
    for(i=size/2;i>=1;i--)    //非葉節點最大序號值為size/2 
    {
        HeapAdjust(a,i,size);    
    }    



void HeapSort(int *a,int size)    //堆排序 
{
    int i;
    BuildHeap(a,size);
    for(i=size;i>=1;i--)
    {
        //cout<<a[1]<<" ";
        swap(a[1],a[i]);           //交換堆頂和最後一個元素,即每次將剩餘元素中的最大者放到最後面 
          //BuildHeap(a,i-1);        //將餘下元素重新建立為大頂堆 
          HeapAdjust(a,1,i-1);      //重新調整堆頂節點成為大頂堆
    }



int main(int argc, char *argv[])
{
     //int a[]={0,16,20,3,11,17,8};
    int a[100];
    int size;
    while(scanf("%d",&size)==1&&size>0)
    {
        int i;
        for(i=1;i<=size;i++)
            cin>>a[i];
        HeapSort(a,size);
        for(i=1;i<=size;i++)
            cout<<a[i]<<"";
        cout<<endl;
    }
    return 0;
}

Java:
[java] view plaincopyprint?
  1. publicclass HeapSortTest {  
  2.     publicstaticvoid main(String[] args) {  
  3.         int[] data5 = newint[] { 536219487 };  
  4.         print(data5);  
  5.         heapSort(data5);  
  6.         System.out.println("排序後的陣列:");  
  7.         print(data5);  
  8.     }  
  9.     publicstaticvoid swap(int[] data, int i, int j) {  
  10.         if (i == j) {  
  11.             return;  
  12.         }  
  13.         data[i] = data[i] + data[j];  
  14.         data[j] = data[i] - data[j];  
  15.         data[i] = data[i] - data[j];  
  16.     }  
  17.     publicstaticvoid heapSort(int[] data) {  
  18.         for (int i = 0; i < data.length; i++) {  
  19.             createMaxdHeap(data, data.length - 1 - i);  
  20.             swap(data, 0, data.length - 1 - i);  
  21.             print(data);  
  22.         }  
  23.     }  
  24.     publicstaticvoid createMaxdHeap(int[] data, int lastIndex) {  
  25.         for (int i = (lastIndex - 1) / 2; i >= 0; i--) {  
  26.             // 儲存當前正在判斷的節點
  27.             int k = i;  
  28.             // 若當前節點的子節點存在
  29.             while (2 * k + 1 <= lastIndex) {  
  30.                 // biggerIndex總是記錄較大節點的值,先賦值為當前判斷節點的左子節點
  31.                 int biggerIndex = 2 * k + 1;  
  32.                 if (biggerIndex < lastIndex) {  
  33.                     // 若右子節點存在,否則此時biggerIndex應該等於 lastIndex
  34.                     if (data[biggerIndex] < data[biggerIndex + 1]) {  
  35.                         // 若右子節點值比左子節點值大,則biggerIndex記錄的是右子節點的值
  36.                         biggerIndex++;  
  37.                     }  
  38.                 }  
  39.                 if (data[k] < data[biggerIndex]) {  
  40.                     // 若當前節點值比子節點最大值小,則交換2者得值,交換後將biggerIndex值賦值給k
  41.                     swap(data, k, biggerIndex);  
  42.                     k = biggerIndex;  
  43.                 } else {  
  44.                     break;  
  45.                 }  
  46.             }  
  47.         }  
  48.     }  
  49.     publicstaticvoid print(int[] data) {  
  50.         for (int i = 0; i < data.length; i++) {  
  51.             System.out.print(data[i] + "\t");  
  52.         }  
  53.         System.out.println();  
  54.     }  
  55. }  


執行結果:

[java] view plaincopyprint?
  1. 536219487
  2. 386715429
  3. 276315489
  4. 436215789
  5. 435216789
  6. 134256789
  7. 231456789
  8. 123456789
  9. 相關推薦

    Java 排序 Top K

    1.堆   堆實際上是一棵完全二叉樹,其任何一非葉節點滿足性質:   Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key[i]>=

    大小排序 & Top K 問題

    大小堆排序 堆這種資料結構定義比較簡單,大根堆就是父節點的值大於左右子孩子節點的值(小根堆相反),而且利用陣列下標就可以很好的表現堆(不過要注意是從0 還是 1開始)。堆常用語實現優先佇列,Top K等問題。 演算法導論第6章對堆的進行了詳細講解,我就不贅述

    java 排序

    修改 stat for arr 描述 nbsp string newobject add package wangChaoPA實習工作練習.com.進階篇.排序;import java.util.ArrayList;/** * * <p> * 描述該類情況 [e

    java排序實現

    wap compare 之前 compareto string swap 代碼 範圍 最後一個元素 代碼如下: public class HeapSort { public static void heapSort(DataWrap[] data) {

    java 排序學習

    /** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> All rights reserved. - https://github.co

    最小解決Top K問題

    問題描述: 有一組資料n個,要求取出這組資料中最大的K個值。 對於這個問題,解法有很多中。比如排序及部分排序,不過效率最高的要數最小堆,它的時間複雜度為O(nlogk)。 解題思路: 取出

    最小解決 Top K 問題

    Top K 問題指從一組資料中選出最大的K個數。常見的例子有:熱門搜尋前10,最常聽的20首歌等。 對於這類問題,可能我們會首先想到先對這組資料進行排序,再選取前K個數。雖然這能解決問題,但效率不高,因為我們只需要部分有序,它卻對整體進行了排序。最小堆是解決To

    Java 排序(大根及小根

    整理網上的最大堆及最小堆程式碼 public abstract class Sorter { public abstract void sort(int[] array); } public class HeapSorter extends

    java排序

    先讓我們看以下序列:然我們把這個先序列堆儲存:然後在進行一次排序,排序的規則是,從最底層開始,左右子樹調出最大的值給父節點,一直到0號位置。最低層排序後,如上然後全部排序後:這就是一次排序,最大值到了0號,位置,然後0號和最後一個交換位置,確定9號位置的值,再進行剩下幾次排序

    hadoop 中文詞頻排序 top-k 問題

        本人最近一直在hadoop領域,摸爬滾打,由於最近老是佈置了一項作業:讓統計一個檔案中出現次數最高的單詞。一看到題目我就想用hadoop來實現這個問題,由於有現成的wordcount框架,所以就在這之上進行程式的修改新增即可。     準備過程:     1、我去下

    從分類,排序,top-k多個方面對推薦演算法穩定性的評價

    介紹 論文名: “classification, ranking, and top-k stability of recommendation algorithms”. 本文講述比較推薦系統在三種情況下, 推薦穩定性情況. 與常規準確率比較的方式不同, 本

    排序演算法整理(6)排序的應用,top K 問題

    top K問題是這樣的,給定一組任意順序的數,假設有n個。如何儘快地找到它們的前K個最大的數? 首先,既然是找前K個最大的數,那麼最直觀的辦法是,n個數全部都排序,然後挑出前K個最大數。但是這樣顯然做了一些不必要的事兒。 利用堆這種資料結構,藉助前文《排序演算法整理(5)堆

    Top K問題——基於排序

    一、簡介 所謂的Top K問題其實就是找陣列中最大的前k個值。為此,只要我們能夠找到陣列中的第k大值,那麼Top K問題就會迎刃而解。在此宣告一下,本文寫的方法肯定不是最好的。不過最近看了幾個題,其核心都是找第k大的值。這裡,我只是總結下而已。 二、

    Java與算法之(8) - 排序

    循環 public tar 最大 swap https rgs tool 技術分享 堆是一種特殊的完全二叉樹,其特點是所有父節點都比子節點要小,或者所有父節點都比字節點要大。前一種稱為最小堆,後一種稱為最大堆。 比如下面這兩個: 那麽這個特性有什麽作用?既然題目是堆排序,

    Java學習筆記——排序算法之進階排序排序與分治並歸排序

    進行 技術分享 ring http 沒有 oid 有序 重復 調整 春蠶到死絲方盡,蠟炬成灰淚始幹               ——無題 這裏介紹兩個比較難的算法: 1、堆排序 2、分治並歸排序 先說堆。 這裏請大家先自行了解完全二叉樹的數據結構。 堆是完全二叉樹。

    排序算法(二):排序-Java實現

    並且 小頂堆 但是 清晰 big 又是 左右 位置 堆排 排序算法(二):堆排序-Java實現 首先對堆排序有個整體的認識,堆排序是一個不穩定的排序算法,其平均時間復雜度為O(nlogn),空間復雜度O(1)。 那麽何為堆排序呢?所謂堆排序是借助於堆的概念來完成的排序算法,

    數據結構——排序(使用Java

    空間 nlog closed pso 算法 隨機數組 復雜度 sed 記錄 一、簡介   堆排序(HeapSort)是選擇排序的改進版,它可以減少在選擇排序中的比較次數,進而減少排序時間,堆排序法用到了二叉樹的技巧,它利用堆積樹來完成,堆積是一種特殊的二叉樹,可分為大根堆和

    最小的k個數1 排序實現

    葉子節點 gpo 新建 void 堆排序實現 oid end 個數 時間 // 使用堆排序實現 其時間復雜度為O(nlgn) private static void buildMaxHeap(int[] input, int end) { // 從

    排序 最大堆 最小 Java實現

    堆排序 最大堆 最小堆 Java 堆排序啊,其實是一種數據結構,二叉樹,二叉樹分為是滿二叉樹和完全二叉樹。一棵深度為 k,且有 2k - 1 個節點稱之為滿二叉樹,完全二叉樹:深度為 k,有 n 個節點的二叉樹,當且僅當其每一個節點都與深度為 k 的滿二叉樹中序號為 1 至 n 的節點對應時,

    排序Java實現

    穩定 bsp urn 復雜 java實現 重新整理 建堆 很多 空間 看了很多博主寫了堆排序的原理,都講解的挺明白,就是代碼實現(主要是java語言)有些讓人眼花繚亂。我重新整理了堆排序的代碼實現(java)。 有哪些問題和不妥之處,還希望夥伴們提醒,我及時改正。感謝!!