Task: External sort


C++: 

 
#include <iostream>
#include <fstream>
#include <queue>
#include <string>
#include <algorithm>
#include <cstdio>




int main(int argc, char* argv[]);
void write_vals(int* const, const size_t, const size_t);
std::string mergeFiles(size_t); 




struct Compare
{
  
  bool operator() ( std::pair<int, int>& p1,  std::pair<int, int>& p2 )
  {
    return p1.first >= p2.first; 
  }
};


 


 
using ipair = std::pair<int,int>;

using pairvector = std::vector<ipair>;

using MinHeap = std::priority_queue< ipair, pairvector, Compare >;






const size_t memsize = 32;                        

const size_t chunksize = memsize / sizeof(int);   

const std::string tmp_prefix{"tmp_out_"};  

const std::string tmp_suffix{".txt"};      

const std::string merged_file{"merged.txt"}; 






void write_vals( int* const values, const size_t size, const size_t chunk )
{
 
  
  std::string output_file = (tmp_prefix + std::to_string(chunk) + tmp_suffix);
    
  std::ofstream ofs(output_file.c_str()); 

  for (int i=0; i<size; i++)  
    ofs << values[i] << '\t';
  
    ofs << '\n';

  ofs.close();
}





std::string mergeFiles(size_t chunks, const std::string& merge_file ) 
{

  std::ofstream ofs( merge_file.c_str() );
    
  MinHeap  minHeap;

  
  std::ifstream* ifs_tempfiles = new std::ifstream[chunks];
 
  for (size_t i = 1; i<=chunks; i++) 
    {
      int topval = 0;	

      
      std::string sorted_file = (tmp_prefix + std::to_string(i) + tmp_suffix);
       
      
      ifs_tempfiles[i-1].open( sorted_file.c_str() ); 

      
      if (ifs_tempfiles[i-1].is_open()) 
	{
	  ifs_tempfiles[i-1] >> topval; 

	  ipair top(topval, (i-1)); 
			      
	  minHeap.push( top );   
	}
    }
  

  while (minHeap.size() > 0) 
    {
      int next_val = 0;

      ipair min_pair = minHeap.top(); 

      minHeap.pop();

      ofs << min_pair.first << ' ';  
  
      std::flush(ofs);

      if ( ifs_tempfiles[min_pair.second] >> next_val) 
	{

	  ipair np( next_val, min_pair.second );

	  minHeap.push( np );
	}

    }
 

  
  for (int i = 1; i <= chunks; i++) 
    {
      ifs_tempfiles[i-1].close();
    }

  ofs << '\n';
  ofs.close();
    
  delete[] ifs_tempfiles; 
 
  return merged_file;  
}
 



int main(int argc, char* argv[] ) 
{

  if (argc < 2)
    {
      std::cerr << "usage:  ExternalSort <filename> \n";
      return 1;
    }

  

  std::ifstream ifs( argv[1] );  
  
  if ( ifs.fail() )
    {
      std::cerr << "error opening " << argv[1] << "\n";
      return 2;
    }


  
  int* inputValues = new int[chunksize];
 
  int chunk = 1;    

  int val = 0;      

  int count = 0;    

  bool done = false; 

  std::cout << "internal buffer is " << memsize << " bytes" << "\n"; 

  
  while (ifs >> val) 
    {
      done = false;

      inputValues[count] = val;
	
      count++;

      if (count == chunksize) 
	{

	  std::sort(inputValues, inputValues + count);

	  write_vals(inputValues, count, chunk); 

	  chunk ++;

	  count = 0;

	  done = true;
	}

    } 


  if (! done)  
    {
      std::sort(inputValues, inputValues + count);
    
      write_vals(inputValues, count, chunk); 
    }
  else 
    {
      chunk --;  
    }

 

  ifs.close();   
    

  delete[] inputValues; 
    

  
  if ( chunk == 0 ) 
    std::cout << "no data found\n";
  else
    std::cout << "Sorted output is in file: " << mergeFiles(chunk, merged_file ) << "\n";
     

  return EXIT_SUCCESS;
}







Go: package main

import (
    "fmt"
    "io"
    "log"
    "math"
    "math/rand"
    "os"
    "time"
)

type MinHeapNode struct{ element, index int }

type MinHeap struct{ nodes []MinHeapNode }

func left(i int) int {
    return (2*i + 1)
}

func right(i int) int {
    return (2*i + 2)
}

func newMinHeap(nodes []MinHeapNode) *MinHeap {
    mh := new(MinHeap)
    mh.nodes = nodes
    for i := (len(nodes) - 1) / 2; i >= 0; i-- {
        mh.minHeapify(i)
    }
    return mh
}

