package upr.u7; import java.util.Comparator; import java.io.*; import upr.utils.*; import upr.u6.HeapSort; /** * Simple External Sort, uses MergeSort with two scratch files and a buffer. */ public class ExternalSort implements SortFile { public static final int DEFAULT_BUFFER_SIZE = 1024*50; private int bufferSize; private String tmpFile1 = "temp_1.txt"; //first scratch file (tape) private String tmpFile2 = "temp_2.txt"; //second scratch file (tape) private boolean sorted = false; //indicates whether the sort is done private int secCount = 0; private int csize; /** Default Constructor */ public ExternalSort() { this(DEFAULT_BUFFER_SIZE); } /** * Constructs an object that sorts files of Item objects, * with given 'bufferSize' - the size of each section (buffer) * used in the external sorting. */ public ExternalSort(int bufferSize) { this.bufferSize = bufferSize; csize = bufferSize; } /** Sorts the file 'fname' of objects of class Item using the given comparator */ public void sort(String fname, Comparator c) { try { start(fname, c);//razpredelia gi v tmp1 i tmp2 i sortira kvoto triabva merge(fname, c); while (secCount > 1) { distribute(fname, c);//distribute merge(fname, c); //merge } } catch (IOException ex) { System.out.println("[ExternalSort][sort] IOException caught: " + ex.getMessage()); throw new RuntimeException("[ExternalSort][sort] " + ex.getMessage()); } } /** Initial work and distribution */ private void start(String fname, Comparator c) throws IOException { Item[] items = new Item[bufferSize]; int iSize = 0; FileInputStream istream = new FileInputStream(fname); ObjectInputStream p = new ObjectInputStream(istream); FileOutputStream ostream1 = new FileOutputStream(tmpFile1); ObjectOutputStream p1 = new ObjectOutputStream(ostream1); FileOutputStream ostream2 = new FileOutputStream(tmpFile2); ObjectOutputStream p2 = new ObjectOutputStream(ostream2); int count = 0; //number of sections to be merged later for(; ; count++) { iSize = ESortUtils.load(items, p); if (iSize == 0) break; //BubbleSort.sort(items, iSize, c); (new HeapSort()).sort(items, c); if (count % 2 == 0) { ESortUtils.writeBuffer(p1, items, iSize); } else { ESortUtils.writeBuffer(p2, items, iSize); } } secCount = count; istream.close(); p1.flush(); ostream1.close(); p2.flush(); ostream2.close(); } /** Merges two work files into 'name' */ private void merge(String name, Comparator c) throws IOException { FileOutputStream ostream = new FileOutputStream(name); ObjectOutputStream oos = new ObjectOutputStream(ostream); FileInputStream istream1 = new FileInputStream(tmpFile1); ObjectInputStream ois1 = new ObjectInputStream(istream1); FileInputStream istream2 = new FileInputStream(tmpFile2); ObjectInputStream ois2 = new ObjectInputStream(istream2); for(int k = 0; k < (secCount + 1)/2; k++) { mergeSection(ois1, ois2, oos, c); } oos.flush(); ostream.close(); istream1.close(); istream2.close(); csize *= 2; secCount = (secCount + 1) / 2; } /** Distributes the sections from 'fname' over two scratch files. */ private void distribute(String fname, Comparator c) throws IOException { FileInputStream istream = new FileInputStream(fname); ObjectInputStream p = new ObjectInputStream(istream); FileOutputStream ostream1 = new FileOutputStream(tmpFile1); ObjectOutputStream oos1 = new ObjectOutputStream(ostream1); FileOutputStream ostream2 = new FileOutputStream(tmpFile2); ObjectOutputStream oos2 = new ObjectOutputStream(ostream2); ObjectOutputStream current = oos1; Item tmp = ESortUtils.readObject(p); int count = 0; //number of sections to merge later while (tmp != null) { count++; for (int i = 0; i < csize && tmp != null; i++) { try { current.writeObject(tmp); } catch (IOException io) { io.printStackTrace(); break; } tmp = ESortUtils.readObject(p); } //one section is distributed current = (current == oos1) ? oos2 : oos1; } secCount = count; istream.close(); ostream1.close(); ostream2.close(); } /** Merges the sorted sections of 'ois1' and 'ois2' into 'oos' */ private void mergeSection(ObjectInputStream ois1, ObjectInputStream ois2, ObjectOutputStream oos, Comparator c) throws IOException { Item tmp1 = ESortUtils.readObject(ois1); Item tmp2 = ESortUtils.readObject(ois2); if (tmp1 == null && tmp2 == null) return; int i = 1; int j = 1; while(i <= csize && j <= csize && tmp1 != null && tmp2 != null) { try { if (c.compare(tmp1.getKey(), tmp2.getKey()) <= 0) { oos.writeObject(tmp1); tmp1 = (i < csize) ? ESortUtils.readObject(ois1) : null; i++; } else { oos.writeObject(tmp2); tmp2 = (j < csize) ? ESortUtils.readObject(ois2) : null; j++; } } catch (Exception e) { System.out.println("[mergeSection] Exception caught:"); e.printStackTrace(); break; } } if (i > csize || tmp1 == null) { while( j <= csize && tmp2 != null){ oos.writeObject(tmp2); tmp2 = (j < csize) ? ESortUtils.readObject(ois2) : null; j++; } } //if if (j > csize || tmp2 == null) { while (i <= csize && tmp1 != null) { oos.writeObject(tmp1); tmp1 = (i < csize) ? ESortUtils.readObject(ois1) : null; i++; } } //if oos.flush(); } //method }