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'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!
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
I am trying to complete an assignment where I need to write a Java program to take a string from the command line, and implement it as a Binary Tree in a specific order, then get the depth of the binary tree.
For example: "((3(4))7((5)9))"
would be entered as a tree with 7 as the root, 3 and 9 as the children, and 4 as a right child of 3, and 5 as a left child of 9.
My code is below.. The problem I am having is that, because I am basing my checks off of finding a right bracket, I am unsure how to get the elements correctly when they are not directly preceding the brackets, such as the 3 in the above string. Any direction would be greatly appreciated..
class Node {
int value;
Node left, right;
}
class BST {
public Node root;
// Add Node to Tree
public void add(int n) {
if (root == null) {
root = new Node( );
root.value = n;
}
else {
Node marker = root;
while (true) {
if (n < marker.value) {
if (marker.left == null) {
marker.left = new Node( );
marker.left.value = n;
break;
} else {
marker = marker.left;
}
} else {
if (marker.right == null) {
marker.right = new Node( );
marker.right.value = n;
break;
} else {
marker = marker.right;
}
}
}
}
} // End ADD
//Find Height of Tree
public int height(Node t) {
if (t.left == null && t.right == null) return 0;
if (t.left == null) return 1 + height(t.right);
if (t.right == null) return 1 + height(t.left);
return 1 + Math.max(height(t.left), height(t.right));
} // End HEIGHT
// Check if string contains an integer
public static boolean isInt(String s) {
try {
Integer.parseInt(s);
}
catch(NumberFormatException e) {
return false;
}
return true;
} // End ISINT
public int elementCount(String[] a) {
int count = 0;
for (int i = 0; i < a.length; i++) {
if (isInt(a[i])) count++;
}
return count;
}
} // End BST Class
public class Depth {
public static void main(String[] args) {
String[] a = args[0].split(" ");
BST tree = new BST();
int[] bcount = new int[10];
int[] elements = new int[10];
int x = 0, bracketcount = 0;
// Display entered string
System.out.print("Entered Format: ");
for (int j=0; j < a.length; j++) {
System.out.print(a[j]);
}
for (int i=0; i < a.length; i++) {
char c = a[i].charAt(0);
switch (c)
{
case '(':
bracketcount++;
break;
case ')':
if (isInt(a[i-1])) {
bcount[x] = bracketcount--;
elements[x++] = Integer.parseInt(a[i-1]);
}
break;
case '1':
case '7':
default : // Illegal character
if ( (a[i-1].charAt(0) == ')') && (a[i+1].charAt(0) == '(') ) {
bcount[x] = bracketcount;
elements[x++] = Integer.parseInt(a[i]);
}
break;
}
}
System.out.println("\nTotal elements: " + tree.elementCount(a));
// Display BracketCounts
for (int w = 0; w < x; w++) {
System.out.print(bcount[w] + " ");
}
System.out.println(" ");
// Display Elements Array
for (int w = 0; w < x; w++) {
System.out.print(elements[w] + " ");
}
System.out.println("\nDepth: " + tree.height(tree.root));
// Build the tree
for (int y = 0; y < x-1; y++) {
for (int z = 1; z < tree.height(tree.root); z++) {
if (bcount[y] == z) {
tree.add(elements[y]);
}
}
}
} // End Main Function
public static boolean isInt(String s) {
try {
Integer.parseInt(s);
}
catch(NumberFormatException e) {
return false;
}
return true;
}
} // End Depth Class
I would do a couple of statements to get access to a tree with that kind of shape:
For input string : input= "((3(4))7((5)9))"
You could do :
public class Trial {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String input = "((3(4))7((5)9))";
String easier = input.replaceAll("\\(\\(", "");
String evenEasier = easier.replaceAll("\\)\\)", "");
System.out.println(evenEasier);
int firstVal = Integer.parseInt(evenEasier.substring(0, 1));
int firstBracketVal = Integer.parseInt(evenEasier.substring(2, 3));
int middleVal = Integer.parseInt(evenEasier.substring(3, 4));
int secondBracketVal = Integer.parseInt(evenEasier.substring(4,5));
int lastVal = Integer.parseInt(evenEasier.substring(6));
System.out.println("First Val:"+firstVal);
System.out.println("First bracket Val:"+firstBracketVal);
System.out.println("Middle Val:"+middleVal);
System.out.println("Second Bracket Val:"+secondBracketVal);
System.out.println("Last Val:"+lastVal);
}
}
This however would only ever work for entries in that specific format, if that were to change, or the length of the input goes up - this would work a bit or break.....If you need to be able to handle more complicated trees as input in this format a bit more thought would be needed on how to best handle and convert into your internal format for processing.
pseudocode:
function getNode(Node)
get one char;
if (the char is "(")
getNode(Node.left);
get one char;
end if;
Node.value = Integer(the char);
get one char;
if (the char is "(")
getNode(Node.right);
get one char;
end if;
//Now the char is ")" and useless.
end function
Before calling this function, you should get a "(" first.
In this method, the framwork of a Node in string is "[leftchild or NULL] value [rightchild or NULL])".
"("is not belong to the Node, but ")" is.