func (mh *MinHeap) getMin() MinHeapNode {
    return mh.nodes[0]
}

func (mh *MinHeap) replaceMin(x MinHeapNode) {
    mh.nodes[0] = x
    mh.minHeapify(0)
}

func (mh *MinHeap) minHeapify(i int) {
    l, r := left(i), right(i)
    smallest := i
    heapSize := len(mh.nodes)
    if l < heapSize && mh.nodes[l].element < mh.nodes[i].element {
        smallest = l
    }
    if r < heapSize && mh.nodes[r].element < mh.nodes[smallest].element {
        smallest = r
    }
    if smallest != i {
        mh.nodes[i], mh.nodes[smallest] = mh.nodes[smallest], mh.nodes[i]
        mh.minHeapify(smallest)
    }
}

func merge(arr []int, l, m, r int) {
    n1, n2 := m-l+1, r-m
    tl := make([]int, n1)
    tr := make([]int, n2)
    copy(tl, arr[l:])
    copy(tr, arr[m+1:])
    i, j, k := 0, 0, l
    for i < n1 && j < n2 {
        if tl[i] <= tr[j] {
            arr[k] = tl[i]
            k++
            i++
        } else {
            arr[k] = tr[j]
            k++
            j++
        }
    }
    for i < n1 {
        arr[k] = tl[i]
        k++
        i++
    }
    for j < n2 {
        arr[k] = tr[j]
        k++
        j++
    }
}

func mergeSort(arr []int, l, r int) {
    if l < r {
        m := l + (r-l)/2
        mergeSort(arr, l, m)
        mergeSort(arr, m+1, r)
        merge(arr, l, m, r)
    }
}


func mergeFiles(outputFile string, n, k int) {
    in := make([]*os.File, k)
    var err error
    for i := 0; i < k; i++ {
        fileName := fmt.Sprintf("es%d", i)
        in[i], err = os.Open(fileName)
        check(err)
    }
    out, err := os.Create(outputFile)
    check(err)
    nodes := make([]MinHeapNode, k)
    i := 0
    for ; i < k; i++ {
        _, err = fmt.Fscanf(in[i], "%d", &nodes[i].element)
        if err == io.EOF {
            break
        }
        check(err)
        nodes[i].index = i
    }
    hp := newMinHeap(nodes[:i])
    count := 0
    for count != i {
        root := hp.getMin()
        fmt.Fprintf(out, "%d ", root.element)
        _, err = fmt.Fscanf(in[root.index], "%d", &root.element)
        if err == io.EOF {
            root.element = math.MaxInt32
            count++
        } else {
            check(err)
        }
        hp.replaceMin(root)
    }
    for j := 0; j < k; j++ {
        in[j].Close()
    }
    out.Close()
}

func check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}



func createInitialRuns(inputFile string, runSize, numWays int) {
    in, err := os.Open(inputFile)
    out := make([]*os.File, numWays)
    for i := 0; i < numWays; i++ {
        fileName := fmt.Sprintf("es%d", i) 
        out[i], err = os.Create(fileName)
        check(err)
    }
    arr := make([]int, runSize)
    moreInput := true
    nextOutputFile := 0
    var i int
    for moreInput {
        for i = 0; i < runSize; i++ {
            _, err := fmt.Fscanf(in, "%d", &arr[i])
            if err == io.EOF {
                moreInput = false
                break
            }
            check(err)
        }
        mergeSort(arr, 0, i-1)
        for j := 0; j < i; j++ {
            fmt.Fprintf(out[nextOutputFile], "%d ", arr[j])
        }
        nextOutputFile++
    }
    for j := 0; j < numWays; j++ {
        out[j].Close()
    }
    in.Close()
}

func externalSort(inputFile, outputFile string, numWays, runSize int) {
    createInitialRuns(inputFile, runSize, numWays)
    mergeFiles(outputFile, runSize, numWays)
}

func main() {
    
    
    numWays := 4
    runSize := 10
    inputFile := "input.txt"
    outputFile := "output.txt"
    in, err := os.Create(inputFile)
    check(err)
    rand.Seed(time.Now().UnixNano())
    for i := 0; i < numWays*runSize; i++ {
        fmt.Fprintf(in, "%d ", rand.Intn(math.MaxInt32))
    }
    in.Close()
    externalSort(inputFile, outputFile, numWays, runSize)
    
    for i := 0; i < numWays; i++ {
        fileName := fmt.Sprintf("es%d", i)
        err = os.Remove(fileName)
        check(err)
    }
}