外部排序:多路歸並樹


定義:

1、按可用內存大小,將外存上的記錄文件分成若干個歸並段 (segments)

2、依次讀入內存並利用有效的外部排序方法進行排序

3、將排序后的有序子文件寫入外存

 

實現:

利用敗者樹進行k路歸並,使得每次歸並在k個記錄中選出最小記錄僅需進行次(二叉樹的深度)比較,從而使總的歸並時間為。其中,m為初始歸並段個數,n為總記錄數,每次比較時間。

 

敗者樹:

典型的4路敗者樹如下圖:

----------à

直觀的,敗者樹是一棵完全二叉樹,可由數組保持。其中根節點保存一次比較中的冠軍;葉節點保存4個歸並段的輸入流;非葉結點保存一次比較中的敗者。

 

難點1:一輪比較選出最小關鍵記錄並調整敗者樹

調整的發起點:值發生變化的葉節點,必然使對應的父節點發生變化。注意,父節點中記錄的敗者必然是另一棵子樹的勝者,但是敗給了本子樹的勝者,如

 

調整:

1、i保存前一次比較的勝者,與的敗者比較

    If i失敗: , 發生互換

2、如此遞歸的向根節點調用,直到根節點,將i中的冠軍計入

難點2:敗者樹的初始化

1、將非葉結點初始化為可能的最小值(冠軍)

2、由調整敗者樹

 

注意點:

每個歸並段內的數據是有序的,這與歸並排序是一致的。並且歸並段的最后需要一個全局最小的"哨兵",防止歸並段讀空(仔細想想),並且當冠軍為"哨兵"時,程序退出。

 

思想:以空間保存歷次比較結果,將一般k-路歸並選擇一次最小值的k-1次操作變為,典型的時空互換思想。

 

代碼:

  1. import java.io.*;
  2.  
  3. public class LoserTree {
  4.  
  5.    public static void main(String[] args) {
  6.  
  7.       PrintWriter[] data = new PrintWriter[LoserTree.K];
  8.       BufferedReader[] segments = new BufferedReader[LoserTree.K];
  9.  
  10.  
  11.       try {
  12.  
  13.          for (int i = 0; i < LoserTree.K; i++) {
  14.  
  15.             data[i] = new PrintWriter(new FileWriter(i + ".txt"));
  16.          }
  17.  
  18.          for (int k = 0; k < 5; k++) {
  19.  
  20.             for (int i = 0; i < 5; i++) {
  21.  
  22.                data[k].println(21 - 5 * k + i);
  23.             }
  24.  
  25.             data[k].println(LoserTree.MAXKEY);
  26.          }
  27.  
  28.          for (int i = 0; i < LoserTree.K; i++) {
  29.  
  30.             data[i].close();
  31.          }
  32.  
  33.          for (int i = 0; i < LoserTree.K; i++) {
  34.  
  35.             segments[i] = new BufferedReader(new FileReader(i + ".txt"));
  36.          }
  37.  
  38.          LoserTree Sorter = new LoserTree();
  39.  
  40.          Sorter.merge(segments);
  41.  
  42.          for (int i = 0; i < LoserTree.K; i++) {
  43.  
  44.             segments[i].close();
  45.          }
  46.  
  47.       } catch (Exception e) {
  48.  
  49.          e.printStackTrace();
  50.       }
  51.  
  52.    }
  53.  
  54.    static final int K = 5;
  55.    static final int MINKEY = -100;
  56.    static final int MAXKEY = 100;
  57.  
  58.    public int[] LS = new int[K];
  59.    public int[] b = new int[K + 1];
  60.  
  61.    PrintWriter result;
  62.  
  63.    public void merge(BufferedReader[] in) {
  64.  
  65.       try {
  66.          result = new PrintWriter(new File("result.txt"));
  67.  
  68.          for (int i = 0; i < K; i++) {
  69.  
  70.             input(in[i], i);
  71.          }
  72.  
  73.          create();
  74.  
  75.          int q;
  76.  
  77.          while (b[LS[0]] != MAXKEY) {
  78.  
  79.             q = LS[0];
  80.  
  81.             output(q);
  82.  
  83.             input(in[q], q);
  84.  
  85.             adjust(q);
  86.  
  87.          }
  88.  
  89.          result.close();
  90.  
  91.       } catch (Exception e) {
  92.          // TODO Auto-generated catch block
  93.          throw new RuntimeException(e);
  94.       }
  95.  
  96.  
  97.    }
  98.  
  99.    private void create() {
  100.  
  101.       b[K] = MINKEY;
  102.  
  103.       for (int i = 0; i < K; i++) {
  104.  
  105.          LS[i] = K;
  106.       }
  107.  
  108.       for (int i = K-1; i > -1; i--) {
  109.  
  110.          adjust(i);
  111.       }
  112.    }
  113.  
  114.    private void adjust(int i) {
  115.  
  116.       int parent = (i + K) / 2;
  117.  
  118.       int temp;
  119.  
  120.       while (parent > 0) {
  121.  
  122.          if (b[i] > b[LS[parent]]) {
  123.  
  124.             temp = LS[parent];
  125.             LS[parent] = i;
  126.             i = temp;
  127.          }
  128.  
  129.          parent = parent / 2;
  130.       }
  131.  
  132.       LS[0] = i;
  133.  
  134.  
  135.    }
  136.  
  137.    private void input(BufferedReader in, int i) {
  138.  
  139.       try {
  140.  
  141.          b[i] = Integer.valueOf(in.readLine());
  142.  
  143.       } catch (Exception e) {
  144.          // TODO Auto-generated catch block
  145.          throw new RuntimeException(e);
  146.  
  147.       }
  148.    }
  149.  
  150.    private void output(int i) {
  151.  
  152.       result.println(b[i]);
  153.       result.flush();
  154.    }
  155. }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM