I am currently learning binary search tree. For a school assignment, I want to implement an self-balancing binary search tree (I choose AVL tree); however, the Node class cannot be modified. I cannot use the common implementation of the AVL tree (I can't store height inside the node).
This is the source code that I implemented (using HashMap).
public class Tree {
static class Student {
String id;
String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
public String toString() {return id + ", " + name;}
}
private class Node {
Student e;
public Node lc, rc; // left child; right child
#SuppressWarnings("unused")
public Node(Student data) {
this.e = data;
}
public String toString() {
return e.toString();
}
}
Node root;
public HashMap<Node, Integer> map = new HashMap<>();
public void insert(Student s) {
root = insert(root, s);
}
public Node insert(Node curNode, Student s){
if (curNode == null){
Node newNode = new Node(s);
map.put(newNode, 1);
return newNode;
}
else if (s.name.compareTo(curNode.e.name) < 0)
curNode.lc = insert(curNode.lc, s);
else if (s.name.compareTo(curNode.e.name) > 0)
curNode.rc = insert(curNode.rc, s);
else return curNode;
int l, r;
map.put(curNode, max(nheight(curNode.rc),
nheight(curNode.lc)) + 1);
int balance = getBalance(curNode);
if (balance > 1 && s.name.compareTo(curNode.e.name) < 0)
return rightRotate(curNode);
if (balance < -1 && s.name.compareTo(curNode.e.name) > 0)
return leftRotate(curNode);
if(balance > 1 && s.name.compareTo(curNode.e.name) > 0){
curNode.lc = leftRotate(curNode.lc);
return rightRotate(curNode);
}
if(balance < -1 && s.name.compareTo(curNode.e.name) < 0){
curNode.rc = rightRotate(curNode.rc);
return leftRotate(curNode);
}
return curNode;
}
public int max(int a, int b){
return a > b ? a : b;
}
public int nheight(Node curRoot){
if (curRoot == null) return 0;
return map.get(curRoot);
}
public int getBalance(Node curNode){
if (curNode == null) return 0;
return nheight(curNode.lc) - nheight(curNode.rc);
}
public Node rightRotate(Node y){
Node x = y.lc;
Node T2 = x.rc;
x.rc = y;
y.lc = T2;
map.put(y, max(nheight(y.lc), nheight(y.rc)) + 1);
map.put(x, max(nheight(x.lc), nheight(x.rc)) + 1);
return x;
}
public Node leftRotate(Node x){
Node y = x.rc;
Node T2 = y.lc;
y.lc = x;
x.rc = T2;
map.put(x, max(nheight(x.lc), nheight(x.rc)) + 1);
map.put(y, max(nheight(y.lc), nheight(y.rc)) + 1);
return y;
}
}
I tried using a HashMap<Node, Integer> to store the height of each node, and using recursive method to calculate the height and balance factor every time. For small number of nodes, the above two methods would work; however, for large node size (>=1000000) those methods will not work. Is there any other data structures I can use the keep track of the height of each node?
This is the code I used to test. I randomly created 1000000 students with names and ids and insert them into the AVL tree.
public class Main {
public static void main(String[] args) {
Tree tree = new Tree();
String[] surnames = {"Chan", "Leung", "Li", "Lai", "Cheung", "Yeung", "Tang", "Chow", "Fung", "Tsang", "Kwok", "Chu", "Liu", "Wong", "Mak"};
SecureRandom random = new SecureRandom();
String[] names = new String[1000000];
for (int j = 0; j < names.length; j++) {
StringBuilder a = new StringBuilder();
for(int i = 0; i < 5; i ++) {
a.append((char)('a' + random.nextInt(25)));
}
names[j] = surnames[random.nextInt(surnames.length)] + " " + a.toString();
}
int id = 22222222;
for (String name : names) {
id += random.nextInt(100);
tree.insert(new Tree.Student(String.valueOf(id), name));
}
}
}
The code works fine when the size of the String is 1000 (String[1000]). It gets error when the size of String gets larger. For example, when it gets to 1000000. The error code is below.
Exception in thread "main" java.lang.NullPointerException: Cannot read field "lc" because "y" is null
Problem found. A careless mistake. I was focusing too much on the size of the input. The actual problem is with the insertion and rotations.
The amended code.
public Node insert(Node curNode, Student s){
if (curNode == null){
Node newNode = new Node(s);
map.put(newNode, 1);
return newNode;
}
else if (s.name.compareTo(curNode.e.name) < 0)
curNode.lc = insert(curNode.lc, s);
else if (s.name.compareTo(curNode.e.name) > 0)
curNode.rc = insert(curNode.rc, s);
else return curNode;
int l, r;
map.put(curNode, max(nheight(curNode.rc), nheight(curNode.lc)) + 1);
int balance = getBalance(curNode);
if (balance > 1 && s.name.compareTo(curNode.lc.e.name) < 0)
return rightRotate(curNode);
if (balance < -1 && s.name.compareTo(curNode.rc.e.name) > 0)
return leftRotate(curNode);
if(balance > 1 && s.name.compareTo(curNode.lc.e.name) > 0){
curNode.lc = leftRotate(curNode.lc);
return rightRotate(curNode);
}
if(balance < -1 && s.name.compareTo(curNode.rc.e.name) < 0){
curNode.rc = rightRotate(curNode.rc);
return leftRotate(curNode);
}
return curNode;
}
im currently working on a uni project and i am having som edifficulty with my Binary search tree, each node has to have a value but also a random "balance value" which is between 0 and 1, if a nodes balance value is more than its parents then the tree needs to be rotated, either left or right depending on the side the child sits.
public class RandomBST {
class Node {
int x;
double balanceValue;
Node parent;
Node LChild;
Node RChild;
public Node(int i, double b) {
x = i;
balanceValue = b;
parent = this;
LChild = RChild = null;
}
}
Node root;
public double randomDouble() {
Random Ran = new Random();
return (0 + (1 - 0) * Ran.nextDouble());
}
public void insert(int i) {
double b = randomDouble();
root = Rec_insert(root, i, b);
Node p = findParent(root,i,-1);
if (p.balanceValue < b ){
if (p.x > i){
rotateLeft();
}else{
rotateRight();
}
}
}
Node Rec_insert(Node root, int i, double b) {
if (root == null) {
root = new Node(i, b);
return root;
}
if (i < root.x)
root.LChild = Rec_insert(root.LChild, i, b);
else if (i > root.x)
root.RChild = Rec_insert(root.RChild, i, b);
return root;
}
static Node findParent(Node node,int i, int parent) {
if (node == null)
return null;
if (node.x == i) {
return node.parent;
} else {
findParent(node.LChild, i, node.x);
findParent(node.RChild, i, node.x);
}
return node.parent;
}
int findMax(int a, int b){
if(a >= b)
return a;
else
return b;
}
int findHeight(Node root){
if(root == null)
return 0;
return findMax(findHeight(root.LChild), findHeight(root.RChild)) + 1;
}
public void rotateRight(){
Node previoius = root;
if (root.RChild!=null){
root = root.RChild;
}
previoius.RChild = root.LChild;
root.LChild = previoius;
}
public void rotateLeft(){
Node previoius = root;
if (root.LChild!=null){
root = root.LChild;
}
previoius.LChild = root.RChild;
root.RChild = previoius;
}
public static void main(String[] args) {
int total = 0;
for (int j = 0; j<1000;j++) {
RandomBST RBST = new RandomBST();
for (int i = 0; i < 1000; i++) {
RBST.insert(i);
}
int height = RBST.findHeight(RBST.root);
total =total + height;
}
System.out.println(total/1000);
}
}
any suggestions on where im goign wrong woukd be fantastic, the output is meant to be around 20 to 21, yet i get around 850.
Making a brand new random number generator with
Random Ran = new Random();
may make your random number ...little random.
Create one generator in your application and direct all calls to it.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
The goal is to draw a maze after resolving it (using BFS) with the shortest path from start to exit.
OUTPUT must be like this
***************************************************
[20,19]
***************************************************
#####################
..#...........#.....#
#.#.#########.#.###.#
#...#.........#.#...#
###############.#.###
#.....#.......#.#...#
#.#######.###.#.#.#.#
#...#...#...#...#.#.#
###.###.###.###.#.#.#
#.#.#.#...#.#...#.#.#
#.#.#.#.#1#.#.###.#.#
#...#.#.#1#.#...#.#.#
#####.###1#.#####.###
#.#1111111#.#...#...#
#.#1#######.#.#.###.#
#.#1#...#...#.#.#...#
#.#1###.#.#####.#####
#.#11111111111111111#
#.##.####.#########1#
#..................11
#####################
There are many path to go to the exit [20,19] , but we must draw with the shortest path.
My code is below but it doesn't print the shortest path.
CODE
class Maze {
public static void main(String args[]) {
int W = 21;
int H = 21;
int X = 9;
int Y = 10;
String[] mazeString = {
"##########.##########",
"..#...........#.....#",
"#.#.#########.#.###.#",
"#...#.........#.#...#",
"###############.#.###",
"#.....#.......#.#...#",
"#.#######.###.#.#.#.#",
"#...#...#...#...#.#..",
"###.###.###.###.#.#.#",
"#.#.#.#...#.#...#.#.#",
"#.#.#.#.#.#.#.###.#.#",
"#...#.#.#.#.#...#.#.#",
"#####.###.#.#####.###",
"#.#.......#.#...#...#",
"#.#.#######.#.#.###.#",
"#.#.#...#...#.#.#...#",
"#.#.###.#.#####.#####",
"#.#.................#",
"#.##.####.#########.#",
"#.........#..........",
"####.######.#########"
};
Node[][] nodes = new Node[W][H];
Node start = null;
List<Node> result = new ArrayList<>();
Boolean[][] visited = new Boolean[W][H];
Boolean[][] blocked = new Boolean[W][H];
Boolean[][] exits = new Boolean[W][H];
for (int i = 0; i < H; i++) {
String R = mazeString[i];
for (int j = 0; j < W; j++) {
Node node = new Node(j, i);
blocked[j][i] = R.charAt(j) == '#';
node.blocked = R.charAt(j) == '#';
exits[j][i] = (!node.blocked) && (i == (H - 1) || j == (W - 1) || i == 0 || j == 0);
visited[j][i] = false;
node.exit = (!node.blocked) && (i == (H - 1) || j == (W - 1) || i == 0 || j == 0);
nodes[j][i] = node;
if (X == j && Y == i) {
start = nodes[j][i];
}
}
}
List<List<Node>> paths = new ArrayList<>();
findExits(start, nodes, visited, W, H, result, paths);
if (!result.isEmpty()) {
Collections.sort(result, new Comparator<Node>() {
#Override
public int compare(Node o1, Node o2) {
if (Integer.compare(o1.x, o2.x) == 0) {
return Integer.compare(o1.y, o2.y);
} else {
return Integer.compare(o1.x, o2.x);
}
}
});
}
for (List<Node> path : paths) {
System.out.println("***************************************************");
System.out.println("[" + path.get(0).x + "," + path.get(0).y + "]");
System.out.println("***************************************************");
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
String s = blocked[j][i] ? "#" : path.contains(new Node(j, i)) ? "1" : ".";
System.out.print(s);
}
System.out.println("");
}
}
}
public static void findExits(Node start, Node[][] nodes, Boolean[][] visited, int W, int H, List<Node> result, List<List<Node>> paths) {
int x = start.x;
int y = start.y;
visited[x][y] = true;
if (start.exit) {
result.add(start);
visited[x][y] = false;
List<Node> path = new ArrayList<Node>();
while (start.parent != null) {
path.add(start);
start = start.parent;
}
path.add(start);
paths.add(path);
}
//TOP
if ((y - 1) >= 0) {
if (!visited[x][y - 1] && (!nodes[x][y - 1].blocked)) {
nodes[x][y - 1].parent = start;
findExits(nodes[x][y - 1], nodes, visited, W, H, result, paths);
}
}
//BOT
if ((y + 1) < H) {
if (!visited[x][y + 1] && (!nodes[x][y + 1].blocked)) {
nodes[x][y + 1].parent = start;
findExits(nodes[x][y + 1], nodes, visited, W, H, result, paths);
}
}
//LEFT
if ((x - 1) >= 0) {
if (!visited[x - 1][y] && (!nodes[x - 1][y].blocked)) {
nodes[x - 1][y].parent = start;
findExits(nodes[x - 1][y], nodes, visited, W, H, result, paths);
}
}
//RIGHT
if ((x + 1) < W) {
if (!visited[x + 1][y] && (!nodes[x + 1][y].blocked)) {
nodes[x + 1][y].parent = start;
findExits(nodes[x + 1][y], nodes, visited, W, H, result, paths);
}
}
}
public static class Node {
public int x, y;
boolean blocked = false;
boolean exit = false;
Node parent = null;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Node other = (Node) obj;
if (this.x != other.x) {
return false;
}
if (this.y != other.y) {
return false;
}
return true;
}
}
}
I want to solve a maze and print the shortest path from start to exit usign BFS. I already solve the maze but my code doesnt print the shortest path, this is my problem.
NB (Additional informations, not questions) :
the maze can have many exit
W (width), H (height), [X,Y] (start point)
'#' (blocked cell), '.' (free cell)
the path from start and exit is represented by '11111...' on the output
Please review the following code. It lets you printout all paths found, as well as the shortest one found.
I did not change nor checked the search algorithm. I think it needs more work because I think it does not find the shortest path possible to each exit. I will look into it later.
I did not figure out yet what is the use of List<Node> result. Also I did not see you implement backtracking.
class Maze {
private static char NUMBER_SIGN = '#', DOT = '.', START = 'S';
private static char EXIT = 'E', PATH = '1';
private static Node[][] nodes;
private static Node start;
private static boolean[][] visited; //no need to use Boolean
//exit holds the same information as Node.blocked. No need to duplicate
//private static boolean[][] blocked;
//exit holds the same information as Node.exit. No need to duplicate
//private static boolean[][] exits;
private static int mazeWidth, mazeHeight, startH, startW; //use meaningful names
private static List<List<Node>> paths;
public static void main(String args[]) {
mazeWidth = 21;//use meaningful names
mazeHeight = 21;
startH = 9; startW = 10;
String[] mazeData = getMazeData() ;
makeMaze(mazeData);
drawMaze(); //draw maze as built from input data
List<Node> result = new ArrayList<>();
paths = new ArrayList<>();
findExits(start, nodes, visited, mazeWidth, mazeHeight, result, paths);
if (!result.isEmpty()) {
Collections.sort(result, new Comparator<Node>() {
#Override
public int compare(Node o1, Node o2) {
if (Integer.compare(o1.x, o2.x) == 0) {
return Integer.compare(o1.y, o2.y);
} else {
return Integer.compare(o1.x, o2.x);
}
}
});
}
drawAllPaths(); // see all paths found
List<Node> shortestPath = getShortestPath();
drawShortestPath(shortestPath);
}
private static void drawMaze() {
System.out.println("***************************************************");
System.out.println("Maze as defined by input");
System.out.println("***************************************************");
drawMaze(null);
}
private static void drawAllPaths() {
for (List<Node> path : paths) {
System.out.println("***************************************************");
System.out.println("Path to exit ["
+ path.get(0).x + "," + path.get(0).y + "] length:"+ path.size());
System.out.println("***************************************************");
drawMaze(path);
}
}
private static void drawShortestPath(List<Node> path) {
System.out.println("***************************************************");
System.out.println("Shortest path is to exit ["
+ path.get(0).x + "," + path.get(0).y + "] length:"+ path.size());
System.out.println("***************************************************");
drawMaze(path);
}
private static void drawMaze(List<Node> path) {
for(Node[] row : nodes ) {
for(Node node : row) {
char c = node.getGraphics();
if ((path != null) && path.contains(node)) {c = PATH;}
System.out.print(c);
}
System.out.println("");
}
}
private static void makeMaze(String[] mazeData) {
nodes = new Node[mazeHeight][mazeWidth];
visited = new boolean[mazeHeight][mazeWidth];
for (int height = 0; height < mazeHeight; height++) {
String row = mazeData[height];
for (int width = 0; width < mazeWidth; width++) {
Node node = new Node(height, width);
node.blocked = row.charAt(width) == NUMBER_SIGN;
visited[width][height] = false;
node.exit = (!node.blocked) && ((height == (mazeHeight - 1)) ||
(width == (mazeWidth - 1)) || (height == 0) || (width == 0));
nodes[height][width] = node;
}
}
start = nodes[startH][startW];//no need to set it in the loop
}
//use boolean instead of Boolean
private static void findExits(Node start, Node[][] nodes,
boolean[][] visited, int W, int H, List<Node> result, List<List<Node>> paths) {
int x = start.x;
int y = start.y;
visited[x][y] = true;
if (start.exit) {
result.add(start);
visited[x][y] = false;
List<Node> path = new ArrayList<>();
while (start.parent != null) {
path.add(start);
start = start.parent;
}
path.add(start);
paths.add(path);
}
//TOP
if ((y - 1) >= 0) {
if (!visited[x][y - 1] && (!nodes[x][y - 1].blocked)) {
nodes[x][y - 1].parent = start;
findExits(nodes[x][y - 1], nodes, visited, W, H, result, paths);
}
}
//BOT
if ((y + 1) < H) {
if (!visited[x][y + 1] && (!nodes[x][y + 1].blocked)) {
nodes[x][y + 1].parent = start;
findExits(nodes[x][y + 1], nodes, visited, W, H, result, paths);
}
}
//LEFT
if ((x - 1) >= 0) {
if (!visited[x - 1][y] && (!nodes[x - 1][y].blocked)) {
nodes[x - 1][y].parent = start;
findExits(nodes[x - 1][y], nodes, visited, W, H, result, paths);
}
}
//RIGHT
if ((x + 1) < W) {
if (!visited[x + 1][y] && (!nodes[x + 1][y].blocked)) {
nodes[x + 1][y].parent = start;
findExits(nodes[x + 1][y], nodes, visited, W, H, result, paths);
}
}
}
public static class Node {
public int x, y;
boolean blocked = false;
boolean exit = false;
Node parent = null;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Node other = (Node) obj;
if (x != other.x) {
return false;
}
if (y != other.y) {
return false;
}
return true;
}
//it is simpler to have Node return its graphic representation
char getGraphics() {
char c = blocked ? NUMBER_SIGN : DOT;
if(equals(start)) { c=START;}
else if (exit) { c=EXIT;}
return c;
}
}
private static List<Node> getShortestPath() {
//initialize with an arbitrary path
List<Node> shortest = paths.get(0);
for (List<Node> path : paths) {
if(path.size() < shortest.size()) {
shortest = path;
}
}
return shortest;
}
private static String[] getMazeData() {
return new String[] {
"##########.##########",
"..#...........#.....#",
"#.#.#########.#.###.#",
"#...#.........#.#...#",
"###############.#.###",
"#.....#.......#.#...#",
"#.#######.###.#.#.#.#",
"#...#...#...#...#.#..",
"###.###.###.###.#.#.#",
"#.#.#.#...#.#...#.#.#",
"#.#.#.#.#.#.#.###.#.#",
"#...#.#.#.#.#...#.#.#",
"#####.###.#.#####.###",
"#.#.......#.#...#...#",
"#.#.#######.#.#.###.#",
"#.#.#...#...#.#.#...#",
"#.#.###.#.#####.#####",
"#.#.................#",
"#.##.####.#########.#",
"#.........#..........",
"####.######.#########"
};
}
}
EDIT
An improved version. Please test carefully.
class Maze {
private static char NUMBER_SIGN = '#', DOT = '.', START = 'S';
private static char EXIT = 'E', PATH = '1';
private static Node[][] nodes;
private static Node startNode;
private static boolean[][] visited; //no need to use Boolean
//exit holds the same information as Node.blocked. No need to duplicate
//private static boolean[][] blocked;
//exit holds the same information as Node.exit. No need to duplicate
//private static boolean[][] exits;
private static int mazeRows, mazeCols, startRow, startCol; //use meaningful names
private static List<List<Node>> paths;
public static void main(String args[]) {
mazeCols = 21; mazeRows = 21;//use meaningful and consistent names
startRow = 9; startCol = 10; //better keep h,w or height,width all over
String[] mazeData = getMazeData() ;
makeMaze(mazeData);
drawMaze(); //draw maze as built from input data
paths = new ArrayList<>();
findExits(startNode);
drawAllPaths(); // print all paths found
List<Node> shortestPath = getShortestPath();
drawShortestPath(shortestPath);
}
private static void drawMaze() {
System.out.println("*****************************************");
System.out.println("Maze as defined by input");
System.out.println("*****************************************");
drawMaze(null);
}
private static void drawAllPaths() {
for (List<Node> path : paths) {
System.out.println("*****************************************");
System.out.println("Path to exit ["
+ path.get(0).row + "," + path.get(0).col + "] length:"+ path.size());
System.out.println("*****************************************");
drawMaze(path);
}
}
private static void drawShortestPath(List<Node> path) {
System.out.println("*****************************************");
System.out.println("Shortest path is to exit ["
+ path.get(0).row + "," + path.get(0).col + "] length:"+ path.size());
System.out.println("*****************************************");
drawMaze(path);
}
private static void drawMaze(List<Node> path) {
for(Node[] row : nodes ) {
for(Node node : row) {
char c = node.getGraphics();
//overwrite c if node is in path
if ( (c != EXIT) && ( c != START ) &&
(path != null) && path.contains(node)) {c = PATH;}
System.out.print(c);
}
System.out.println("");
}
}
private static void makeMaze(String[] mazeData) {
nodes = new Node[mazeRows][mazeCols];
visited = new boolean[mazeRows][mazeCols];
for (int rowIndex = 0; rowIndex < mazeRows; rowIndex++) {
String row = mazeData[rowIndex];
for (int colIndex = 0; colIndex < mazeCols; colIndex++) {
Node node = new Node(rowIndex, colIndex);
node.blocked = row.charAt(colIndex) == NUMBER_SIGN;
visited[rowIndex][colIndex] = false;
node.exit = (!node.blocked) && ((rowIndex == (mazeRows - 1)) ||
(colIndex == (mazeCols - 1)) || (rowIndex == 0) || (colIndex == 0));
nodes[rowIndex][colIndex] = node;
}
}
startNode = nodes[startRow][startCol];//no need to set it in the loop
}
//use boolean instead of Boolean
private static void findExits(Node node) {
int row = node.row;
int col = node.col;
if(visited[row][col]) { return; }
if (node.exit) {
List<Node> path = new ArrayList<>();
while (node.parent != null) {
path.add(node);
node = node.parent;
}
path.add(node);
paths.add(path);
return; //do not continue to check exit neighbors
}
//LEFT
if ((col - 1) >= 0) {
Node testNode = nodes[row][col - 1];
//the following if statement repeats for all directions
//better put in a method
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node; //parent ! null indicates that cell is tested
findExits(testNode);
testNode.parent = null; //set back to null: test finished
}
}
//RIGHT
if ((col + 1) < mazeCols) {
Node testNode = nodes[row][col + 1];
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node;
findExits(testNode);
testNode.parent = null;
}
}
//TOP
if ((row - 1) >= 0) {
Node testNode = nodes[row-1][col];
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node;
findExits(testNode);
testNode.parent = null;
}
}
//BOTTOM
if ((row + 1) < mazeRows) {
Node testNode = nodes[row+1][col];
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node;
findExits(testNode);
testNode.parent = null;
}
}
visited[row][col] = true; //mark as visited after all directions explored
node.parent = null;
}
public static class Node {
public int row, col;
boolean blocked = false;
boolean exit = false;
Node parent = null;
public Node(int row, int col) {
this.row = row;
this.col = col;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Node other = (Node) obj;
if (row != other.row) {
return false;
}
if (col != other.col) {
return false;
}
return true;
}
//it is simpler to have Node return its graphic representation
char getGraphics() {
char c = blocked ? NUMBER_SIGN : DOT;
if(equals(startNode)) { c=START;}
else if (exit) { c=EXIT;}
return c;
}
#Override
public String toString() {
return "Node " + row +"-"+ col +" ("+ getGraphics() + ")";
}
}
private static List<Node> getShortestPath() {
//initialize with an arbitrary path
List<Node> shortest = paths.get(0);
for (List<Node> path : paths) {
if(path.size() < shortest.size()) {
shortest = path;
}
}
return shortest;
}
private static String[] getMazeData() {
return new String[] {
"##########.##########",
"..#...........#.....#",
"#.#.#########.#.###.#",
"#...#.........#.#...#",
"###############.#.###",
"#.....#.......#.#...#",
"#.#######.###.#.#.#.#",
"#...#...#...#...#.#..",
"###.###.###.###.#.#.#",
"#.#.#.#...#.#...#.#.#",
"#.#.#.#.#.#.#.###.#.#",
"#...#.#.#.#.#...#.#.#",
"#####.###.#.#####.###",
"#.#.......#.#...#...#",
"#.#.#######.#.#.###.#",
"#.#.#...#...#.#.#...#",
"#.#.###.#.#####.#####",
"#.#.................#",
"#.##.####.#########.#",
"#.........#..........",
"####.######.#########"
};
}
}
Feedback would be appreciated.
You're on the right track where you're building a list of paths.
Try this:
create an empty list of paths
start at the starting point, create one path with one cell
look in the four directions and for each cell that is not blocked and not already included in any of the previous paths clone your current path, add that new cell to the end and add it to the list of paths
now loop through all your paths and repeat this progress, checking the four directions from the cell at the tip
stop building a path when it hits the exit or has no more legitimate moves to make, i.e. dead end
use the path with the shortest length
I want to implement the Java AVL tree and to rotate the tree left and right. I am not getting this.
Can anybody by looking at the code below tell me how can I possibly rotate the tree left and right and then use fix up with those two functions to balance the AVL tree?
I hope someone here can guide me through this.
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;
public class AVLTree<T> extends
BinarySearchTree<AVLTree.Node<T>, T> implements SSet<T> {
Random rand;
public static class Node<T> extends BSTNode<Node<T>,T> {
int h; // the height of the node
}
public AVLTree() {
sampleNode = new Node<T>();
rand = new Random();
c = new DefaultComparator<T>();
}
public int height(Node<T> u) {
return (u == null) ? 0 : u.h;
}
public boolean add(T x) {
Node<T> u = new Node<T>();
u.x = x;
if (super.add(u)) {
for (Node<T> w = u; w != nil; w = w.parent) {
// walk back up to the root adjusting heights
w.h = Math.max(height(w.left), height(w.right)) + 1;
}
fixup(u);
return true;
}
return false;
}
public void splice(Node<T> u) {
Node<T> w = u.parent;
super.splice(u);
for (Node<T> z = u; z != nil; z = z.parent)
z.h = Math.max(height(z.left), height(z.right)) + 1;
fixup(w);
}
public void checkHeights(Node<T> u) {
if (u == nil) return;
checkHeights(u.left);
checkHeights(u.right);
if (height(u) != 1 + Math.max(height(u.left), height(u.right)))
throw new RuntimeException("Check heights shows incorrect heights");
int dif = height(u.left) - height(u.right);
if (dif < -1 || dif > 1)
throw new RuntimeException("Check heights found height difference of " + dif);
}
/**
* TODO: finish writing this method
* #param u
*/
public void fixup(Node<T> u) {
while (u != nil) {
int dif = height(u.left) - height(u.right);
if (dif > 1) {
// TODO: add code here to fix AVL condition
// on the path from u to the root, if necessary
} else if (dif < -1) {
// TODO: add code here to fix AVL condition
// on the path from u to the root, if necessary
}
u = u.parent;
}
}
public Node rotateLeft() {
return rotateLeft(u.parent);
}
public void rotateLeft(Node<T> u) {
// TODO: Recompute height values at u and u.parent
}
public void rotateRight(Node<T> u) {
// TODO: Recompute height values at u and u.parent
}
public static <T> T find(SortedSet<T> ss, T x) {
SortedSet<T> ts = ss.tailSet(x);
if (!ts.isEmpty()) {
return ts.first();
}
return null;
}
/**
* This just does some very basic correctness testing
* #param args
*/
public static void main(String[] args) {
AVLTree<Integer> t = new AVLTree<Integer>();
Random r = new Random(0);
System.out.print("Running AVL tests...");
int n = 1000;
for (int i = 0; i < n; i++) {
t.add(r.nextInt(2*n));
t.checkHeights(t.r);
}
for (int i = 0; i < n; i++) {
t.remove(r.nextInt(2*n));
t.checkHeights(t.r);
}
System.out.println("done");
t.clear();
System.out.print("Running correctness tests...");
n = 100000;
SortedSet<Integer> ss = new TreeSet<Integer>();
Random rand = new Random();
for (int i = 0; i < n; i++) {
Integer x = rand.nextInt(2*n);
boolean b1 = t.add(x);
boolean b2 = ss.add(x);
if (b1 != b2) {
throw new RuntimeException("Adding " + x + " gives " + b2
+ " in SortedSet and " + b1 + " in AVL Tree");
}
}
for (int i = 0; i < n; i++) {
Integer x = rand.nextInt(2*n);
Integer x1 = t.find(x);
Integer x2 = find(ss, x);
if (x1 != x2) {
throw new RuntimeException("Searching " + x + " gives " + x2
+ " in SortedSet and " + x1 + " in AVL Tree");
}
ss.headSet(x);
}
for (int i = 0; i < n; i++) {
Integer x = rand.nextInt(2*n);
boolean b1 = t.remove(x);
boolean b2 = ss.remove(x);
if (b1 != b2) {
throw new RuntimeException("Error (2): Removing " + x + " gives " + b2
+ " in SortedSet and " + b1 + " in AVL Tree");
}
}
for (int i = 0; i < n; i++) {
Integer x = rand.nextInt(2*n);
Integer x1 = t.find(x);
Integer x2 = find(ss, x);
if (x1 != x2) {
throw new RuntimeException("Error (3): Searching " + x + " gives " + x2
+ " in SortedSet and " + x1 + " in AVL Tree");
}
ss.headSet(x);
}
System.out.println("done");
}
}
Full AVL tree implementation:
public class AVLTree<T> {
private AVLNode<T> root;
private static class AVLNode<T> {
private T t;
private int height;
private AVLNode<T> left;
private AVLNode<T> right;
private AVLNode(T t) {
this.t = t;
height = 1;
}
}
public void insert(T value) {
root = insert(root, value);
}
private AVLNode<T> insert(AVLNode<T> n, T v) {
if (n == null) {
n = new AVLNode<T>(v);
return n;
} else {
int k = ((Comparable) n.t).compareTo(v);
if (k > 0) {
n.left = insert(n.left, v);
} else {
n.right = insert(n.right, v);
}
n.height = Math.max(height(n.left), height(n.right)) + 1;
int heightDiff = heightDiff(n);
if (heightDiff < -1) {
if (heightDiff(n.right) > 0) {
n.right = rightRotate(n.right);
return leftRotate(n);
} else {
return leftRotate(n);
}
} else if (heightDiff > 1) {
if (heightDiff(n.left) < 0) {
n.left = leftRotate(n.left);
return rightRotate(n);
} else {
return rightRotate(n);
}
} else;
}
return n;
}
private AVLNode<T> leftRotate(AVLNode<T> n) {
AVLNode<T> r = n.right;
n.right = r.left;
r.left = n;
n.height = Math.max(height(n.left), height(n.right)) + 1;
r.height = Math.max(height(r.left), height(r.right)) + 1;
return r;
}
private AVLNode<T> rightRotate(AVLNode<T> n) {
AVLNode<T> r = n.left;
n.left = r.right;
r.right = n;
n.height = Math.max(height(n.left), height(n.right)) + 1;
r.height = Math.max(height(r.left), height(r.right)) + 1;
return r;
}
private int heightDiff(AVLNode<T> a) {
if (a == null) {
return 0;
}
return height(a.left) - height(a.right);
}
private int height(AVLNode<T> a) {
if (a == null) {
return 0;
}
return a.height;
}
}
Here's a full implementation of AVL tree in Java
class Node {
int key;
Node left;
Node right;
int height;
Node(int value) {
key = value;
left = null;
right = null;
height = 1;
}
}
class AVLTree {
Node root;
int height(Node root) {
if (root == null)
return 0;
return root.height;
}
int findHeight() {
return height(root);
}
int findHeightFrom(int value) {
Node node = search(root, value);
if (node == null)
return -1;
return node.height;
}
Node search(Node root, int value) {
if (root == null)
return null;
else {
if (value == root.key)
return root;
else if (value < root.key)
return search(root.left, value);
else
return search(root.right, value);
}
}
boolean find(int value) {
Node node = search(root,value);
if (node == null)
return false;
return true;
}
int max(int one, int two) {
return (one > two) ? one : two;
}
Node rightRotate(Node root) {
Node rootLeftChild = root.left;
root.left = rootLeftChild.right;
rootLeftChild.right = root;
root.height = max(height(root.left), height(root.right)) + 1;
rootLeftChild.height = max(height(rootLeftChild.left), height(rootLeftChild.right)) + 1;
return rootLeftChild;
}
Node leftRotate(Node root) {
Node rootRightChild = root.right;
root.right = rootRightChild.left;
rootRightChild.left = root;
root.height = max(height(root.left), height(root.right)) + 1;
rootRightChild.height = max(height(rootRightChild.left), height(rootRightChild.right)) + 1;
return rootRightChild;
}
Node insertNode(Node root, int value) {
if (root == null)
root = new Node(value);
else {
if (value < root.key)
root.left = insertNode(root.left, value);
else
root.right = insertNode(root.right, value);
}
root.height = max(height(root.left), height(root.right)) + 1;
int balanceFactor = height(root.left) - height(root.right);
if (balanceFactor > 1) {
// either left-left case or left-right case
if (value < root.left.key) {
// left-left case
root = rightRotate(root);
} else {
// left-right case
root.left = leftRotate(root.left);
root = rightRotate(root);
}
} else if (balanceFactor < -1) {
// either right-right case or right-left case
if (value > root.right.key) {
// right-right case
root = leftRotate(root);
} else {
// right-left case
root.right = rightRotate(root.right);
root = leftRotate(root);
}
}
return root;
}
void insert(int value) {
root = insertNode(root, value);
}
void inorder(Node root) {
if (root != null) {
inorder(root.left);
System.out.print(root.key + " ");
inorder(root.right);
}
}
void inorderTraversal() {
inorder(root);
System.out.println();
}
void preorder(Node root) {
if (root != null) {
System.out.print(root.key + " ");
preorder(root.left);
preorder(root.right);
}
}
void preorderTraversal() {
preorder(root);
System.out.println();
}
}
public class AVLTreeExample {
public static void main(String[] args) {
AVLTree avl = new AVLTree();
avl.insert(10);
avl.insert(20);
avl.insert(30);
avl.insert(40);
avl.insert(50);
avl.insert(25);
System.out.print("Inorder Traversal : "); avl.inorderTraversal();
System.out.print("Preorder Traversal : "); avl.preorderTraversal();
System.out.println("Searching for 10 : " + avl.find(10));
System.out.println("Searching for 11 : " + avl.find(11));
System.out.println("Searching for 20 : " + avl.find(20));
System.out.println("Height of the tree : " + avl.findHeight());
System.out.println("Finding height from 10 : " + avl.findHeightFrom(10));
System.out.println("Finding height from 20 : " + avl.findHeightFrom(20));
System.out.println("Finding height from 25 : " + avl.findHeightFrom(25));
}
}
in order to rotate it right
you need to first check if the parent is not root
then if the parent is the right of the grand parent
if so, set the right of the grand parent to the child
else, set the left of the gran parent to the child
otherwise,
root is child