diff --git a/.gitignore b/.gitignore index aff01a41b54c1ac1fa81e2a282a939e27034a607..54a63ca7b617a3b932d20c9439b1b178442dd532 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.blg *DS_Store* *.csv +*/bin *.ser .idea/ *.class diff --git a/Proposals/.DS_Store b/Proposals/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f15975d6621e185c2e729fc3672df259aa712fcf Binary files /dev/null and b/Proposals/.DS_Store differ diff --git a/Proposals/Chris/.DS_Store b/Proposals/Chris/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f5ba65c9459514dcc1c0f74d2dfae2553fa06873 Binary files /dev/null and b/Proposals/Chris/.DS_Store differ diff --git a/src/sandbox/.classpath b/src/sandbox/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..ac37fb2e4bca5ec7510383d7e55ea7b6b759e05a --- /dev/null +++ b/src/sandbox/.classpath @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/src/sandbox/.project b/src/sandbox/.project new file mode 100644 index 0000000000000000000000000000000000000000..ff1db54e8e75fcedb2a0b27c0661b0b6c87fc009 --- /dev/null +++ b/src/sandbox/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>sandbox</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/src/sandbox/GeneralCompare.java b/src/sandbox/GeneralCompare.java new file mode 100644 index 0000000000000000000000000000000000000000..9e7584c7399a163c5ff6ef9ec6c98829ce1735dc --- /dev/null +++ b/src/sandbox/GeneralCompare.java @@ -0,0 +1,6 @@ +package sandbox; + +public interface GeneralCompare { + public int eval(Comparable a1, Comparable a2); + +} diff --git a/src/sandbox/TestLambdas.java b/src/sandbox/TestLambdas.java index 69ac2bc4ac76ff8d89bbf350715f975842e96eef..91dc35c0120ef2193dd16f11cc8e5e4a4c8f975e 100644 --- a/src/sandbox/TestLambdas.java +++ b/src/sandbox/TestLambdas.java @@ -7,9 +7,9 @@ package sandbox; public class TestLambdas { public static void main(String[] args) { //declare the instances of BinaryIntExpression - BinaryIntExpression b0; - BinaryIntExpression b1; - BinaryIntExpression b2; + GeneralCompare<Integer> b0; + GeneralCompare<Integer> b1; + GeneralCompare<Integer> b2; BinaryIntExpression b3; BinaryIntExpression b4; BinaryIntExpression b5; @@ -34,13 +34,13 @@ public class TestLambdas { }; //call the main function using the instances as a parameter. - result = binaryOperation(1,2,b0); + result = binaryIntegerOperation(1,2,b0); System.out.println(result); - result = binaryOperation(1,2,b1); + result = binaryIntegerOperation(1,2,b1); System.out.println(result); - result = binaryOperation(1,2,b2); + result = binaryIntegerOperation(1,2,b2); System.out.println(result); result = binaryOperation(1,2,b3); @@ -61,4 +61,9 @@ public class TestLambdas { return exp.eval(a1, a2); } + public static int binaryIntegerOperation(int a1, int a2, GeneralCompare<Integer> exp) { + //call the eval() function in the given BinaryIntExpression. + return exp.eval(a1, a2); + } + } diff --git a/src/search/CC.java b/src/search/CC.java new file mode 100644 index 0000000000000000000000000000000000000000..7726bac67040148ddff0916c89ef584aa57ac3fc --- /dev/null +++ b/src/search/CC.java @@ -0,0 +1,50 @@ +package search; + +public class CC { + + private boolean[] marked; + private int[] id; + private int count; + + public static void main(String[] args) { + Graph g = new Graph(5); + g.addEdge(4, 3); + g.addEdge(2, 3); + g.addEdge(1, 2); + g.addEdge(0, 2); + CC component = new CC(g); + System.out.println(component.connected(0, 2)); + } + + public CC(Graph G){ + marked = new boolean[G.V()]; + id = new int[G.V()]; + for(int s = 0; s < G.V(); s++){ + if(!marked[s]){ + dfs(G,s); + count++; + } + } + } + + private void dfs(Graph G, int v){ + marked[v] = true; + id[v] = count; + for(int w : G.adj(v)){ + if(!marked[w]) + dfs(G, w); + } + } + + public boolean connected(int v, int w){ + return id[v] == id[w]; + } + + public int id(int v){ + return id[v]; + } + + public int count(){ + return count; + } +} diff --git a/src/search/DepthFirstSearch.java b/src/search/DepthFirstSearch.java new file mode 100644 index 0000000000000000000000000000000000000000..000a3e93fbee5c6246a3cbeb2683973a2f6da02f --- /dev/null +++ b/src/search/DepthFirstSearch.java @@ -0,0 +1,39 @@ +package search; + +public class DepthFirstSearch { + + private boolean[] marked; + private int count; + + public static void main(String[] args) { + + Graph g = new Graph(5); + g.addEdge(4, 3); + g.addEdge(2, 3); + g.addEdge(1, 2); + g.addEdge(0, 2); + DepthFirstSearch s = new DepthFirstSearch(g, g.V()); + } + + public DepthFirstSearch(Graph G, int s){ + marked = new boolean[G.V()]; + dfs(G, s); + + } + + public void dfs(Graph G, int v){ + marked[v] = true; + count++; + for(int w : G.adj(v)) + if(!marked[w]) + dfs(G, w); + } + + public boolean marked(int w){ + return marked[w]; + } + + public int count(){ + return count; + } +} diff --git a/src/search/Field.java b/src/search/Field.java new file mode 100644 index 0000000000000000000000000000000000000000..46c5d2179860ef9ba54f7c1d77bb965d9fef3a60 --- /dev/null +++ b/src/search/Field.java @@ -0,0 +1,7 @@ +package search; + +// The interface for a function that returns one field (piece of data) from a record +public interface Field<Key, Value> { + public Comparable<Key> field(Value a1); +} + diff --git a/src/search/Fish.java b/src/search/Fish.java new file mode 100644 index 0000000000000000000000000000000000000000..3cc9e20d05861a7b7d65b829a30d00becee1de9b --- /dev/null +++ b/src/search/Fish.java @@ -0,0 +1,49 @@ +package search; + +import java.util.Iterator; + +public class Fish<Integer> implements Iterable<Integer> { + + private Node first; + + private class Node{ + Integer item; + Node next; + } + + public void add(Integer item){ + Node oldfirst = first; + first = new Node(); + first.item = item; + first.next = oldfirst; + } + + @Override + public Iterator<Integer> iterator() { + return new ListIterator(); + } + + private class ListIterator implements Iterator<Integer>{ + + private Node current = first; + + public boolean hasNext(){ + return current != null; + } + public void remove(){ + current.next = current.next.next; + } + public Integer next(){ + + Integer item = current.item; + current = current.next; + return item; + + } + } + + + + + +} diff --git a/src/search/GeneralCompare.java b/src/search/GeneralCompare.java new file mode 100644 index 0000000000000000000000000000000000000000..215fddf629ae39a3fec841758c91034af5e200f2 --- /dev/null +++ b/src/search/GeneralCompare.java @@ -0,0 +1,5 @@ +package search; + +public interface GeneralCompare<T> { + public int compare(Comparable<T> a1, Comparable<T> a2); +} diff --git a/src/search/Graph.java b/src/search/Graph.java new file mode 100644 index 0000000000000000000000000000000000000000..093a437d93bbdb0074f1ea138e5359fb9c72e972 --- /dev/null +++ b/src/search/Graph.java @@ -0,0 +1,45 @@ +package search; + +public class Graph { + + private final int V; // Number of nodes + private int E; // Number of edges + private Fish<Integer>[] adj; // Adjacency list for a node + + public static void main(String[] args) { + + Graph g = new Graph(5); + g.addEdge(4, 3); + g.addEdge(2, 3); + g.addEdge(1, 2); + g.addEdge(0, 2); + for(int i = 0; i < 5; i++) + System.out.println(g.adj(i)); + } + + public Graph(int V){ + this.V = V; + this.E = 0; + adj = (Fish<Integer>[]) new Fish[V]; + for(int v = 0; v < V; v++) + adj[v] = new Fish<Integer>(); + } + + public int V(){ + return V; + } + + public int E(){ + return E; + } + + public void addEdge(int v, int w){ + adj[v].add(w); + adj[w].add(v); + E++; + } + + public Iterable<Integer> adj(int V){ + return adj[V]; + } +} diff --git a/src/search/In.java b/src/search/In.java new file mode 100644 index 0000000000000000000000000000000000000000..f9fe5bbd6f86ff16949b2ec06eb178d6e54e7f2f --- /dev/null +++ b/src/search/In.java @@ -0,0 +1,731 @@ +package search; + +import java.io.*; +import java.util.*; +import java.util.regex.Pattern; +import java.net.*; + +public final class In { + + ///// begin: section (1 of 2) of code duplicated from In to StdIn. + + // assume Unicode UTF-8 encoding + private static final String CHARSET_NAME = "UTF-8"; + + // assume language = English, country = US for consistency with System.out. + private static final Locale LOCALE = Locale.US; + + // the default token separator; we maintain the invariant that this value + // is held by the scanner's delimiter between calls + private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\p{javaWhitespace}+"); + + // makes whitespace characters significant + private static final Pattern EMPTY_PATTERN = Pattern.compile(""); + + // used to read the entire input. source: + // http://weblogs.java.net/blog/pat/archive/2004/10/stupid_scanner_1.html + private static final Pattern EVERYTHING_PATTERN = Pattern.compile("\\A"); + + //// end: section (1 of 2) of code duplicated from In to StdIn. + + private Scanner scanner; + + /** + * Initializes an input stream from standard input. + */ + public In() { + scanner = new Scanner(new BufferedInputStream(System.in), CHARSET_NAME); + scanner.useLocale(LOCALE); + } + + /** + * Initializes an input stream from a socket. + * + * @param socket the socket + * @throws IllegalArgumentException if cannot open {@code socket} + * @throws IllegalArgumentException if {@code socket} is {@code null} + */ + public In(Socket socket) { + if (socket == null) throw new IllegalArgumentException("socket argument is null"); + try { + InputStream is = socket.getInputStream(); + scanner = new Scanner(new BufferedInputStream(is), CHARSET_NAME); + scanner.useLocale(LOCALE); + } + catch (IOException ioe) { + throw new IllegalArgumentException("Could not open " + socket, ioe); + } + } + + /** + * Initializes an input stream from a URL. + * + * @param url the URL + * @throws IllegalArgumentException if cannot open {@code url} + * @throws IllegalArgumentException if {@code url} is {@code null} + */ + public In(URL url) { + if (url == null) throw new IllegalArgumentException("url argument is null"); + try { + URLConnection site = url.openConnection(); + InputStream is = site.getInputStream(); + scanner = new Scanner(new BufferedInputStream(is), CHARSET_NAME); + scanner.useLocale(LOCALE); + } + catch (IOException ioe) { + throw new IllegalArgumentException("Could not open " + url, ioe); + } + } + + /** + * Initializes an input stream from a file. + * + * @param file the file + * @throws IllegalArgumentException if cannot open {@code file} + * @throws IllegalArgumentException if {@code file} is {@code null} + */ + public In(File file) { + if (file == null) throw new IllegalArgumentException("file argument is null"); + try { + // for consistency with StdIn, wrap with BufferedInputStream instead of use + // file as argument to Scanner + FileInputStream fis = new FileInputStream(file); + scanner = new Scanner(new BufferedInputStream(fis), CHARSET_NAME); + scanner.useLocale(LOCALE); + } + catch (IOException ioe) { + throw new IllegalArgumentException("Could not open " + file, ioe); + } + } + + + /** + * Initializes an input stream from a filename or web page name. + * + * @param name the filename or web page name + * @throws IllegalArgumentException if cannot open {@code name} as + * a file or URL + * @throws IllegalArgumentException if {@code name} is {@code null} + */ + public In(String name) { + if (name == null) throw new IllegalArgumentException("argument is null"); + try { + // first try to read file from local file system + File file = new File(name); + if (file.exists()) { + // for consistency with StdIn, wrap with BufferedInputStream instead of use + // file as argument to Scanner + FileInputStream fis = new FileInputStream(file); + scanner = new Scanner(new BufferedInputStream(fis), CHARSET_NAME); + scanner.useLocale(LOCALE); + return; + } + + // next try for files included in jar + URL url = getClass().getResource(name); + + // try this as well + if (url == null) { + url = getClass().getClassLoader().getResource(name); + } + + // or URL from web + if (url == null) { + url = new URL(name); + } + + URLConnection site = url.openConnection(); + + // in order to set User-Agent, replace above line with these two + // HttpURLConnection site = (HttpURLConnection) url.openConnection(); + // site.addRequestProperty("User-Agent", "Mozilla/4.76"); + + InputStream is = site.getInputStream(); + scanner = new Scanner(new BufferedInputStream(is), CHARSET_NAME); + scanner.useLocale(LOCALE); + } + catch (IOException ioe) { + throw new IllegalArgumentException("Could not open " + name, ioe); + } + } + + /** + * Initializes an input stream from a given {@link Scanner} source; use with + * {@code new Scanner(String)} to read from a string. + * <p> + * Note that this does not create a defensive copy, so the + * scanner will be mutated as you read on. + * + * @param scanner the scanner + * @throws IllegalArgumentException if {@code scanner} is {@code null} + */ + public In(Scanner scanner) { + if (scanner == null) throw new IllegalArgumentException("scanner argument is null"); + this.scanner = scanner; + } + + /** + * Returns true if this input stream exists. + * + * @return {@code true} if this input stream exists; {@code false} otherwise + */ + public boolean exists() { + return scanner != null; + } + + //// begin: section (2 of 2) of code duplicated from In to StdIn, + //// with all methods changed from "public" to "public static". + + /** + * Returns true if input stream is empty (except possibly whitespace). + * Use this to know whether the next call to {@link #readString()}, + * {@link #readDouble()}, etc will succeed. + * + * @return {@code true} if this input stream is empty (except possibly whitespace); + * {@code false} otherwise + */ + public boolean isEmpty() { + return !scanner.hasNext(); + } + + /** + * Returns true if this input stream has a next line. + * Use this method to know whether the + * next call to {@link #readLine()} will succeed. + * This method is functionally equivalent to {@link #hasNextChar()}. + * + * @return {@code true} if this input stream has more input (including whitespace); + * {@code false} otherwise + */ + public boolean hasNextLine() { + return scanner.hasNextLine(); + } + + /** + * Returns true if this input stream has more input (including whitespace). + * Use this method to know whether the next call to {@link #readChar()} will succeed. + * This method is functionally equivalent to {@link #hasNextLine()}. + * + * @return {@code true} if this input stream has more input (including whitespace); + * {@code false} otherwise + */ + public boolean hasNextChar() { + scanner.useDelimiter(EMPTY_PATTERN); + boolean result = scanner.hasNext(); + scanner.useDelimiter(WHITESPACE_PATTERN); + return result; + } + + + /** + * Reads and returns the next line in this input stream. + * + * @return the next line in this input stream; {@code null} if no such line + */ + public String readLine() { + String line; + try { + line = scanner.nextLine(); + } + catch (NoSuchElementException e) { + line = null; + } + return line; + } + + /** + * Reads and returns the next character in this input stream. + * + * @return the next {@code char} in this input stream + * @throws NoSuchElementException if the input stream is empty + */ + public char readChar() { + scanner.useDelimiter(EMPTY_PATTERN); + try { + String ch = scanner.next(); + assert ch.length() == 1 : "Internal (Std)In.readChar() error!" + + " Please contact the authors."; + scanner.useDelimiter(WHITESPACE_PATTERN); + return ch.charAt(0); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'char' value from input stream, but there are no more tokens available"); + } + } + + + /** + * Reads and returns the remainder of this input stream, as a string. + * + * @return the remainder of this input stream, as a string + */ + public String readAll() { + if (!scanner.hasNextLine()) + return ""; + + String result = scanner.useDelimiter(EVERYTHING_PATTERN).next(); + // not that important to reset delimeter, since now scanner is empty + scanner.useDelimiter(WHITESPACE_PATTERN); // but let's do it anyway + return result; + } + + + /** + * Reads the next token from this input stream and returns it as a {@code String}. + * + * @return the next {@code String} in this input stream + * @throws NoSuchElementException if the input stream is empty + */ + public String readString() { + try { + return scanner.next(); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'String' value from input stream, but there are no more tokens available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code int}, + * and returns the {@code int}. + * + * @return the next {@code int} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as an {@code int} + */ + public int readInt() { + try { + return scanner.nextInt(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read an 'int' value from input stream, but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read an 'int' value from input stream, but there are no more tokens available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code double}, + * and returns the {@code double}. + * + * @return the next {@code double} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code double} + */ + public double readDouble() { + try { + return scanner.nextDouble(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'double' value from input stream, but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read a 'double' value from input stream, but there are no more tokens available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code float}, + * and returns the {@code float}. + * + * @return the next {@code float} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code float} + */ + public float readFloat() { + try { + return scanner.nextFloat(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'float' value from input stream, but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read a 'float' value from input stream, but there are no more tokens available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code long}, + * and returns the {@code long}. + * + * @return the next {@code long} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code long} + */ + public long readLong() { + try { + return scanner.nextLong(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'long' value from input stream, but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read a 'long' value from input stream, but there are no more tokens available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code short}, + * and returns the {@code short}. + * + * @return the next {@code short} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code short} + */ + public short readShort() { + try { + return scanner.nextShort(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'short' value from input stream, but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read a 'short' value from input stream, but there are no more tokens available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code byte}, + * and returns the {@code byte}. + * <p> + * To read binary data, use {@link BinaryIn}. + * + * @return the next {@code byte} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code byte} + */ + public byte readByte() { + try { + return scanner.nextByte(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'byte' value from input stream, but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read a 'byte' value from input stream, but there are no more tokens available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code boolean} + * (interpreting either {@code "true"} or {@code "1"} as {@code true}, + * and either {@code "false"} or {@code "0"} as {@code false}). + * + * @return the next {@code boolean} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code boolean} + */ + public boolean readBoolean() { + try { + String token = readString(); + if ("true".equalsIgnoreCase(token)) return true; + if ("false".equalsIgnoreCase(token)) return false; + if ("1".equals(token)) return true; + if ("0".equals(token)) return false; + throw new InputMismatchException("attempts to read a 'boolean' value from input stream, but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'boolean' value from input stream, but there are no more tokens available"); + } + } + + /** + * Reads all remaining tokens from this input stream and returns them as + * an array of strings. + * + * @return all remaining tokens in this input stream, as an array of strings + */ + public String[] readAllStrings() { + // we could use readAll.trim().split(), but that's not consistent + // since trim() uses characters 0x00..0x20 as whitespace + String[] tokens = WHITESPACE_PATTERN.split(readAll()); + if (tokens.length == 0 || tokens[0].length() > 0) + return tokens; + String[] decapitokens = new String[tokens.length-1]; + for (int i = 0; i < tokens.length-1; i++) + decapitokens[i] = tokens[i+1]; + return decapitokens; + } + + /** + * Reads all remaining lines from this input stream and returns them as + * an array of strings. + * + * @return all remaining lines in this input stream, as an array of strings + */ + public String[] readAllLines() { + ArrayList<String> lines = new ArrayList<String>(); + while (hasNextLine()) { + lines.add(readLine()); + } + return lines.toArray(new String[lines.size()]); + } + + + /** + * Reads all remaining tokens from this input stream, parses them as integers, + * and returns them as an array of integers. + * + * @return all remaining lines in this input stream, as an array of integers + */ + public int[] readAllInts() { + String[] fields = readAllStrings(); + int[] vals = new int[fields.length]; + for (int i = 0; i < fields.length; i++) + vals[i] = Integer.parseInt(fields[i]); + return vals; + } + + /** + * Reads all remaining tokens from this input stream, parses them as longs, + * and returns them as an array of longs. + * + * @return all remaining lines in this input stream, as an array of longs + */ + public long[] readAllLongs() { + String[] fields = readAllStrings(); + long[] vals = new long[fields.length]; + for (int i = 0; i < fields.length; i++) + vals[i] = Long.parseLong(fields[i]); + return vals; + } + + /** + * Reads all remaining tokens from this input stream, parses them as doubles, + * and returns them as an array of doubles. + * + * @return all remaining lines in this input stream, as an array of doubles + */ + public double[] readAllDoubles() { + String[] fields = readAllStrings(); + double[] vals = new double[fields.length]; + for (int i = 0; i < fields.length; i++) + vals[i] = Double.parseDouble(fields[i]); + return vals; + } + + ///// end: section (2 of 2) of code duplicated from In to StdIn */ + + /** + * Closes this input stream. + */ + public void close() { + scanner.close(); + } + + /** + * Reads all integers from a file and returns them as + * an array of integers. + * + * @param filename the name of the file + * @return the integers in the file + * @deprecated Replaced by {@code new In(filename)}.{@link #readAllInts()}. + */ + @Deprecated + public static int[] readInts(String filename) { + return new In(filename).readAllInts(); + } + + /** + * Reads all doubles from a file and returns them as + * an array of doubles. + * + * @param filename the name of the file + * @return the doubles in the file + * @deprecated Replaced by {@code new In(filename)}.{@link #readAllDoubles()}. + */ + @Deprecated + public static double[] readDoubles(String filename) { + return new In(filename).readAllDoubles(); + } + + /** + * Reads all strings from a file and returns them as + * an array of strings. + * + * @param filename the name of the file + * @return the strings in the file + * @deprecated Replaced by {@code new In(filename)}.{@link #readAllStrings()}. + */ + @Deprecated + public static String[] readStrings(String filename) { + return new In(filename).readAllStrings(); + } + + /** + * Reads all integers from standard input and returns them + * an array of integers. + * + * @return the integers on standard input + * @deprecated Replaced by {@link StdIn#readAllInts()}. + */ + @Deprecated + public static int[] readInts() { + return new In().readAllInts(); + } + + /** + * Reads all doubles from standard input and returns them as + * an array of doubles. + * + * @return the doubles on standard input + * @deprecated Replaced by {@link StdIn#readAllDoubles()}. + */ + @Deprecated + public static double[] readDoubles() { + return new In().readAllDoubles(); + } + + /** + * Reads all strings from standard input and returns them as + * an array of strings. + * + * @return the strings on standard input + * @deprecated Replaced by {@link StdIn#readAllStrings()}. + */ + @Deprecated + public static String[] readStrings() { + return new In().readAllStrings(); + } + + /** + * Unit tests the {@code In} data type. + * + * @param args the command-line arguments + */ + public static void main(String[] args) { + In in; + String urlName = "https://introcs.cs.princeton.edu/stdlib/InTest.txt"; + + // read from a URL + System.out.println("readAll() from URL " + urlName); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In(urlName); + System.out.println(in.readAll()); + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + // read one line at a time from URL + System.out.println("readLine() from URL " + urlName); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In(urlName); + while (!in.isEmpty()) { + String s = in.readLine(); + System.out.println(s); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + // read one string at a time from URL + System.out.println("readString() from URL " + urlName); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In(urlName); + while (!in.isEmpty()) { + String s = in.readString(); + System.out.println(s); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + + // read one line at a time from file in current directory + System.out.println("readLine() from current directory"); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In("./InTest.txt"); + while (!in.isEmpty()) { + String s = in.readLine(); + System.out.println(s); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + + // read one line at a time from file using relative path + System.out.println("readLine() from relative path"); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In("../stdlib/InTest.txt"); + while (!in.isEmpty()) { + String s = in.readLine(); + System.out.println(s); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + // read one char at a time + System.out.println("readChar() from file"); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In("InTest.txt"); + while (!in.isEmpty()) { + char c = in.readChar(); + System.out.print(c); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + System.out.println(); + + // read one line at a time from absolute OS X / Linux path + System.out.println("readLine() from absolute OS X / Linux path"); + System.out.println("---------------------------------------------------------------------------"); + in = new In("/n/fs/introcs/www/java/stdlib/InTest.txt"); + try { + while (!in.isEmpty()) { + String s = in.readLine(); + System.out.println(s); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + + // read one line at a time from absolute Windows path + System.out.println("readLine() from absolute Windows path"); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In("G:\\www\\introcs\\stdlib\\InTest.txt"); + while (!in.isEmpty()) { + String s = in.readLine(); + System.out.println(s); + } + System.out.println(); + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + } + +} \ No newline at end of file diff --git a/src/search/Node.java b/src/search/Node.java new file mode 100644 index 0000000000000000000000000000000000000000..b661f73b6f20207437721739e1f00aa98acf07dd --- /dev/null +++ b/src/search/Node.java @@ -0,0 +1,113 @@ +package search; + +// An abstract data type that represents a node in a Red Black Search Tree +public class Node<Key, Value>{ + + private final Comparable<Key> key; + private Value val; + private Node<Key, Value> left, right; + private int n; + private boolean color; + + /** + * Constructor + * @param key Used to assign order amongst the nodes/implement comparability + * @param val The value stored at a node + * @param n How many nodes are in the subtree beneath this node (inclusive) + * @param color True represents a red connection between the current node and its parent, black represents false + */ + public Node(Comparable<Key> key, Value val, int n, boolean color){ + this.key = key; + this.val = val; + this.n = n; + this.color = color; + } + + /** + * Getter for a node's key + * @return The node's key + */ + public Comparable<Key> key(){ + return this.key; + } + + /** + * Getter for a node's value + * @return The node's value + */ + public Value val(){ + return this.val; + } + + /** + * Setter for a node's value + * @param val New value being assigned + */ + public void val(Value val){ + this.val = val; + } + + /** + * Getter for a node's left child + * @return The node's left child + */ + public Node<Key, Value> left(){ + return this.left; + } + + /** + * Setter for a node's left child + * @param left The node's new left child + */ + public void left(Node<Key, Value> left){ + this.left = left; + } + + /** + * Getter for a node's right child + * @return The node's right child + */ + public Node<Key, Value> right(){ + return this.right; + } + + /** + * Setter for a node's right child + * @param left The node's new right child + */ + public void right(Node<Key, Value> right){ + this.right = right; + } + + /** + * Getter for the subtree size beneath the current node + * @return Subtree size + */ + public int n(){ + return this.n; + } + + /** + * Setter for a subtree's size + * @param n New subtree size + */ + public void n(int n){ + this.n = n; + } + + /** + * Getter method for a node's color + * @return The node's color + */ + public boolean color(){ + return this.color; + } + + /** + * Setter for a node's color + * @param color New node color + */ + public void color(boolean color){ + this.color = color; + } +} diff --git a/src/search/RedBlackTree.java b/src/search/RedBlackTree.java new file mode 100644 index 0000000000000000000000000000000000000000..8d5728ef2d2d6a3315e9da2dabed2353e89b5002 --- /dev/null +++ b/src/search/RedBlackTree.java @@ -0,0 +1,184 @@ +package search; + +public class RedBlackTree<Key, Value> { + private Node<Key, Value> root; // Root of the tree + private GeneralCompare<Key> compare; + private Field<Key, Value> field; + + // Main method only used for testing + + public static void main(String[] args) { + GeneralCompare<Integer> b1; + b1 = (a1, a2) -> (Integer) a1 - (Integer) a2; + Field<Integer, Integer[]> fld; + fld = (a1) -> (Integer) a1[0]; + + + Integer[][] x = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7}, {8, 8}, {9, 9}}; + RedBlackTree<Integer, Integer[]> myTree = new RedBlackTree<Integer, Integer[]>(fld, b1); + for(int i = 0; i < x.length; i++){ + myTree.put(x[i]); + } + Node h = myTree.root(); + System.out.println(h.key()); + while (h.left() != null) { + System.out.println(h.left().key()); + h = h.left(); + } + } + + + /** + * Constructor for a red black tree object + * @param fld A function that retrieves the desired field from an array of comparable items + * @param gc A function that compares two comparable items + */ + public RedBlackTree(Field<Key, Value> fld, GeneralCompare<Key> gc) { + compare = gc; + field = fld; + } + + /** + * Getter method for the root of a tree + * @return The root of a tree object + */ + public Node<Key, Value> root() { + return root; + } + + /** + * Wrapper method for adding a new node + * @param val A new record + */ + public void put(Value val){ + Node<Key, Value> newNode = new Node<Key, Value>(field.field(val), val, 1, true); + root = put(root, newNode); + } + + /** + * Adds a new node to an existing tree + * @param h An existing node on the tree + * @param newNode A node to be added to the tree + * @return + */ + private Node<Key, Value> put(Node<Key, Value> h, Node<Key, Value> newNode){ + // Placing the first node in a tree + if (root == null) { + root = newNode; + root.color(false); + return root; + } + + // Place new element in the tree + int cmp = compare.compare(newNode.key(), h.key()); + if (cmp < 0 && (h.left() == null)) + h.left(newNode); + else if (cmp < 0 ) + h.left(put(h.left(), newNode)); + else if (cmp > 0 && (h.right() == null)) + h.right(newNode); + else if (cmp > 0) + h.right(put(h.right(), newNode)); + else + h = newNode; + + // Rearrange the tree to maintain balance + if(h.n() > 2){ + if(isRed(h.right()) && !isRed(h.left())) + h = rotateLeft(h); + if(isRed(h.left()) && isRed(h.left().left())) + h = rotateRight(h); + if(isRed(h.left()) && isRed(h.right())) + flipColors(h); + } + + // Increment how many nodes are in a subtree + if ((h.left() != null) && (h.right() != null)) + h.n(h.left().n() + h.right().n() + 1); + else if (h.left() != null) + h.n(h.left().n() + 1); + else if (h.right() != null) + h.n(h.right().n() + 1); + else + h.n(1); + + return h; + } + + /** + * Check if the link to a node's parent is red + * @param x Node in a tree + * @return Boolean result of whether the node is red or not + */ + private boolean isRed(Node<Key, Value> x){ + if (x == null) + return false; + return x.color(); + } + + /** + * Rotates a subtree in a counterclockwise direction + * @param h Root of a tree segment to be rotated + * @return New root of the rotated segment + */ + public Node<Key, Value> rotateLeft(Node<Key, Value> h){ + System.out.println("Rotate left!"); + Node<Key, Value> x = h.right(); + h.right(x.left()); + x.left(h); + x.color(h.color()); + h.color(true); + x.n(h.n()); + + // Increment how many nodes are in a subtree + if (h.left() != null & h.right() != null) + h.n(h.left().n() + h.right().n() + 1); + else if (h.left() != null) + h.n(h.left().n() + 1); + else if (h.right() != null) + h.n(h.right().n() + 1); + else + h.n(1); + + return x; + } + + /** + * Rotates a subtree in a clockwise direction + * @param h Root of a tree segment to be rotated + * @return New root of the rotated segment + */ + public Node<Key, Value> rotateRight(Node<Key, Value> h){ + Node<Key, Value> x = h.left(); + h.left(x.right()); + x.right(h); + x.color(h.color()); + h.color(true); + x.n(h.n()); + + // Increment how many nodes are in a subtree + if (h.left() != null & h.right() != null) + h.n(h.left().n() + h.right().n() + 1); + else if (h.left() != null) + h.n(h.left().n() + 1); + else if (h.right() != null) + h.n(h.right().n() + 1); + else + h.n(1); + + return x; + + } + + /** + * Changes two red connections from a single node to black + * @param h Root of tree segment whose colors are to be switched + */ + private void flipColors(Node<Key, Value> h){ + if(h.left() != null && h.right() != null){ + h.left().color(false); + h.right().color(false); + h.color(true); + } + } +} \ No newline at end of file diff --git a/src/sort/Bound.java b/src/sort/Bound.java index 990bac2766133a87334256150c9108509b01fb03..2a9e9eb6f23a0dda65b3ff21ebab77de21c0e260 100644 --- a/src/sort/Bound.java +++ b/src/sort/Bound.java @@ -1,5 +1,5 @@ -package sort; +package sort; public enum Bound { LOWER, UPPER, LOWHIGH, ANY, EQUALS; -} +} diff --git a/src/sort/KDT.java b/src/sort/KDT.java index 8709fc5cb21d0a07f24894f66fe353053f7ed7bc..3e9f11395813107dbfa9e981689fdc378a70f361 100644 --- a/src/sort/KDT.java +++ b/src/sort/KDT.java @@ -1,217 +1,217 @@ -package sort; - -import sandbox.Point; - -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.ArrayList; - -public class KDT<KeyVal extends Comparable<KeyVal>> implements Serializable { - /** - * - */ - private static final long serialVersionUID = 8807259801436570835L; - /** - * - */ - KDNode root; - ArrayList<GeneralCompare<KeyVal>> axes; - - public static void main(String[] args) { - GeneralCompare<Point> compX = (p1, p2) -> ((Point) p1).getX() - ((Point) p2).getX(); - GeneralCompare<Point> compY = (p1, p2) -> ((Point) p1).getY() - ((Point) p2).getY(); - - //(2,3), (4,7), (5,4), (7,2), (8,1), (9,6) - //(8,1), (7,2), (2,3), (5,4), (9,6), (4,7) - Point p1 = new Point(2,3); - Point p2 = new Point(5,4); - Point p3 = new Point(9,6); - Point p4 = new Point(4,7); - Point p5 = new Point(8,1); - Point p6 = new Point(7,2); - - ArrayList<GeneralCompare<Point>> axes = new ArrayList<GeneralCompare<Point>>(); - axes.add(compX); - axes.add(compY); - - Point[] pts = {p1, p2, p3, p4, p5, p6}; - - //KDT<Point> kdt = new KDT<Point>(axes, pts); - KDT<Point> kdt = new KDT<Point>("kdtree.ser"); - System.out.println(kdt.size()); - System.out.println(kdt.height()); - - //GeneralRange<Point> xRange = p -> 4 <= p.getX() && p.getX() <= 6; - //GeneralRange<Point> yRange = p -> 3 <= p.getY() && p.getY() <= 5; - - GeneralRange<Point> xRange = p -> p.getX() < 2 ? -1 : (p.getX() > 7 ? 1 : 0); - GeneralRange<Point> yRange = p -> 0;//p.getY() < 3 ? -1 : (p.getY() > 6 ? 1 : 0); - - - ArrayList<GeneralRange<Point>> ranges = new ArrayList<GeneralRange<Point>>(); - ranges.add(xRange); - ranges.add(yRange); - - Iterable<Point> results = kdt.rangeSearch(ranges); - - System.out.println("Results"); - for (Point p : results) { - System.out.println(p); - } - - System.out.println(kdt.toString()); - - kdt.writeToFile("kdtree.ser"); - } - - private class KDNode implements Serializable{ - /** - * - */ - private static final long serialVersionUID = -664511393872278542L; - /** - * - */ - private KeyVal keyval; - private KDNode left, right; - private int n; - - public KDNode(KeyVal keyval, int n) { - this.keyval = keyval; - this.n = n; - } - } - - /** - * Load a kd-tree from a serialized file. - * @param fn - */ - public KDT(String fn) { - KDT<KeyVal> kdt = null; - try { - FileInputStream fileIn = new FileInputStream(fn); - ObjectInputStream in = new ObjectInputStream(fileIn); - kdt = (KDT<KeyVal>) in.readObject(); - in.close(); - fileIn.close(); - } catch (IOException i) { - i.printStackTrace(); - } catch (ClassNotFoundException c) { - System.out.println("Employee class not found"); - c.printStackTrace(); - } - //https://stackoverflow.com/questions/26327956/set-this-in-a-class - this.root = kdt.root; - this.axes = kdt.axes; - } - - public KDT(ArrayList<GeneralCompare<KeyVal>> axes, Comparable<KeyVal>[] keyvals) { - this.axes = axes; - root = buildTree(keyvals, 0, keyvals.length - 1, 0); - } - - private KDNode buildTree(Comparable<KeyVal>[] keyvals, int lo, int hi, int depth) { - if (lo > hi) return null; - int axis = depth % getK(); - - int mid = (lo + hi) / 2; - MergeSort.sort(keyvals, lo, hi, axes.get(axis)); - KeyVal median = (KeyVal) keyvals[mid]; - - //TODO: fix size - KDNode newNode = new KDNode(median, 0); - newNode.left = buildTree(keyvals, lo, mid - 1, depth + 1); - newNode.right = buildTree(keyvals, mid + 1, hi, depth + 1); - - newNode.n = size(newNode.left) + size(newNode.right) + 1; - return newNode; - } - - public Iterable<KeyVal> rangeSearch(ArrayList<GeneralRange<KeyVal>> range){ - ArrayList<KeyVal> result = new ArrayList<KeyVal>(); - rangeSearch(root, range, result, 0); - return result; - } - - private void rangeSearch(KDNode x, ArrayList<GeneralRange<KeyVal>> range, ArrayList<KeyVal> result, int depth) { - if (x == null) return; - int axis = depth % getK(); - GeneralRange<KeyVal> rg = range.get(axis); - - //System.out.println("Try: " + x.keyval); - - int bounds = rg.isInBounds((KeyVal) x.keyval); - if (bounds == 0) { - //System.out.println(pointInside(x.keyval, range)); - if (pointInside(x.keyval, range)) { - result.add(x.keyval); - } - rangeSearch(x.left, range, result, depth + 1); - rangeSearch(x.right, range, result, depth + 1); - } else if (bounds > 0) { - rangeSearch(x.left, range, result, depth + 1); - } else if (bounds < 0) - rangeSearch(x.right, range, result, depth + 1); - - return; - } - - private boolean pointInside(KeyVal pt, ArrayList<GeneralRange<KeyVal>> range) { - for (int i = 0; i < axes.size(); i++) - if (range.get(i).isInBounds(pt) != 0) return false; - return true; - } - - public int size() { - return size(root); - } - - public int height() { - return height(root); - } - - private int height(KDNode x) { - if (x == null) return 0; - return 1 + Math.max(height(x.left), height(x.right)); - } - - private int size(KDNode x) { - if (x == null) return 0; - else return x.n; - } - - public int getK() { - return axes.size(); - } - - public String toString() { - return toString(root, ""); - } - - public void writeToFile(String fn) { - try { - FileOutputStream fileOut = - new FileOutputStream(fn); - ObjectOutputStream out = new ObjectOutputStream(fileOut); - out.writeObject(this); - out.close(); - fileOut.close(); - System.out.printf("Serialized data is saved in /tmp/kdtree.ser"); - } catch (IOException i) { - i.printStackTrace(); - } - } - - private String toString(KDNode x, String depth) { - if (x == null) return depth + "null\n"; - String result = ""; - result += depth + x.keyval.toString() + "\n"; - result += toString(x.left, depth + " "); - result += toString(x.right, depth + " "); - return result; - } -} +package sort; + +import sandbox.Point; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; + +public class KDT<KeyVal extends Comparable<KeyVal>> implements Serializable { + /** + * + */ + private static final long serialVersionUID = 8807259801436570835L; + /** + * + */ + KDNode root; + ArrayList<GeneralCompare<KeyVal>> axes; + + public static void main(String[] args) { + GeneralCompare<Point> compX = (p1, p2) -> ((Point) p1).getX() - ((Point) p2).getX(); + GeneralCompare<Point> compY = (p1, p2) -> ((Point) p1).getY() - ((Point) p2).getY(); + + //(2,3), (4,7), (5,4), (7,2), (8,1), (9,6) + //(8,1), (7,2), (2,3), (5,4), (9,6), (4,7) + Point p1 = new Point(2,3); + Point p2 = new Point(5,4); + Point p3 = new Point(9,6); + Point p4 = new Point(4,7); + Point p5 = new Point(8,1); + Point p6 = new Point(7,2); + + ArrayList<GeneralCompare<Point>> axes = new ArrayList<GeneralCompare<Point>>(); + axes.add(compX); + axes.add(compY); + + Point[] pts = {p1, p2, p3, p4, p5, p6}; + + //KDT<Point> kdt = new KDT<Point>(axes, pts); + KDT<Point> kdt = new KDT<Point>("kdtree.ser"); + System.out.println(kdt.size()); + System.out.println(kdt.height()); + + //GeneralRange<Point> xRange = p -> 4 <= p.getX() && p.getX() <= 6; + //GeneralRange<Point> yRange = p -> 3 <= p.getY() && p.getY() <= 5; + + GeneralRange<Point> xRange = p -> p.getX() < 2 ? -1 : (p.getX() > 7 ? 1 : 0); + GeneralRange<Point> yRange = p -> 0;//p.getY() < 3 ? -1 : (p.getY() > 6 ? 1 : 0); + + + ArrayList<GeneralRange<Point>> ranges = new ArrayList<GeneralRange<Point>>(); + ranges.add(xRange); + ranges.add(yRange); + + Iterable<Point> results = kdt.rangeSearch(ranges); + + System.out.println("Results"); + for (Point p : results) { + System.out.println(p); + } + + System.out.println(kdt.toString()); + + kdt.writeToFile("kdtree.ser"); + } + + private class KDNode implements Serializable{ + /** + * + */ + private static final long serialVersionUID = -664511393872278542L; + /** + * + */ + private KeyVal keyval; + private KDNode left, right; + private int n; + + public KDNode(KeyVal keyval, int n) { + this.keyval = keyval; + this.n = n; + } + } + + /** + * Load a kd-tree from a serialized file. + * @param fn + */ + public KDT(String fn) { + KDT<KeyVal> kdt = null; + try { + FileInputStream fileIn = new FileInputStream(fn); + ObjectInputStream in = new ObjectInputStream(fileIn); + kdt = (KDT<KeyVal>) in.readObject(); + in.close(); + fileIn.close(); + } catch (IOException i) { + i.printStackTrace(); + } catch (ClassNotFoundException c) { + System.out.println("Employee class not found"); + c.printStackTrace(); + } + //https://stackoverflow.com/questions/26327956/set-this-in-a-class + this.root = kdt.root; + this.axes = kdt.axes; + } + + public KDT(ArrayList<GeneralCompare<KeyVal>> axes, Comparable<KeyVal>[] keyvals) { + this.axes = axes; + root = buildTree(keyvals, 0, keyvals.length - 1, 0); + } + + private KDNode buildTree(Comparable<KeyVal>[] keyvals, int lo, int hi, int depth) { + if (lo > hi) return null; + int axis = depth % getK(); + + int mid = (lo + hi) / 2; + MergeSort.sort(keyvals, lo, hi, axes.get(axis)); + KeyVal median = (KeyVal) keyvals[mid]; + + //TODO: fix size + KDNode newNode = new KDNode(median, 0); + newNode.left = buildTree(keyvals, lo, mid - 1, depth + 1); + newNode.right = buildTree(keyvals, mid + 1, hi, depth + 1); + + newNode.n = size(newNode.left) + size(newNode.right) + 1; + return newNode; + } + + public Iterable<KeyVal> rangeSearch(ArrayList<GeneralRange<KeyVal>> range){ + ArrayList<KeyVal> result = new ArrayList<KeyVal>(); + rangeSearch(root, range, result, 0); + return result; + } + + private void rangeSearch(KDNode x, ArrayList<GeneralRange<KeyVal>> range, ArrayList<KeyVal> result, int depth) { + if (x == null) return; + int axis = depth % getK(); + GeneralRange<KeyVal> rg = range.get(axis); + + //System.out.println("Try: " + x.keyval); + + int bounds = rg.isInBounds((KeyVal) x.keyval); + if (bounds == 0) { + //System.out.println(pointInside(x.keyval, range)); + if (pointInside(x.keyval, range)) { + result.add(x.keyval); + } + rangeSearch(x.left, range, result, depth + 1); + rangeSearch(x.right, range, result, depth + 1); + } else if (bounds > 0) { + rangeSearch(x.left, range, result, depth + 1); + } else if (bounds < 0) + rangeSearch(x.right, range, result, depth + 1); + + return; + } + + private boolean pointInside(KeyVal pt, ArrayList<GeneralRange<KeyVal>> range) { + for (int i = 0; i < axes.size(); i++) + if (range.get(i).isInBounds(pt) != 0) return false; + return true; + } + + public int size() { + return size(root); + } + + public int height() { + return height(root); + } + + private int height(KDNode x) { + if (x == null) return 0; + return 1 + Math.max(height(x.left), height(x.right)); + } + + private int size(KDNode x) { + if (x == null) return 0; + else return x.n; + } + + public int getK() { + return axes.size(); + } + + public String toString() { + return toString(root, ""); + } + + public void writeToFile(String fn) { + try { + FileOutputStream fileOut = + new FileOutputStream(fn); + ObjectOutputStream out = new ObjectOutputStream(fileOut); + out.writeObject(this); + out.close(); + fileOut.close(); + System.out.printf("Serialized data is saved in /tmp/kdtree.ser"); + } catch (IOException i) { + i.printStackTrace(); + } + } + + private String toString(KDNode x, String depth) { + if (x == null) return depth + "null\n"; + String result = ""; + result += depth + x.keyval.toString() + "\n"; + result += toString(x.left, depth + " "); + result += toString(x.right, depth + " "); + return result; + } +} diff --git a/src/sort/MergeSort.java b/src/sort/MergeSort.java index defaccfa246c3f0af1d334286489f02e0307f907..836eac549e103cf15d16c4643b70abe2e8f6aac0 100644 --- a/src/sort/MergeSort.java +++ b/src/sort/MergeSort.java @@ -1,7 +1,7 @@ package sort; public class MergeSort{ - + /*// Main Function for Testing Purposes Only public static void main(String[] args) { GeneralCompare<Integer> b1; b1 = (a1, a2) -> (Integer) a1 - (Integer) a2; @@ -12,16 +12,30 @@ public class MergeSort{ for (int i = 0 ; i < (test.length) ; i++) { System.out.println(test[i]); } - } + }*/ + /** + * Wrapper function for the MergeSort implementation + * @param x Array of comparable items to be sorted + * @param lo Lower bound of a sub-array to be sorted + * @param hi Upper bound of a sub-array to be sorted + * @param gc A lambda function that compares two comparable items + */ public static <T> void sort(Comparable<T>[] x, int lo, int hi, GeneralCompare<T> gc) { Comparable<T>[] aux; aux = (Comparable<T>[]) new Comparable[x.length]; sortWrapped(x, lo, hi, gc, aux); } + /** + * Recursively sort each half of a sub-array + * @param lo + * @param hi + * @param gc + * @param aux Auxiliary array to accommodate temporary memory use in the algorithm + */ private static <T> void sortWrapped(Comparable<T>[] x, int lo, int hi, GeneralCompare<T> gc, Comparable<T>[] aux) { - int n = hi - lo; + int n = hi - lo; if(n < 1) return; // Recursively sort each half of the array @@ -31,13 +45,18 @@ public class MergeSort{ merge(x, lo, hi, gc, aux); } + /** + * Merges two sorted sub-arrays into a single sorted array + * @param x + * @param lo + * @param hi + * @param gc + * @param aux + */ private static <T> void merge(Comparable<T>[] x, int lo, int hi, GeneralCompare<T> gc, Comparable<T>[] aux){ int n = hi - lo; int mid = lo + (n/2); - - // Fill auxiliary array - //System.out.println("lo, mid, hi: " + lo + ", " + mid + ", " + hi); for(int k = lo; k <= hi; k++){ aux[k] = x[k]; diff --git a/src/sort/QuickSelect.java b/src/sort/QuickSelect.java new file mode 100644 index 0000000000000000000000000000000000000000..623352224c0c0e228cba2167722fedb2b5d63e87 --- /dev/null +++ b/src/sort/QuickSelect.java @@ -0,0 +1,105 @@ +package sort; + +import search.GeneralCompare; + +// Code from "Algorithms: 4th Edition" by Robert Sedgewick +// Adapted from the Sedgewick Quicksort implementation + +public class QuickSelect { + + /* + // Main function for testing purposes only + public static void main(String[] args) { + //{1, 2, 3, 4, 5, 6, 7, 8, 9} 5 is median. + Integer[] test = {4, 6, 7, 2, 2, 2, 2,2, 2, 2,2 ,2 ,2, 2, 2}; + GeneralCompare<Integer> b1; + b1 = (a1, a2) -> (Integer) a1 - (Integer) a2; + + median(test, b1); + System.out.println(test[test.length/2]); + } + */ + + /** + * Partially sorts a comparable array such that elements smaller than the median occur in + * the first half of the array, and elements larger than the median occur in the second half + * @param a Array of comparable items + * @param gc Lambda function to compare items + */ + public static <T> void median(Comparable<T>[] a, GeneralCompare<T> gc) { + sort(a, 0, a.length - 1, a.length/2, gc); + } + + /** + * Partially sorts a comparable array such that elements smaller than the kth largest element + * occur in the first half of the array, and larger elements occur in the second half + * @param a Array of comparable items + * @param k Pivot element that will be in its sorted place in the array + * @param gc Lambda function to compare items + */ + public static <T> void partialSort(Comparable<T>[] a, int k, GeneralCompare<T> gc) { + sort(a, 0, a.length - 1, k, gc); + } + + /** + * Sorts the half of the array containing the kth (or median) index + * @param a Array of comparable items + * @param lo Lower bound index of the subarray to be sorted + * @param hi Upper bound index of the subarray to be sorted + * @param k Pivot element that will be in its sorted place in the array + * @param gc Lambda function to compare items + */ + public static <T> void sort(Comparable<T>[] a, int lo, int hi, int k, GeneralCompare<T> gc) { + if (hi <= lo) + return; + int j = partition(a, lo, hi, gc); + if (j < k) + sort(a, j + 1, hi, k, gc); // Sort right part a[j+1 .. hi]. + else if (j > k) + sort(a, lo, j - 1, k, gc); // Sort left part a[lo .. j-1]. + return; + } + + /** + * Places elements smaller than a partitioning element at smaller indices than the partitioning element + * Same algorithm for partitioning as standard QuickSort from + * @param a Array of comparable items + * @param lo Index that scans from the left side of the array, points to an item to be compared + * @param hi Index that scans from the right side of the array, points to an item to be compared + * @param gc Lambda function to compare items + * @return + */ + private static <T> int partition(Comparable<T>[] a, int lo, int hi, GeneralCompare<T> gc) { + // Partition into a[lo..i-1], a[i], a[i+1..hi]. + int i = lo, j = hi + 1; // left and right scan indices + Comparable<T> v = a[lo]; // partitioning item + + while (true) { // Scan right, scan left, check for scan complete, and exchange. + while (gc.compare(a[++i], v) < 0) + if (i == hi) + break; + while (gc.compare(v, a[--j]) < 0) + if (j == lo) + break; + if (i >= j) + break; + exch(a, i, j); + } + + exch(a, lo, j); + return j; + } + + /** + * Exchanges the values at two indices of an array + * @param a Array of comparable items + * @param b Index of an item to be swapped + * @param c Index of an item to be swapped + */ + private static <T> void exch(Comparable<T>[] a, int b, int c) { + Comparable<T> temp = a[c]; + a[c] = a[b]; + a[b] = temp; + } + +} diff --git a/src/sort/Range.java b/src/sort/Range.java index 4ffa5e71db4df84c414b149504a36e7a32847fcc..59b943785f9b3188d8a55f6dbdd4898114a9874e 100644 --- a/src/sort/Range.java +++ b/src/sort/Range.java @@ -37,11 +37,15 @@ public class Range<Key extends Comparable<Key>> { this.boundType = bt; } +<<<<<<< HEAD + public <T> boolean inBounds(T key) { +======= <<<<<<< HEAD public <T> boolean inBounds(T key) { ======= public boolean inBounds(Key key, GeneralCompare<Key> gc) { >>>>>>> fd3aa70... add Bound and Range +>>>>>>> refs/remotes/origin/master if (boundType == Bound.ANY) return true; else if (boundType == Bound.LOWER) return gc.compare(lower, key) <= 0; else if (boundType == Bound.UPPER) return gc.compare(upper, key) >= 0;