Implement selection sort and in-place merge sort for RandomAccessFileList

This commit is contained in:
Travis Burtrum 2017-02-10 02:38:24 -05:00
parent ba0b66ce54
commit 8635874c04
2 changed files with 140 additions and 8 deletions

View File

@ -1,6 +1,7 @@
package com.moparisthebest.filelist;
import java.io.IOException;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
@ -11,7 +12,7 @@ public class Main {
public static void main(String[] args) throws IOException {
System.out.println("str " + new Date());
//final List<Long> list = new RandomAccessFileList<>("/home/mopar/raf2.list", new UnsignedLongConverter(5));
final List<Long> list = new RandomAccessFileList<>("/home/mopar/raf2.list", LongConverter40Bit.instance);
final List<Long> list = new RandomAccessFileList<>("/home/mopar/raf2.list", LongConverter40Bit.instance); list.clear();
/*
System.out.println(list.get(0));
System.out.println(((RandomAccessFileList)list).longSize());
@ -35,14 +36,18 @@ public class Main {
list.add(99999999999L);
System.out.println(list.get(1));
list.add(6L);
list.add(4L);
System.out.println(list);
for(long l : list)
System.out.println(l);
list.sort(Long::compareTo);
System.out.println(list);
System.out.println("------");
//if(true) return;
for(long l = 0; l < 1000; ++l)
//for(long l = 7; l < 11; ++l)
list.add(l);
System.out.println(list);
list.sort(Long::compareTo);
list.sort(Comparator.reverseOrder());
System.out.println(list);
}
}

View File

@ -4,8 +4,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.AbstractList;
import java.util.Objects;
import java.util.*;
/**
* Created by mopar on 2/9/17.
@ -19,7 +18,7 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
public RandomAccessFileList(final RandomAccessFile raf, final ByteArrayConverter<T> bac) {
Objects.requireNonNull(raf);
Objects.requireNonNull(bac);
if(bac.numBytes() < 1)
if (bac.numBytes() < 1)
throw new IllegalArgumentException("bytesPerEntry must be > 0");
this.raf = raf;
this.buffer = new byte[bac.numBytes()];
@ -44,7 +43,7 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
public T get(final long index) throws IOException {
raf.seek(index * buffer.length);
if(raf.read(buffer) != buffer.length)
if (raf.read(buffer) != buffer.length)
throw new IOException("no full buffer to read, corrupted file?");
return bac.fromBytes(buffer);
}
@ -76,7 +75,7 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
@Override
public T set(final int index, final T o) {
try {
return this.set((long)index, o);
return this.set((long) index, o);
} catch (IOException e) {
throw new RuntimeException(e);
}
@ -98,4 +97,132 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
throw new RuntimeException(e);
}
}
@Override
public void sort(final Comparator<? super T> c) {
try {
//this.selectionSort(c);
this.inPlaceMergeSort(c);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void selectionSort(final Comparator<? super T> c) throws IOException {
// a[0] to a[n-1] is the array to sort
final long n = this.longSize(), n1 = n - 1;
final byte[] tmp = new byte[this.buffer.length];
// advance the position through the entire array
// (could do j < n-1 because single element is also min element)
for (long j = 0; j < n1; ++j) {
/* find the min element in the unsorted a[j .. n-1] */
/* assume the min is the first element */
long iMin = j;
/* test against elements after j to find the smallest */
for (long i = j + 1; i < n; ++i) {
// if this element is less, then it is the new minimum
// this order is important, we want get(iMin) done last so it's already in buffer below if we need to swap!
// in all cases except when iMin is last, in which case we have to seek back and read it, this is less common though usually
final T iObj = this.get(i);
if (c.compare(iObj, this.get(iMin)) <= 0){
// found new minimum; remember its index
iMin = i;
}
}
if (iMin != j) {
//swap(a[j], a[iMin]);
// buffer already has iMin value in it unless iMin was last value
if (iMin == n1) {
// grab iMin to buffer
raf.seek(iMin * buffer.length);
if (raf.read(buffer) != buffer.length)
throw new IOException("no full buffer to read, corrupted file?");
}
// grab j to tmp
raf.seek(j * buffer.length);
if (raf.read(tmp) != buffer.length)
throw new IOException("no full buffer to read, corrupted file?");
//System.out.printf("iMin: %d j: %d buffer: %d tmp: %d%n", iMin, j, bac.fromBytes(buffer), bac.fromBytes(tmp));
// write buffer to j
raf.seek(j * buffer.length);
raf.write(buffer);
// write tmp to iMin
raf.seek(iMin * buffer.length);
raf.write(tmp);
}
}
}
/**
* In-Place Merge Sort.
* <p>
* Building on the algorithm core found in
* http://www.cs.ubc.ca/~harrison/Java/MergeSortAlgorithm.java.html
* http://penguin.ewu.edu/cscd300/Topic/AdvSorting/MergeSorts/InPlace.html
* http://penguin.ewu.edu/cscd300/Topic/AdvSorting/MergeSorts/MergeSort.java
*/
public void inPlaceMergeSort(final Comparator<? super T> c) throws IOException {
this.inPlaceMergeSort(c, 0, this.longSize() - 1);
}
public void inPlaceMergeSort(final Comparator<? super T> c, final long first, final long last) throws IOException {
long mid, lt, rt;
if (first >= last) return;
mid = (first + last) / 2;
inPlaceMergeSort(c, first, mid);
inPlaceMergeSort(c, mid + 1, last);
lt = first;
rt = mid + 1;
// One extra check: can we SKIP the merge?
if (c.compare(this.get(mid), this.get(rt)) <= 0)
return;
byte[] tmp = new byte[buffer.length], tmp2 = new byte[buffer.length], tmp3;
while (lt <= mid && rt <= last) {
// Select from left: no change, just advance lt
if (c.compare(this.get(lt), this.get(rt)) <= 0)
++lt;
// Select from right: rotate [lt..rt] and correct
else {
// buffer contains rt here due to this.get(rt) being called last above, will move to [lt]
// scoot everything else over one todo: can do this in bigger chunks than buffer.length to speed things up...
//System.out.printf("lt: %d, rt: %d, rt-lt: %d, buffer: %d%n", lt, rt, rt-lt, bac.fromBytes(buffer));
raf.seek(lt * buffer.length);
raf.read(tmp);
for(long dst = lt + 1; dst <= lt + (rt - lt); ++dst){
//raf.seek(dst * buffer.length);
raf.read(tmp2);
raf.seek(dst * buffer.length);
raf.write(tmp);
tmp3 = tmp2;
tmp2 = tmp;
tmp = tmp3;
}
// write buffer to lt
raf.seek(lt * buffer.length);
raf.write(buffer);
// EVERYTHING has moved up by one
lt++;
mid++;
rt++;
}
}
// Whatever remains in [rt..last] is in place
}
}