I'm working with DFS solver on 8 puzzle game. This code print all children from the tree until the correct state, but I want to print only the correct solution.
My output:
120
345
678
125
340
678
102
345
678
125
348
670
125
304
678
142
305
678
012
345
678
Expected output:
120
345
678
102
345
678
012
345
678
Code:
public class puzzle {
public static LinkedHashSet<String> OPEN = new LinkedHashSet<String>();
public static HashSet<String> CLOSED = new HashSet<String>();
public static boolean STATE = false;
public static void main(String args[]) {
int statesVisited = 0;
String start = "120345678";
String goal = "012345678";
String X = "";
String temp = "";
OPEN.add(start);
while (OPEN.isEmpty() == false && STATE == false) {
X = OPEN.iterator().next();
OPEN.remove(X);
print(X);
int pos = X.indexOf('0'); // get position of ZERO or EMPTY SPACE
if (X.equals(goal)) {
System.out.println("SUCCESS");
STATE = true;
} else {
// generate children
CLOSED.add(X);
temp = up(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = down(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = left(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = right(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
}
}
}
/*
* MOVEMENT UP
*/
public static String up(String s, int p) {
String str = s;
if (!(p < 3)) {
char a = str.charAt(p - 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 3)) + '0' + newS.substring(p - 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT DOWN
*/
public static String down(String s, int p) {
String str = s;
if (!(p > 5)) {
char a = str.charAt(p + 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 3)) + '0' + newS.substring(p + 4);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT LEFT
*/
public static String left(String s, int p) {
String str = s;
if (p != 0 && p != 3 && p != 7) {
char a = str.charAt(p - 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 1)) + '0' + newS.substring(p);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT RIGHT
*/
public static String right(String s, int p) {
String str = s;
if (p != 2 && p != 5 && p != 8) {
char a = str.charAt(p + 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 1)) + '0' + newS.substring(p + 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
public static void print(String s) {
System.out.println(s.substring(0, 3));
System.out.println(s.substring(3, 6));
System.out.println(s.substring(6, 9));
System.out.println();
}
}
DFS returns the first path it finds. To get the shortest path use BFS.
You can use a map
private static Map<String, List<String>> paths = new HashMap<>();
to map each node (state) to the path that led to it:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
public class puzzle {
private static LinkedHashSet<String> OPEN = new LinkedHashSet<>();
private static HashSet<String> CLOSED = new HashSet<>();
private static Map<String, List<String>> paths = new HashMap<>();
public static boolean STATE = false;
public static void main(String args[]) {
String start = "120345678";
String goal = "012345678";
String X = "";
String temp = "";
OPEN.add(start);
paths.put(start, Arrays.asList(start));
while (OPEN.isEmpty() == false && STATE == false) {
X = OPEN.iterator().next();
OPEN.remove(X);
print(X);
int pos = X.indexOf('0'); // get position of ZERO or EMPTY SPACE
if (X.equals(goal)) {
System.out.println("SUCCESS" +"\n" + paths.get(X));
STATE = true;
} else {
// generate children
CLOSED.add(X);
temp = up(X, pos);
if (!temp.equals("-1")) {
OPEN.add(temp);
updatePaths(temp, paths.get(X));
}
temp = down(X, pos);
if (!temp.equals("-1")) {
OPEN.add(temp);
updatePaths(temp, paths.get(X));
}
temp = left(X, pos);
if (!temp.equals("-1")) {
OPEN.add(temp);
updatePaths(temp, paths.get(X));
}
temp = right(X, pos);
if (!temp.equals("-1")) {
OPEN.add(temp);
updatePaths(temp, paths.get(X));
}
}
}
}
static void updatePaths(String s, List<String> path){
if(paths.containsKey(s)) return;
List<String> newPath = new ArrayList<>(path);
newPath.add(s);
paths.put(s, newPath);
}
/*
* MOVEMENT UP
*/
public static String up(String s, int p) {
String str = s;
if (!(p < 3)) {
char a = str.charAt(p - 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, p - 3) + '0' + newS.substring(p - 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT DOWN
*/
public static String down(String s, int p) {
String str = s;
if (!(p > 5)) {
char a = str.charAt(p + 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, p + 3) + '0' + newS.substring(p + 4);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT LEFT
*/
public static String left(String s, int p) {
String str = s;
if (p != 0 && p != 3 && p != 7) {
char a = str.charAt(p - 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, p - 1) + '0' + newS.substring(p);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT RIGHT
*/
public static String right(String s, int p) {
String str = s;
if (p != 2 && p != 5 && p != 8) {
char a = str.charAt(p + 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, p + 1) + '0' + newS.substring(p + 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
public static void print(String s) {
System.out.println(s.substring(0, 3));
System.out.println(s.substring(3, 6));
System.out.println(s.substring(6, 9));
System.out.println();
}
}
Online code can be reviewed and executed here and a refactored version here
We need somehow save relation between steps to find only steps from successful path.
Here is my solution:
public class Puzzle {
public static LinkedHashSet<Step> open = new LinkedHashSet<>();
public static HashSet<Step> closed = new HashSet<>();
public static boolean problemSolved = false;
private static class Step {
final String data;
Step previous = null;
Step(String data) {
this.data = data;
}
Step(Step previous, String data) {
this.previous = previous;
this.data = data;
}
public String getData() {
return data;
}
public Step getPrevious() {
return previous;
}
#Override
public String toString() {
return new StringBuilder()
.append(data.substring(0, 3))
.append("\r\n")
.append(data.substring(3, 6))
.append("\r\n")
.append(data.substring(6, 9))
.toString();
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof Step)) {
return false;
}
if (obj == this) {
return true;
}
return this.getData().equals(((Step) obj).getData());
}
#Override
public int hashCode() {
return this.getData().hashCode();
}
}
public static void main(String args[]) {
int statesVisited = 0;
Step startStep = new Step("120345678");
Step goalStep = new Step("012345678");
Step currentStep;
open.add(startStep);
while (!open.isEmpty() && !problemSolved) {
currentStep = open.iterator().next();
open.remove(currentStep);
// print(currentStep);
if (currentStep.equals(goalStep)) {
System.out.println("SUCCESS PATH: \r\n");
printSuccessPath(
getSuccessPathFromFinishStep(currentStep) // here currentStep is finish step
);
problemSolved = true;
} else {
// generate children
closed.add(currentStep);
Step nextStep = up(currentStep);
if (nextStep != null) {
open.add(nextStep);
}
nextStep = down(currentStep);
if (nextStep != null) {
open.add(nextStep);
}
nextStep = left(currentStep);
if (nextStep != null) {
open.add(nextStep);
}
nextStep = right(currentStep);
if (nextStep != null) {
open.add(nextStep);
}
}
}
}
/*
* MOVEMENT UP
*/
public static Step up(Step step) {
int p = step.getData().indexOf('0');
String str = step.getData();
if (!(p < 3)) {
char a = str.charAt(p - 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 3)) + '0' + newS.substring(p - 2);
}
Step nexStep = new Step(step, str); // Creates new step with step as previous one
// Eliminates child of X if its on open or closed
if (!open.contains(nexStep) && !closed.contains(nexStep))
return nexStep;
else
return null;
}
/*
* MOVEMENT DOWN
*/
public static Step down(Step step) {
int p = step.getData().indexOf('0');
String str = step.getData();
if (!(p > 5)) {
char a = str.charAt(p + 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 3)) + '0' + newS.substring(p + 4);
}
Step nexStep = new Step(step, str); // Creates new step with step as previous one
// Eliminates child of X if its on open or closed
if (!open.contains(nexStep) && !closed.contains(nexStep))
return nexStep;
else
return null;
}
/*
* MOVEMENT LEFT
*/
public static Step left(Step step) {
int p = step.getData().indexOf('0');
String str = step.getData();
if (p != 0 && p != 3 && p != 7) {
char a = str.charAt(p - 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 1)) + '0' + newS.substring(p);
}
Step nexStep = new Step(step, str); // Creates new step with step as previous one
// Eliminates child of X if its on open or closed
if (!open.contains(nexStep) && !closed.contains(nexStep))
return nexStep;
else
return null;
}
/*
* MOVEMENT RIGHT
*/
public static Step right(Step step) {
int p = step.getData().indexOf('0');
String str = step.getData();
if (p != 2 && p != 5 && p != 8) {
char a = str.charAt(p + 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 1)) + '0' + newS.substring(p + 2);
}
Step nexStep = new Step(step, str); // Creates new step with step as previous one
// Eliminates child of X if its on open or closed
if (!open.contains(nexStep) && !closed.contains(nexStep))
return nexStep;
else
return null;
}
private static void print(Step s) {
System.out.println(s);
System.out.println();
}
private static void printSuccessPath(List<Step> successPath) {
for (Step step : successPath) {
print(step);
}
}
private static List<Step> getSuccessPathFromFinishStep(Step finishStep) {
LinkedList<Step> successPath = new LinkedList<>();
Step step = finishStep;
while (step != null) {
successPath.addFirst(step);
step = step.getPrevious();
}
return successPath;
}
}
I've refactored your code a bit. And introduced new class Step which allows us to save relation between current step and previous one.
Logic is a bit complicated, but feel free to ask additional question if something if not clear for you)
And, by the way, here is the result:
SUCCESS PATH:
120
345
678
102
345
678
012
345
678
So, a clean(er) solution that does what you've asked for looks like this:
package basic;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
public class Puzzle {
private static class Node {
private final Node previous;
private final String data;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((data == null) ? 0 : data.hashCode());
return result;
}
public Node getPrevious() {
return previous;
}
public String getData() {
return data;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (data == null) {
if (other.data != null)
return false;
} else if (!data.equals(other.data))
return false;
return true;
}
public Node(String data) {
this.data = data;
this.previous = null;
}
public Node(String data, Node previous) {
this.data = data;
this.previous = previous;
}
}
public static void main(String args[]) {
Queue<Node> open = new LinkedList<>();
Set<Node> closed = new HashSet<>();
Node start = new Node("120345678");
Node goal = new Node("012345678");
open.add(start);
boolean solving = true;
while (!open.isEmpty() && solving) {
Node current = open.poll();
int pos = current.getData().indexOf('0');
if (!closed.contains(current)) {
if (current.equals(goal)) {
printPath(current);
System.out.println("SUCCESS");
solving = false;
} else {
// generate children
up(current, pos, open, closed);
down(current, pos, open, closed);
left(current, pos, open, closed);
right(current, pos, open, closed);
closed.add(current);
}
}
}
}
/*
* MOVEMENT UP
*/
private static void up(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition >= 3) {
char substitutedChar = current.getData().charAt(zeroPosition - 3);
open.add(new Node(current.getData().substring(0, zeroPosition - 3) + '0'
+ current.getData().substring(zeroPosition - 2, zeroPosition) + substitutedChar
+ current.getData().substring(zeroPosition + 1), current));
}
}
/*
* MOVEMENT DOWN
*/
private static void down(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition <= 5) {
char substitutedChar = current.getData().charAt(zeroPosition + 3);
open.add(new Node(current.getData().substring(0, zeroPosition) + substitutedChar
+ current.getData().substring(zeroPosition + 1, zeroPosition + 3) + '0'
+ current.getData().substring(zeroPosition + 4), current));
}
}
/*
* MOVEMENT LEFT
*/
private static void left(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition % 3 != 0) {
char substitutedChar = current.getData().charAt(zeroPosition - 1);
open.add(new Node(current.getData().substring(0, zeroPosition - 1) + '0' + substitutedChar
+ current.getData().substring(zeroPosition + 1), current));
}
}
/*
* MOVEMENT RIGHT
*/
private static void right(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition % 3 != 2) {
char substitutedChar = current.getData().charAt(zeroPosition - 1);
open.add(new Node(current.getData().substring(0, zeroPosition) + substitutedChar + '0'
+ current.getData().substring(zeroPosition + 2), current));
}
}
private static void printPath(Node current) {
Stack<String> stack = new Stack<>();
for (; current != null; current = current.getPrevious()) {
stack.push(current.getData());
}
while (!stack.isEmpty()) {
print(stack.pop());
}
}
private static void print(String s) {
System.out.println(s.substring(0, 3));
System.out.println(s.substring(3, 6));
System.out.println(s.substring(6, 9));
System.out.println();
}
}
Do note that I haven't changed the basic board representation (you chose to use String, while I recommend using a 2d array, where swaps are much less costly and the code becomes easier to understand)
A few notes:
To print the entire "path" you must maintain connections between the "steps" of your solution
Avoid using globals where possible
Prefer using Interfaces (Set, Queue) as the types of your collections (and choose them based on how you would use them)
Java 8 doesn't require you to specify the concrete types used in a generic collection during construction (So use Set<String> set = new HashSet<>(); instead of using Set<String> set = new HashSet<String>();
Where possible, avoid using superfluous (and less readable) conditions / code structure (prefer if (booleanVariable) over if (booleanVariable == true)
(There are probably a few more things to take away from this, but this is a useful list to start with)
EDIT:
a version where data is a 2d array is added below
package basic;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
public class Puzzle {
private static class Node {
private final Node previous;
private final char[][] data;
public Node getPrevious() {
return previous;
}
public char[][] getData() {
return data;
}
public int getZeroX() {
return zeroX;
}
public int getZeroY() {
return zeroY;
}
private final int zeroX;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.deepHashCode(data);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (!Arrays.deepEquals(data, other.data))
return false;
return true;
}
private final int zeroY;
public Node(Node previous, char[][] data, int zeroX, int zeroY) {
super();
this.previous = previous;
this.data = data;
this.zeroX = zeroX;
this.zeroY = zeroY;
}
}
public static void main(String args[]) {
Queue<Node> open = new LinkedList<>(); //Stack<Node> open = new Stack<>();
Set<Node> closed = new HashSet<>();
Node start = new Node(null, new char[][] { { '1', '2', '0' }, { '3', '4', '5' }, { '6', '7', '8' } }, 2, 0);
Node goal = new Node(null, new char[][] { { '0', '1', '2' }, { '3', '4', '5' }, { '6', '7', '8' } }, 0, 0);
open.add(start); //open.push(start);
boolean solving = true;
while (!open.isEmpty() && solving) {
Node current = open.poll(); //open.pop();
if (!closed.contains(current)) {
if (current.equals(goal)) {
printPath(current);
System.out.println("SUCCESS");
solving = false;
} else {
// generate children
up(current, open, closed);
down(current, open, closed);
left(current, open, closed);
right(current, open, closed);
closed.add(current);
}
}
}
}
/*
* MOVEMENT UP
*/
private static void up(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroY() > 0) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY() - 1][current.getZeroX()];
chars[current.getZeroY() - 1][current.getZeroX()] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX(), current.getZeroY() - 1));
}
}
/*
* MOVEMENT DOWN
*/
private static void down(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroY() < 2) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY() + 1][current.getZeroX()];
chars[current.getZeroY() + 1][current.getZeroX()] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX(), current.getZeroY() + 1));
}
}
/*
* MOVEMENT LEFT
*/
private static void left(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroX() > 0) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY()][current.getZeroX() - 1];
chars[current.getZeroY()][current.getZeroX() - 1] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX() - 1, current.getZeroY()));
}
}
/*
* MOVEMENT RIGHT
*/
private static void right(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroX() < 2) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY()][current.getZeroX() + 1];
chars[current.getZeroY()][current.getZeroX() + 1] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX() + 1, current.getZeroY()));
}
}
private static char[][] copy(char[][] data) {
char[][] newData = new char[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
newData[i][j] = data[i][j];
}
}
return newData;
}
private static void printPath(Node current) {
Stack<char[][]> stack = new Stack<>();
for (; current != null; current = current.getPrevious()) {
stack.push(current.getData());
}
while (!stack.isEmpty()) {
print(stack.pop());
}
}
private static void print(char[][] chars) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(chars[i][j]);
}
System.out.println();
}
System.out.println();
}
}
EDIT2: added comments of changes that turn this into DFS
Good luck!
Related
Using the following input string * + 16 4 + 3 1 and these instructions:
A prefix expression is where the operator comes first. For example, +
5 7 would be 12.
I am able to successfully generate the expected output of 80 with my current code, which I will post below. However, with another input string * + 16 * + 16 4 + 3 1 + 3 1 my output is 576, where it is expected to be 384. I'm not quite sure where I went wrong with my algorithm.
public class QueueUtils {
public static Queue<String> build(String line) {
Queue<String> queue = new LinkedList<>();
Scanner scanner = new Scanner(line);
while (scanner.hasNext())
{
String token = scanner.next();
queue.add(token);
}
return queue;
}
public static int eval(Queue<String> s)
{
List<String> list = new ArrayList<>(s);
List<String> operators = new ArrayList<>();
operators.add("+");
operators.add("-");
operators.add("*");
int n = eval(list, operators);
return n;
}
private static Integer eval(List<String> list, List<String> operators)
{
for (int i = 0; i < list.size(); i++)
{
String current = list.get(i);
String prev = null;
String next = null;
String nextNext = null;
if (i != 0)
{
prev = list.get(i - 1);
}
if (i != list.size() - 1)
{
next = list.get(i + 1);
}
if (i < list.size() - 2)
{
nextNext = list.get(i + 2);
}
if (operators.contains(prev) && prev != null)
{
if (!operators.contains(current)) {
int a = Integer.parseInt(current);
if (!operators.contains(next) && next != null) {
int b = Integer.parseInt(next);
Integer result = doOperation(prev, a, b);
list.remove(current);
list.remove(next);
list.add(i, result.toString());
eval(list, operators);
}
if (next == null)
{
list.remove(prev);
}
}
else
{
if (!operators.contains(next))
{
if (operators.contains(nextNext))
{
list.remove(current);
eval(list, operators);
}
}
}
}
else
{
if (operators.contains(current))
{
if (!operators.contains(next))
{
if (operators.contains(nextNext) || nextNext == null)
{
if (prev != null)
{
list.remove(current);
eval(list, operators);
}
}
}
}
}
}
return Integer.parseInt(list.get(0));
}
private static int doOperation(String operator, int a, int b)
{
int n = 0;
if (operator.equals("+"))
{
n = a + b;
}
else if (operator.equals("-"))
{
n = a - b;
}
else if (operator.equals("*"))
{
n = a * b;
}
return n;
}
}
Calling code:
public class Demo2 {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
System.out.println("Enter an expression in prefix form (operator comes first)");
String line = keyboard.nextLine();
Queue<String> q = QueueUtils.build(line);
int result = QueueUtils.eval(q);
System.out.println(result);
}
}
So in order to solve this you need first need to reverse your input (so * + 16 * + 16 4 + 3 1 + 3 1 will become 1 3 + 1 3 + 4 16 + * 16 + *) and then use a bit of recursion to work your operations in groups of three.
So
1 3 + 1 3 + 4 16 + * 16 + *
4 4 20 * 16 + *
4 [80 16 + *] // we can't do anything with 4 4 20, so we just move on one.
4 [96 *]
4 96 *
384
Here's the code:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class InputFunction {
private int doOperation(int a, int b, String operator) throws Exception {
int result;
if("+".equals(operator)){
result = a + b;
} else if("-".equals(operator)){
result = a - b;
} else if("*".equals(operator)){
result = a * b;
} else {
throw new Exception("Unsupported operator \"" + operator + "\"");
}
return result;
}
private List<String> evaluate(List<String> function) throws Exception {
List<String> processed = new ArrayList<>();
if(function.size() <= 2) {
return function;
} else {
for (int i = 0; i < function.size(); i += 3) {
String a = function.get(i);
if ((i + 1) < function.size()) {
String b = function.get(i + 1);
if ((i + 2) < function.size()) {
String c = function.get(i + 2);
if (a.matches("\\d+") && b.matches("\\d+") && !c.matches("\\d+")) {
processed.add(String.valueOf(doOperation(Integer.valueOf(a), Integer.valueOf(b), c)));
} else {
processed.add(a);
if(c.matches("\\d+")) {
processed.addAll(evaluate(function.subList(i + 1, function.size())));
break;
} else {
processed.add(b);
processed.add(c);
}
}
} else {
processed.add(a);
processed.add(b);
}
} else {
processed.add(a);
}
}
}
return evaluate(processed);
}
private void doFunction(String input) throws Exception{
List<String> function = Arrays.asList(input.split(" "));
Collections.reverse(function);
System.out.println(evaluate(function));
}
public static void main(String ... args) {
InputFunction inputFunction = new InputFunction();
try {
inputFunction.doFunction("+ + 5 5 + 5 5");
inputFunction.doFunction("* + 16 * + 16 4 + 3 1 + 3 1");
} catch (Exception e) {
e.printStackTrace();
}
}
}
... admit-ably I've not tried with any examples with a "-", but you should get the idea.
I know it is a bit too late to answer this, but the answer given does not contain any stacks or queues, and the assignment requires that you use them. so here it is:
public static int eval(Queue<String> s){
Stack<String> list = new Stack<>();
Stack<Integer> saved = new Stack<>();
list.addAll(s);
while(!list.isEmpty()){
String val = list.pop();
if(val.equals("+") || val.equals("-") || val.equals("*")){
if(val.equals("+")){
saved.add((saved.pop() + saved.pop()));
}
if(val.equals("-")){
saved.add((saved.pop() - saved.pop()));
}
if(val.equals("*")){
saved.add((saved.pop() * saved.pop()));
}
}else{
saved.add(Integer.parseInt(val));
}
}
return saved.pop();
}
I have been working on this problem for several hours now and I just cannot figure out what I am doing wrong here. Could anyone help point me in the right direction?
I was asked to write an Autocomplete program and I've completed everything except for this one method I cannot get working. Each term has: 1. String query and 2. long weight.
Here is the method:
public static Comparator<Term> byReverseWeightOrder() {
return new Comparator<Term>() { // LINE CAUSING PROBLEM
public int compare(Term t1, Term t2) {
if (t1.weight > t2.weight) { // LINE CAUSING PROBLEM
return -1;
} else if (t1.weight == t2.weight) {
return 0;
} else {
return 1;
}
}
};
}
My problem is that no matter how I mess with the method I always result in a NullPointerException(). Which, it points to this method (byReverseWeightOrder) as well as these two statements.
Arrays.sort(matches, Term.byReverseWeightOrder());
Term[] results = autocomplete.allMatches(prefix);
Here is the rest of the code if it can be found helpful:
Term
import java.util.Comparator;
public class Term implements Comparable<Term> {
public String query;
public long weight;
public Term(String query, long weight) {
if (query == null) {
throw new java.lang.NullPointerException("Query cannot be null");
}
if (weight < 0) {
throw new java.lang.IllegalArgumentException("Weight cannot be negative");
}
this.query = query;
this.weight = weight;
}
public static Comparator<Term> byReverseWeightOrder() {
return new Comparator<Term>() {
public int compare(Term t1, Term t2) {
if (t1.weight > t2.weight) {
return -1;
} else if (t1.weight == t2.weight) {
return 0;
} else {
return 1;
}
}
};
}
public static Comparator<Term> byPrefixOrder(int r) {
if (r < 0) {
throw new java.lang.IllegalArgumentException("Cannot order with negative number of characters");
}
final int ref = r;
return
new Comparator<Term>() {
public int compare(Term t1, Term t2) {
String q1 = t1.query;
String q2 = t2.query;
int min;
if (q1.length() < q2.length()) {
min = q1.length();
}
else {
min = q2.length();
}
if (min >= ref) {
return q1.substring(0, ref).compareTo(q2.substring(0, ref));
}
else if (q1.substring(0, min).compareTo(q2.substring(0, min)) == 0) {
if (q1.length() == min) {
return -1;
}
else {
return 1;
}
}
else {
return q1.substring(0, min).compareTo(q2.substring(0, min));
}
}
};
}
public int compareTo(Term that) {
String q1 = this.query;
String q2 = that.query;
return q1.compareTo(q2);
}
public long getWeight() {
return this.weight;
}
public String toString() {
return this.weight + "\t" + this.query;
}
}
BinarySearchDeluxe
import java.lang.*;
import java.util.*;
import java.util.Comparator;
public class BinarySearchDeluxe {
public static <Key> int firstIndexOf(Key[] a, Key key, Comparator<Key> comparator) {
if (a == null || key == null || comparator == null) {
throw new java.lang.NullPointerException();
}
if (a.length == 0) {
return -1;
}
int left = 0;
int right = a.length - 1;
while (left + 1 < right) {
int middle = left + (right - left)/2;
if (comparator.compare(key, a[middle]) <= 0) {
right = middle;
} else {
left = middle;
}
}
if (comparator.compare(key, a[left]) == 0) {
return left;
}
if (comparator.compare(key, a[right]) == 0) {
return right;
}
return -1;
}
public static <Key> int lastIndexOf(Key[] a, Key key, Comparator<Key> comparator) {
if (a == null || key == null || comparator == null) {
throw new java.lang.NullPointerException();
}
if (a == null || a.length == 0) {
return -1;
}
int left = 0;
int right = a.length - 1;
while (left + 1 < right) {
int middle = left + (right - left)/2;
if (comparator.compare(key, a[middle]) < 0) {
right = middle;
} else {
left = middle;
}
}
if (comparator.compare(key, a[right]) == 0) {
return right;
}
if (comparator.compare(key, a[left]) == 0) {
return left;
}
return -1;
}
}
AutoComplete
import java.util.Arrays;
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import java.util.Comparator;
public class Autocomplete {
public Term[] terms;
public Autocomplete(Term[] terms) {
if (terms == null) {
throw new java.lang.NullPointerException();
}
this.terms = terms.clone();
Arrays.sort(this.terms);
}
public Term[] allMatches(String prefix) {
if (prefix == null) {
throw new java.lang.NullPointerException();
}
Term theTerm = new Term(prefix, 0);
int start = BinarySearchDeluxe.firstIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length()));
int end = BinarySearchDeluxe.lastIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length()));
int count = start;
System.out.println("Start: " + start + " End: " + end);
if (start == -1 || end == -1) {
// System.out.println("PREFIX: " + prefix);
throw new java.lang.NullPointerException();
} // Needed?
Term[] matches = new Term[end - start + 1];
//matches = Arrays.copyOfRange(terms, start, end);
for (int i = 0; i < end - start; i++) {
matches[i] = this.terms[count];
count++;
}
Arrays.sort(matches, Term.byReverseWeightOrder());
System.out.println("Finished allmatches");
return matches;
}
public int numberOfMatches(String prefix) {
if (prefix == null) {
throw new java.lang.NullPointerException();
}
Term theTerm = new Term(prefix, 0);
int start = BinarySearchDeluxe.firstIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length()));
int end = BinarySearchDeluxe.lastIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length()));
System.out.println("Finished numberMatches");
return end - start + 1; // +1 needed?
}
public static void main(String[] args) throws IOException {
// Read the terms from the file
Scanner in = new Scanner(new File("wiktionary.txt"));
int N = in.nextInt(); // Number of terms in file
Term[] terms = new Term[N];
for (int i = 0; i < N; i++) {
long weight = in.nextLong(); // read the next weight
String query = in.nextLine(); // read the next query
terms[i] = new Term(query.replaceFirst("\t",""), weight); // construct the term
}
Scanner ip = new Scanner(System.in);
// TO DO: Data Validation Here
int k;
do {
System.out.println("Enter how many matching terms do you want to see:");
k = ip.nextInt();
} while (k < 1 || k > N);
Autocomplete autocomplete = new Autocomplete(terms);
// TO DO: Keep asking the user to enter the prefix and show results till user quits
boolean cont = true;
do {
// Read in queries from standard input and print out the top k matching terms
System.out.println("Enter the term you are searching for. Enter * to exit");
String prefix = ip.next();
if (prefix.equals("*")) {
cont = false;
break;
}
Term[] results = autocomplete.allMatches(prefix);
System.out.println(results.length);
for(int i = 0; i < Math.min(k,results.length); i++)
System.out.println(results[i].toString());
} while(cont);
System.out.println("Done!");
}
}
I apologize for the sloppy code, I have been pulling my hair out for awhile now and keep forgetting to clean it up.
Two examples:
Example 1:
int k = 2;
String prefix = "auto";
Enter how many matching terms do you want to see:
2
Enter the term you are searching for. Enter * to exit
auto
619695 automobile
424997 automatic
Example 2:
int k = 5;
String prefix = "the";
Enter how many matching terms do you want to see:
5
Enter the term you are searching for. Enter * to exit
the
5627187200 the
334039800 they
282026500 their
250991700 them
196120000 there
For some reason, my program seems to keep crashing because it's reading a token wrong.On line 362 and 363, where it reads token[i], no matter what happens it seems to read it as a '(' character, even though it's clearly not. If I input something like a 100*(5+5) , it will call recursion after i = 2 on 0*(5+5) instead of correctly going to i=4 and calling it on (5+5). Any help debugging would be great!
package apps;
import java.io.IOException;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.StringTokenizer;
import structures.Stack;
public class Expression {
/**
* Expression to be evaluated
*/
String expr;
/**
* Scalar symbols in the expression
*/
ArrayList<ScalarSymbol> scalars;
/**
* Array symbols in the expression
*/
ArrayList<ArraySymbol> arrays;
/**
* Positions of opening brackets
*/
ArrayList<Integer> openingBracketIndex;
/**
* Positions of closing brackets
*/
ArrayList<Integer> closingBracketIndex;
/**
* String containing all delimiters (characters other than variables and constants),
* to be used with StringTokenizer
*/
public static final String delims = " \t*+-/()[]";
/**
* Initializes this Expression object with an input expression. Sets all other
* fields to null.
*
* #param expr Expression
*/
public Expression(String expr) {
this.expr = expr;
scalars = null;
arrays = null;
openingBracketIndex = null;
closingBracketIndex = null;
}
/**
* Matches parentheses and square brackets. Populates the openingBracketIndex and
* closingBracketIndex array lists in such a way that closingBracketIndex[i] is
* the position of the bracket in the expression that closes an opening bracket
* at position openingBracketIndex[i]. For example, if the expression is:
* <pre>
* (a+(b-c))*(d+A[4])
* </pre>
* then the method would return true, and the array lists would be set to:
* <pre>
* openingBracketIndex: [0 3 10 14]
* closingBracketIndex: [8 7 17 16]
* </pe>
*
* See the FAQ in project description for more details.
*
* #return True if brackets are matched correctly, false if not
*/
public boolean isLegallyMatched()
{
Stack<Character> brack = new Stack<Character>();
Stack<Integer> opens = new Stack<Integer>();
openingBracketIndex = new ArrayList<Integer>();
closingBracketIndex = new ArrayList<Integer>();
char x;
char y;
String expr = this.expr;
for(int i=0; i<expr.length(); i++)
{
x = expr.charAt(i);
if(x!='(' && x!= '[' && x!=')' && x!=']')
{
continue;
}
if(x=='(' || x== '[')
{
opens.push(i);
brack.push(x);
}
else if(x==')' || x==']')
{
closingBracketIndex.add(i);
if(opens.isEmpty())
{
return false;
}
openingBracketIndex.add(opens.pop());
if(brack.isEmpty())
{
return false;
}
y = brack.pop();
if(y=='(' && x==')')
{
continue;
}
else if(y=='[' && x==']')
{
continue;
}
else if(y=='{' && x=='}')
{
continue;
}
else
{
return false;
}
}
}
if(!brack.isEmpty())
{
return false;
}
selectionSort(openingBracketIndex);
if(openingBracketIndex.isEmpty()!= true)
{
System.out.print("Opening Bracket Index: [ ");
for(int i=0;i<openingBracketIndex.size(); i++)
{
System.out.print(openingBracketIndex.get(i) + " ");
}
System.out.print("]");
System.out.println();
System.out.print("Closing bracket Index: [ ");
for(int i=0;i<openingBracketIndex.size(); i++)
{
System.out.print(closingBracketIndex.get(i) + " ");
}
System.out.println("]");
}
return true;
}
/**
* Populates the scalars and arrays lists with symbols for scalar and array
* variables in the expression. For every variable, a SINGLE symbol is created and stored,
* even if it appears more than once in the expression.
* At this time, values for all variables are set to
* zero - they will be loaded from a file in the loadSymbolValues method.
*/
public void buildSymbols()
{
scalars = new ArrayList<ScalarSymbol>();
arrays = new ArrayList<ArraySymbol>();
for(int i=0;i<expr.length();i++)
{
String symb = "";
while(i<expr.length() && Character.isLetter(expr.charAt(i)))
{
symb = symb + expr.charAt(i);
i++;
}
if(i==expr.length())
{
i--;
}
if(expr.charAt(i) == '[')
{
ArraySymbol arr = new ArraySymbol(symb);
boolean dupe = checkArrDupes(arr, arrays);
if(symb!="" && dupe == true)
{
arrays.add(arr);
}
}
else
{
ScalarSymbol scal = new ScalarSymbol(symb);
boolean dupe = checkScalDupes(scal,scalars);
if(symb!="" && dupe==true)
{
scalars.add(scal);
}
}
}
// COMPLETE THIS METHOD
}
/**
* Loads values for symbols in the expression
*
* #param sc Scanner for values input
* #throws IOException If there is a problem with the input
*/
public void loadSymbolValues(Scanner sc)
throws IOException {
while (sc.hasNextLine()) {
StringTokenizer st = new StringTokenizer(sc.nextLine().trim());
int numTokens = st.countTokens();
String sym = st.nextToken();
ScalarSymbol ssymbol = new ScalarSymbol(sym);
ArraySymbol asymbol = new ArraySymbol(sym);
int ssi = scalars.indexOf(ssymbol);
int asi = arrays.indexOf(asymbol);
if (ssi == -1 && asi == -1) {
continue;
}
int num = Integer.parseInt(st.nextToken());
if (numTokens == 2) { // scalar symbol
scalars.get(ssi).value = num;
} else { // array symbol
asymbol = arrays.get(asi);
asymbol.values = new int[num];
// following are (index,val) pairs
while (st.hasMoreTokens()) {
String tok = st.nextToken();
StringTokenizer stt = new StringTokenizer(tok," (,)");
int index = Integer.parseInt(stt.nextToken());
int val = Integer.parseInt(stt.nextToken());
asymbol.values[index] = val;
}
}
}
}
/**
* Evaluates the expression, using RECURSION to evaluate subexpressions and to evaluate array
* subscript expressions.
*
* #return Result of evaluation
*/
public float evaluate()
{
printScalars();
printArrays();
String expr = this.expr;
System.out.println("Hello");
float result = evaluate(expr, 0);
return result;
}
public float evaluate(String base, int brackIndex)
{
System.out.println("Method Start");
Stack<Float> numStack = new Stack<Float>();
Stack<String> opStack = new Stack<String>();
Stack<String> op2Stack = new Stack<String>();
Stack<Float> num2Stack = new Stack<Float>();
float x;
float y;
float result;
int swag = findParenIndexes(base);
Stack<Integer> open = new Stack<Integer>();
Stack<Integer> close= new Stack<Integer>();
for(int i=0;i<base.length();i++)
{
if(open.size()==1 && close.size()==1)
{
System.out.println(open.pop() + " " + close.pop());
break;
}
if(base.charAt(i)=='(' || base.charAt(i)=='[')
{
open.push(i);
}
if(base.charAt(i)==')'|| base.charAt(i)==']')
{
open.pop();
close.push(i);
}
}
String expr = base;
String orig = this.expr;
for(int i=0;i<scalars.size();i++)
{
expr = expr.replaceAll(scalars.get(i).name, scalars.get(i).value + "");
}
System.out.println(expr);
StringTokenizer st = new StringTokenizer(expr,delims,true);
String[] tokens = new String[st.countTokens()];
int z=0;
while(st.hasMoreTokens())
{
tokens[z] = st.nextToken();
z++;
}
for(int i=0;i<tokens.length;i++)
{
System.out.println(tokens[i]);
}
for(int i=0;i<tokens.length;i++)
{
String currToken = tokens[i];
if(isNumeric(currToken))
{
numStack.push(Float.parseFloat(currToken));
System.out.println("Number pushed to stack.");
}
if(currToken.charAt(0)=='+')
{
opStack.push(currToken);
System.out.println("+ pushed to stack.");
}
else if(currToken.charAt(0)=='-')
{
opStack.push(currToken);
System.out.println("- pushed to stack.");
}
else if(currToken.charAt(0)=='*')
{
System.out.println("Multiplying...");
System.out.println("Current bracket index is "+ brackIndex);
x = numStack.pop();
i++;
String next = tokens[i];
if(next.charAt(0)=='(')
{
try{
System.out.println("Evaluating " + expr.substring(i+1, swag));
}
catch(Exception e)
{
swag = findParenIndexes(expr.substring(swag,expr.length()));
}
System.out.println("i: " + i + " swag: ") ;
y=evaluate(expr.substring(i+1, swag), brackIndex+1);
result = x*y;
System.out.println("Multiplication worked - evaluate() returned " + result + " and jumped to the "+closingBracketIndex.get(brackIndex)+" index");
i = swag;
System.out.println("i: " + i);
numStack.push(result);
}
if(isNumeric(next))
{
y = Float.parseFloat(next);
result = x*y;
System.out.println(result + " pushed to stack");
numStack.push(result);
}
}
else if(currToken.charAt(0)=='/')
{
System.out.println("Dividing...");
x = numStack.pop();
i++;
String next = tokens[i];
if(next.charAt(0)== '(')
{
y=evaluate(expr.substring(i+1, swag), brackIndex+1);
i = swag;
}
else
{
y = Float.parseFloat(next);
}
if(y==0)
{
System.out.println("Divide by Zero encountered! Please check your input");
throw new IllegalArgumentException();
}
result = x/y;
System.out.println(result + " pushed to stack");
numStack.push(result);
}
else if(currToken.charAt(0)=='(')
{
System.out.println("Evaluating parentheses and adding the term to the stack.");
numStack.push(evaluate(expr.substring(i+1,swag), brackIndex+1));
System.out.println("Jumping to " + swag);
i = swag;
System.out.println("i: " + i);
}
if(arrays.contains(currToken))
{
System.out.println("array variable detected. looking up" + currToken);
int k = arrays.indexOf(currToken);
int cool = arrays.get(k).values[10];
}
// 5+(5*6+(5*3)-4)-9
}
// (a+(b-c))*(d+4)
while(!opStack.isEmpty())
{
op2Stack.push(opStack.pop());
}
while(!numStack.isEmpty())
{
num2Stack.push(numStack.pop());
}
while(op2Stack.isEmpty() == false)
{
String currOp = op2Stack.pop();
if(currOp.charAt(0) == '+')
{
x = num2Stack.pop();
y = num2Stack.pop();
System.out.println("adding "+ x +" and "+ y);
result = x+y;
System.out.println(result + " pushed to stack");
num2Stack.push(result);
if(!opStack.isEmpty())
System.out.println("next op... " + op2Stack.peek());
}
if(currOp.charAt(0) == '-')
{
System.out.println("subtracting...");
x = num2Stack.pop();
y = num2Stack.pop();
result = x-y;
System.out.println(result + " pushed to stack");
num2Stack.push(result);
if(!opStack.isEmpty())
System.out.println("next op... " + op2Stack.peek());
}
}
Float end = num2Stack.pop();
System.out.println("pls work - " + end);
return end;
}
private int findParenIndexes(String expr)
{
Stack<Integer> open = new Stack<Integer>();
Stack<Integer> close = new Stack<Integer>();
for(int i = 0;i<expr.length();i++)
{
if(expr.charAt(i)=='(' || expr.charAt(i)==']')
{
open.push(i);
}
if(expr.charAt(i)==')' || expr.charAt(i)==']')
{
close.push(i);
if(open.size()==1)
{
return close.pop();
}
open.pop();
}
}
return 0;
// COMPLETE THIS METHOD
}
private static boolean isNumeric(String str)
{
try
{
float f = Float.parseFloat(str);
}
catch(Exception e)
{
return false;
}
return true;
}
// test 5*(2+6-(5*3)-6)
/**
* Utility method, prints the symbols in the scalars list
*/
public void printScalars() {
for (ScalarSymbol ss: scalars) {
System.out.println(ss);
}
}
/**
* Utility method, prints the symbols in the arrays list
*/
public void printArrays()
{
for (ArraySymbol as: arrays)
{
System.out.println(as);
}
}
private boolean checkArrDupes(ArraySymbol sym, ArrayList<ArraySymbol> list)
{
if(list.size()!=0)
{
for(int i=0;i<list.size();i++)
{
if(sym==list.get(i))
{
return false;
}
}
}
return true;
}
private boolean checkScalDupes(ScalarSymbol sym, ArrayList<ScalarSymbol> list)
{
if(list.size()!=0)
{
for(int i=0;i<list.size();i++)
{
if(sym==list.get(i))
{
return false;
}
}
}
return true;
}
private void selectionSort(ArrayList<Integer> data)
{
if (data == null)
return;
if (data.size() == 0 || data.size() == 1)
return;
int smallestIndex;
int smallest;
for (int i = 0; i < data.size(); i++)
{
smallest = data.get(i);
smallestIndex = i;
for (int z = i + 1; z < data.size(); z++)
{
if (smallest > data.get(z))
{
// update smallest
smallest = data.get(z);
smallestIndex = z;
}
}
if (smallestIndex != i)
{
int temp = data.get(i);
data.set(i, data.get(smallestIndex));
data.set(smallestIndex, temp);
temp = closingBracketIndex.get(i);
closingBracketIndex.set(i,closingBracketIndex.get(smallestIndex));
closingBracketIndex.set(smallestIndex,temp);
}
}
}
}
I have to implement the T9 Dictionary .
Essentially, when I am pressing any of the 9 keys, it should show me
the top 5 words that can be started with that combination of keys.
If I type '46', it can give 'hotel' or 'good' depending on whether I
intended 'g' or 'h' when I pressed 4.
The priority is based on which words are relatively popular - you can
use, say, the first 5000 words from the top 100 000 words.
The code I am doing is:
Import
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
T9Dict class
public class T9Dict {
private static final Runtime s_runtime = Runtime.getRuntime();
public static void main(String[] args) throws Exception {
runGC();
long heap1 = usedMemory();
long start = new Date().getTime();
Trie trie = Trie.getInstance();
System.out.println("Creating Dictionary");
File f = new File("C:\\Users\\hp1\\Desktop\\100kfound.txt");
BufferedReader br = new BufferedReader(new FileReader(f));
String s = br.readLine();
int i = 0;
do {
i++;
trie.add(s);
s = br.readLine();
} while (s != null);
br.close();
long end = new Date().getTime();
long time = (end - start);
System.out.println("Loaded Dictionary with " + i + " words in " + time
+ " msec");
// runGC();
long heap2 = usedMemory(); // take an "after" heap snapshot:
System.out.println("Memory used = " + (heap2 - heap1));
String pattern = "4663";
start = new Date().getTime();
String word = trie.getWord(pattern);
end = new Date().getTime();
time = (end - start);
System.out.println("Found word : " + word + " in " + time + " msec");
}
private static void runGC() throws Exception {
// for whatever reason it helps to call Runtime.gc()
// using several method calls:
for (int r = 0; r < 4; ++r) {
_runGC();
}
}
private static void _runGC() throws Exception {
long usedMem1 = usedMemory();
long usedMem2 = Long.MAX_VALUE;
for (int i = 0; (usedMem1 < usedMem2) && (i < 1000); ++i) {
s_runtime.runFinalization();
s_runtime.gc();
Thread.currentThread().yield();
usedMem2 = usedMem1;
usedMem1 = usedMemory();
}
}
private static long usedMemory() {
return s_runtime.totalMemory() - s_runtime.freeMemory();
}
}
Trie class
class Trie {
private static final String regex = "[a-zA-Z]*";
private static Trie instance = null;
Node root = null;
Map<Character, Integer> map = new HashMap<Character, Integer>();
private Trie() {
map.put('a', 2);
map.put('b', 2);
map.put('c', 2);
map.put('d', 3);
map.put('e', 3);
map.put('f', 3);
map.put('g', 4);
map.put('h', 4);
map.put('i', 4);
map.put('j', 5);
map.put('k', 5);
map.put('l', 5);
map.put('m', 6);
map.put('n', 6);
map.put('o', 6);
map.put('p', 7);
map.put('q', 7);
map.put('r', 7);
map.put('s', 7);
map.put('t', 8);
map.put('u', 8);
map.put('v', 8);
map.put('w', 9);
map.put('x', 9);
map.put('y', 9);
map.put('z', 9);
}
private int getVal(char c) {
return map.get(c);
}
public static Trie getInstance() {
if (instance == null) {
synchronized (Trie.class) {
instance = new Trie();
}
}
return instance;
}
public String getWord(String pattern) {
String s = null;
Node node = root;
int i = 0;
int num = 0;
while (i < pattern.length()) {
num = pattern.charAt(i) - '0';
if (num == node.val) {
i++;
if (i == pattern.length()) {
s = node.list.get(0);
}
node = node.middle;
} else if (num < node.val) {
if (i == pattern.length()) {
s = node.list.get(0);
}
node = node.left;
} else {
if (i == pattern.length()) {
s = node.list.get(0);
}
node = node.right;
}
}
return s;
}
public void add(String s) {
if (s.length() > 0) {
s = s.toLowerCase();
System.out.println("Adding : " + s);
if (root == null) {
root = new Node(this.getVal(s.charAt(0)));
Node node = root;
Node temp = null;
for (int i = 1; i < s.length(); i++) {
temp = new Node(getVal(s.charAt(i)));
node.middle = temp;
node = temp;
if (i == s.length() - 1) {
temp.set(s);
}
}
} else {
Node node = root;
int i = 0;
Node temp = null;
int val = 0;
while (i < s.length()) {
val = getVal(s.charAt(i));
if (node.val == val) {
if (i == s.length() - 1) {
node.set(s);
i++;
} else {
i++;
if (node.middle == null) {
while (i < s.length()) {
val = getVal(s.charAt(i));
temp = new Node(val);
node.middle = temp;
node = temp;
if (i == s.length() - 1) {
temp.set(s);
}
i++;
}
} else {
node = node.middle;
}
}
} else if (val < node.val) {
if (node.left == null) {
temp = new Node(val);
node.left = temp;
node = temp;
if (i == s.length() - 1) {
temp.set(s);
} else {
i++;
while (i < s.length()) {
val = getVal(s.charAt(i));
temp = new Node(val);
node.middle = temp;
node = temp;
if (i == s.length() - 1) {
temp.set(s);
}
i++;
}
}
} else {
node = node.left;
}
} else {
if (node.right == null) {
temp = new Node(val);
node.right = temp;
node = temp;
if (i == s.length() - 1) {
temp.set(s);
} else {
i++;
while (i < s.length()) {
val = getVal(s.charAt(i));
temp = new Node(val);
node.middle = temp;
node = temp;
if (i == s.length() - 1) {
temp.set(s);
}
i++;
}
}
} else {
node = node.right;
}
}
}
}
}
}
}
Node class
class Node {
int val;
Node left;
Node middle;
Node right;
List<String> list = new LinkedList<String>();
public Node(int val) {
this.val = val;
}
public void set(String s) {
list.add(s);
}
public String toString() {
return String.valueOf(val);
}
}
This code is giving nullpointerexception when adding to Trie
I cannot find the solution please help
1 - You File doesn't contains characters. It is binary so you should use FileInputStream object to read it.
2 - In reading file and adding string in your Trie you should verify that this string is not null, otherwise it can throws a NullPointerException. You can run your file like this:
When I run this I find that the exception occurs on this line:
root = new Node(this.getVal(s.charAt(0)));
Let's unroll this, you're passing the first character of the "word" (ie the String, s) to the getVal(), and this in turn will return an int if, and only if, that character is a lowercase letter, a-z.
When I run the file the "word" is 6724 yahoo - this is the first line of the dictionary text file you linked to. There is nothing in your code to clean up this line to get to the actual word itself, instead you are facing a series of spaces and then a number.
So the reason it fails is because you're effectively going this.getVal(" "). If you call map.get() and the key doesn't exist it'll return null (as described in the Map documentation).
One simple way of getting to the word itself and not the whitespace or frequency number is to first process the string:
s = s.trim(); // removes all leading and trailing whitespace
String word = s.substring(s.indexOf(" ")+1); // extract just the word after the space
And then you can pass the first character of word:
root = new Node(this.getVal(word.charAt(0)));
The calculator is now almost working. It now gives me the same answer for every equation it reads in?
the output ends up as:
49+62*61-36
15.666666666666668
4/64
15.666666666666668
(53+26)
15.666666666666668
0*72
15.666666666666668
21-85+75-85
15.666666666666668
90*76-50+67
15.666666666666668
46*89-15
15.666666666666668
34/83-38
15.666666666666668
20/76/14+92-15
15.666666666666668
5*10/3-1
15.666666666666668
Instead of having the answer for each equation there?
Have i missed something out in my methods?
Thanks
All code is shown below. Any help will be much appreciated.
Stack class:
import java.util.Iterator;
import java.util.NoSuchElementException;
public class myStack<Item> implements Iterable<Item> {
private int N; // size of the stack
private Node first; // top of stack
private class Node {
private Item item;
private Node next;
}
/**
* Create an empty stack.
*/
public myStack() {
first = null;
N = 0;
assert check();
}
public boolean isEmpty() {
return first == null;
}
public int size() {
return N;
}
public void push(Item item) {
Node oldfirst = first;
first = new Node();
first.item = item;
first.next = oldfirst;
N++;
assert check();
}
public Item pop() {
if (isEmpty())
throw new NoSuchElementException("Stack underflow");
Item item = first.item; // save item to return
first = first.next; // delete first node
N--;
assert check();
return item; // return the saved item
}
public Item peek() {
if (isEmpty())
throw new NoSuchElementException("Stack underflow");
return first.item;
}
public String toString() {
StringBuilder s = new StringBuilder();
for (Item item : this)
s.append(item + " ");
return s.toString();
}
// check internal invariants
private boolean check() {
if (N == 0) {
if (first != null)
return false;
} else if (N == 1) {
if (first == null)
return false;
if (first.next != null)
return false;
} else {
if (first.next == null)
return false;
}
// check internal consistency of instance variable N
int numberOfNodes = 0;
for (Node x = first; x != null; x = x.next) {
numberOfNodes++;
}
if (numberOfNodes != N)
return false;
return true;
}
public Object[] toArray(String[] elementData) {
return (Object[]) elementData.clone();
}
public Iterator<Item> iterator() {
return new ListIterator();
}
// did not implement remove as it was not needed
private class ListIterator implements Iterator<Item> {
private Node current = first;
public boolean hasNext() {
return current != null;
}
public void remove() {
throw new UnsupportedOperationException();
}
public Item next() {
if (!hasNext())
throw new NoSuchElementException();
Item item = current.item;
current = current.next;
return item;
}
}
}
Array list class
import java.util.Arrays;
public class myArrayList<Item>{
private Object[] myStore;
private int actSize = 0;
public myArrayList() {
myStore = new Object[100];
}
public Object get(int index) {
if (index < actSize) {
return myStore[index];
} else {
throw new ArrayIndexOutOfBoundsException();
}
}
public void add(Object obj) {
if (myStore.length - actSize <= 0) {
increaseListSize();
}
myStore[actSize++] = obj;
}
public Object remove(int index) {
if (index < actSize) {
Object obj = myStore[index];
myStore[index] = null;
int tmp = index;
while (tmp < actSize) {
myStore[tmp] = myStore[tmp + 1];
myStore[tmp + 1] = null;
tmp++;
}
actSize--;
return obj;
} else {
throw new ArrayIndexOutOfBoundsException();
}
}
public int size() {
return actSize;
}
private void increaseListSize() {
myStore = Arrays.copyOf(myStore, myStore.length * 2);
}
#SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size())
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(myStore, size(), a.getClass());
System.arraycopy(myStore, 0, a, 0, size());
if (a.length > size())
a[size()] = null;
return a;
}
}
The TestClass for equation handling
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
public class TestClass {
private static final int LEFT_ASSOC = 0;
private static final int RIGHT_ASSOC = 1;
static String OPERATORS1 = "+-*/()";
// Operators
private static final Map<String, int[]> OPERATORS = new HashMap<String, int[]>();
static {
// Map<"token", []{precedence, associativity}>
OPERATORS.put("+", new int[] { 0, LEFT_ASSOC });
OPERATORS.put("-", new int[] { 0, LEFT_ASSOC });
OPERATORS.put("*", new int[] { 5, LEFT_ASSOC });
OPERATORS.put("/", new int[] { 5, LEFT_ASSOC });
OPERATORS.put("(", new int[] {1, LEFT_ASSOC});
OPERATORS.put(")", new int[] {1, LEFT_ASSOC});
}
private static boolean isOperator(String token) {
return OPERATORS.containsKey(token);
}
// Test associativity of operator token
private static boolean isAssociative(String token, int type) {
if (!isOperator(token)) {
throw new IllegalArgumentException("Invalid token: " + token);
}
if (OPERATORS.get(token)[1] == type) {
return true;
}
return false;
}
// Compare precedence of operators.
private static final int cmpPrecedence(String token1, String token2) {
if (!isOperator(token1) || !isOperator(token2)) {
throw new IllegalArgumentException("Invalid tokens: " + token1
+ " " + token2);
}
return OPERATORS.get(token1)[0] - OPERATORS.get(token2)[0];
}
public static String[] infixToRPN(String[] inputTokens) {
myArrayList<String> out = new myArrayList<String>();
myStack<String> stack = new myStack<String>();
// For each token
for (String token : inputTokens) {
StringTokenizer tokens = new StringTokenizer(token,OPERATORS1,true);
while (tokens.hasMoreTokens()) {
token = tokens.nextToken();
// If token is an operator
if (isOperator(token)) {
// While stack not empty AND stack top element
// is an operator
while (!stack.isEmpty() && isOperator(stack.peek())) {
if ((isAssociative(token, LEFT_ASSOC) && cmpPrecedence(
token, stack.peek()) <= 0)
|| (isAssociative(token, RIGHT_ASSOC) && cmpPrecedence(
token, stack.peek()) < 0)) {
out.add(stack.pop());
continue;
}
break;
}
// Push the new operator on the stack
stack.push(token);
}
// If token is a left bracket '('
else if (token.equals("(")) {
stack.push(token);
}
// If token is a right bracket ')'
else if (token.equals(")")) {
while (!stack.isEmpty() && !stack.peek().equals("(")) {
out.add(stack.pop());
}
stack.pop();
}
// If token is a number
else {
out.add(token);
}
}
while (!stack.isEmpty()) {
out.add(stack.pop());
}
}
String[] output = new String[out.size()];
return out.toArray(output);
}
public static double RPNtoDouble(String[] tokens) {
myStack<String> stack = new myStack<String>();
// For each token
for (String token : tokens) {
//System.out.println( "Working this token: " + token );
// If the token is a value push it onto the stack
if (!isOperator(token)) {
stack.push(token);
} else {
// Token is an operator: pop top two entries
Double d2 = Double.valueOf(stack.pop());
Double d1 = Double.valueOf(stack.pop());
// Get the result
Double result = token.compareTo("+") == 0 ? d1 + d2 : token
.compareTo("-") == 0 ? d1 - d2
: token.compareTo("*") == 0 ? d1 * d2 : d1 / d2;
// Push result onto stack
stack.push(String.valueOf(result));
}
}
return Double.valueOf(stack.pop());
}
static public void main(String[] args) throws IOException {
File file = new File("testEquations.txt");
String[] lines = new String[1];
try {
FileReader reader = new FileReader(file);
#SuppressWarnings("resource")
BufferedReader buffReader = new BufferedReader(reader);
int x = 0;
String s;
while ((s = buffReader.readLine()) != null) {
lines[x] = s;
x++;
}
} catch (IOException e) {
System.exit(0);
}
// test printing string array
for (String s : lines) {
System.out.println("" + s);
String[] output =infixToRPN(lines);
System.out.println(RPNtoDouble(output));
}
}
}
Your problem is here:
String[] lines = new String[1];
try {
FileReader reader = new FileReader(file);
#SuppressWarnings("resource")
BufferedReader buffReader = new BufferedReader(reader);
int x = 0;
String s;
while ((s = buffReader.readLine()) != null) {
lines[x] = s;
x++;
}
...
you define array of string with a size = 1 but you don't check inside the loop if x is getting out of the borders of this array.
Do somethink like this:
int Size = // define the size..;
String[] lines = new String[Size];
...
while (x < Size && (s = buffReader.readLine()) != null)) {
lines[x] = s;
x++;
}
when your x becames bigger then Size, x < Size will evaluate false, thus getting out of the loop.
About one of the error you are getting ArrayIndexOutOfBoundsException:
Thrown to indicate that an array has been accessed with an illegal
index. The index is either negative or greater than or equal to the
size of the array. (source)
The other error NoSuchElementException :
Thrown by the nextElement method of an Enumeration to indicate that
there are no more elements in the enumeration (source).
Another problem is here:
// test printing string array
for (String s : lines)
{
System.out.println("" + s);
String[] output =infixToRPN(lines);
System.out.println(RPNtoDouble(output));
}
You have to pass s, and not lines into method infixToRPN, thats why you are getting the same output, because you are giving the same input.
Remember that infixToRPN receives a String [] not a string like 's', but this I leave to you to find a workaround.