外部排序:多路归并树

定义:

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. }

posted on 2013-09-12 15:11  zjgtan  阅读(7829)  评论(0编辑  收藏  举报

导航