I am trying to implement a search algorithm which uses recursion method.
The algorithm should expand startnode to its neighbouring nodes and then select the neighbouring node with least cost and then add that cost to the pathcost(which is initially 0) and the selected least cost node will become the startnode and the search continues again recursively until goalnodeis found.
Below is my code for implementing this recursion. It isn't giving me any errors but it is not giving me the expected solution.
INSTEAD it is adding the cost of each and every neighbouring node (I only need it to add the leastcost node). I have been trying to do it, but can't seem to find any clue how to do it.
Queue<String> frontierNodes = new PriorityQueue<String>();
Queue<Node1> frontierCosts = new PriorityQueue<Node1>(); // here Node1 is class storing the start, end and cost of the map.
public void Search(Node1[] nodes, String startnode, String goalnode, int size, double pathcost){
for(int i=0; i<size;i++) {
if(startnode.equalsIgnoreCase(nodes[i].getStartNode())) {
frontierNodes.add(nodes[i].getEndNode());
frontierCosts.add(new Node1(nodes[i].getCost()));
System.out.println("Frontier Nodes are " +frontierNodes);
System.out.println("Path cost till now "+pathcost);
// Something should be implemented here to add only the least cost
pathcost += frontierCosts.peek().toCostString();
System.out.println("Path cost till now "+pathcost);
}
}
System.out.println("Expanding node... " +frontierNodes.peek());
//Recursive call
Search(nodes, frontierNodes.poll(), goalnode, nodes.length-(frontierNodes.size()), pathcost);
}
I'm not sure why you want to use the PriorityQueue. You should be keeping everything within the scope of the recursive method. For tree traversal recursively, you want to follow the general pattern (psuedo code)
int sumOfLeastCost(Node node){
if(node == null){ return 0; }
int sum = 0;
Node min = null;
for each child{
if(min == null){
min = currentChild;
}else if(currentChild.getCost() < min.getCost()){
min = currentChild;
sum = min.getCost();
}
}
return sum + sumOfLeastCost(min);
}
This will only follow the branches of minimal cost nodes.
Is this closer to what you need?
public double Search(ArrayList<Node1> nodes, String startnode, String goalnode, double pathcost){
//Probably needs a better data structure to hold these
ArrayList<String> neighbours = new ArrayList<>();
ArrayList<Double> neighbourPathCosts = new ArrayList<>();
int i;
for(i=0; i<nodes.size();i++) {
if(startnode.equalsIgnoreCase(nodes.get(i).getStartNode())) {
neighbours.add(nodes.get(i).getEndNode());
neighbourPathCosts.add(nodes.get(i).getCost());
}
}
int indexOfCheapest = -1;
double cheapest = Double.MAX_VALUE;
for(int j = 0; j < neighbours.size(); j++){
if(cheapest > neighbourPathCosts.get(i)){
cheapest = neighbourPathCosts.get(i);
indexOfCheapest = i;
}
}
pathcost += neighbourPathCosts.get(indexOfCheapest);
System.out.println("Path cost till now " + pathcost);
String nextNode = neighbours.get(indexOfCheapest);
System.out.println("Expanding node... " + nextNode );
if(startNode.equals(goalNode)){
return pathcost;
}else{
nodes.remove(i);
//Recursive call
return Search(nodes, nextNode, goalnode, pathcost);
}
}
Related
I hope someone can help with the issue I am having. First of all, I tried to remove as much code as I can that wasn't causing the issue.
My problem is this: When I run the program everything runs perfectly until I create a graph with about 130 nodes. Once it hits 130+ nodes the program will run forever in an infinite loop.
I try running the program with 135 nodes at 15 for the desired graph density.
To give some context I am working on research simulations and for this I am creating random graphs and building spanning trees using BFS.
My problem arises during the creation of the Spanning Tree.
Copy and paste code and compile using javac MMB.java all in one file.
import java.util.*;
/**
* Custom type Set used to differentiate nodes in the FAST and SLOW sets
*/
enum Set {
FAST, SLOW;
}
/**
* Custom node class used to store our spanning tree
*/
class Node<T> {
private T data;
private Node<T> parent;
private List<Node<T>> children;
private int level;
private int rank;
private Set set;
// constructor for root Nodes and stand alone nodes
public Node(T data){
this.data = data;
this.parent = null;
this.level = 0;
this.rank = Integer.MIN_VALUE;
this.children = new ArrayList<Node<T>>();
}
// constructor for all non root nodes
public Node(T data, Node<T> parent){
this.data = data;
this.setParent(parent);
this.level = (parent.getLevel()) + 1;
this.rank = Integer.MIN_VALUE;
this.children = new ArrayList<Node<T>>();
}
// get data
public T getData(){
return this.data;
}
// set data
public void setData(T data){
this.data = data;
}
// add child node
public void addChild(Node<T> child){
children.add(child);
}
// remove child node
public void removeChild(Node<T> child){
children.remove(child);
}
// get rank
public int getRank(){
return this.rank;
}
// set rank
public void setRank(int rank){
this.rank = rank;
}
// get parent
public Node<T> getParent(){
return this.parent;
}
// set parent - updates parent node to have child
public void setParent(Node<T> parent){
this.parent = parent;
parent.addChild(this);
}
// returns level of a Node
public int getLevel(){
return this.level;
}
// returns a list of children of a given node
public List<Node<T>> getChildren(){
return this.children;
}
// set the Set a node is in
public void setSet(Set set){
this.set = set;
}
// get the Set a node is in
public Set getSet(){
return this.set;
}
// returns the tree as a list of nodes using DFS traversal
public List<Node<T>> treeToList(){
List<Node<T>> list = new LinkedList<Node<T>>();
List<Node<T>> visitedNodes = new LinkedList<Node<T>>();
list.add(this);
while(list.size() > 0){
Node<T> currentNode = list.get(list.size() - 1);
List<Node<T>> currentNodesChildren = currentNode.getChildren();
if(!visitedNodes.contains(currentNode)){
for(Node<T> n : currentNodesChildren){
list.add(n);
}
visitedNodes.add(currentNode);
}
else {
list.remove(currentNode);
}
}
return visitedNodes;
}
// returns the number of levels in the tree
// Note: levels start at 0
public int numberOfLevels(){
List<Node<T>> list = this.treeToList();
int maxLevel = 0;
for(Node<T> n : list)
if(n.getLevel() > maxLevel)
maxLevel = n.getLevel();
return maxLevel + 1;
}
// returns the max rank in the tree
public int maxRank(){
List<Node<T>> list = this.treeToList();
int maxRank = 0;
for(Node<T> n : list)
if(n.getRank() > maxRank)
maxRank = n.getRank();
return maxRank;
}
// returns a list of nodes with a given rank and level in the FAST set
public List<Node<T>> nodeRankLevelSubset(int rank, int level){
List<Node<T>> list = this.treeToList();
List<Node<T>> subset = new LinkedList<Node<T>>();
for(Node<T> n : list)
if(n.getRank() == rank && n.getLevel() == level && n.getSet() == Set.FAST)
subset.add(n);
return subset;
}
// Print All
public void printAll(){
List<Node<T>> list = this.treeToList();
for(Node<T> n : list){
System.out.println("{");
System.out.println(" \"data\": " + n.getData() + ",");
System.out.println(" \"level\": " + n.getLevel() + ",");
System.out.println(" \"rank\": " + n.getRank() + ",");
switch(n.getSet()){
case FAST:
System.out.println(" \"set\": \"FAST\"");
break;
case SLOW:
System.out.println(" \"set\": \"SLOW\"");
break;
}
System.out.print(" \"parent\": ");
if(n.getParent() != null)
System.out.println(n.getParent().getData() + ",");
else
System.out.println(" ,");
System.out.print(" \"children\": [");
for(Node<T> cn : n.getChildren()){
System.out.print(cn.getData() + ",");
}
System.out.println("]\n}");
}
}
// BFS to print
public void printTree(){
List<Node<T>> discoveredNodes = new LinkedList<Node<T>>();
List<Node<T>> queue = new LinkedList<Node<T>>();
List<Node<T>> children;
Node<T> currentNode;
queue.add(this);
discoveredNodes.add(this);
while(queue.size() > 0){
currentNode = queue.remove(0);
children = currentNode.getChildren();
System.out.print("\n" + currentNode.getData() + ": ");
for(Node<T> n : children){
queue.add(n);
discoveredNodes.add(n);
System.out.print(n.getData() + " " + " Rank: " + n.getRank() + " ");
}
}
System.out.print("\n");
}
}
public class MMB {
// boolean 2D array used to make the edges in a random graph
public static boolean[][] randomGraph;
// custom Node class used to store our BFS spanning tree
public static Node<Integer> spanningTree;
public static void main(String[] args){
int numberOfNodes, graphDensity;
Scanner scanner = new Scanner(System.in);
System.out.print("Enter the desired number of Nodes: ");
numberOfNodes = scanner.nextInt();
System.out.print("Enter the desired graph density: ");
graphDensity = scanner.nextInt();
randomGraph = randomGraph(numberOfNodes, graphDensity);
/* Print Out Graph */
for(int i = 0; i < randomGraph.length; i++){
System.out.print(i + " ");
for(int j = 0; j < randomGraph.length; j++){
System.out.printf(" " + randomGraph[i][j] + " ");
}
System.out.println("");
}
System.out.println("");
System.out.println("HERE - CREATED GRAPH");
spanningTree = spanningTree(0);
System.out.println("HERE - CREATED SPAnnING TREE");
// rankNodes(spanningTree, spanningTree.numberOfLevels());
// System.out.println("HERE - FIRST RANK");
// determineSet(spanningTree);
// System.out.println("HERE - DETERMINE SET");
// //spanningTree.printTree();
// reRankNodes(spanningTree);
// System.out.println("HERE - RERANK NODES");
// //spanningTree.printTree();
// spanningTree.printAll();
}
/**
* Create an undirected graph at random
* A 2D boolean array will represent the edges between nodes
* #param numberOfNodes number of nodes in the graph
* #param graphDensity integer percentage of graph density
*/
public static boolean[][] randomGraph(int numberOfNodes, int graphDensity){
boolean[][] graph = new boolean[numberOfNodes][numberOfNodes];
Random randomNumber = new Random();
boolean hasEdge;
for(int i = 0; i < numberOfNodes; i++){
hasEdge = false;
for(int j = 0; j < numberOfNodes; j++){
// i != j ensures no loops
if(i != j && (randomNumber.nextInt(100) + 1) < graphDensity){
graph[i][j] = true;
graph[j][i] = true;
hasEdge = true;
}
}
// to ensure no disconnected nodes, keep track with hasEdge
// if no edge exists create a random one
int randomNum;
while(!hasEdge){
if((randomNum = randomNumber.nextInt(numberOfNodes)) != i){
graph[i][randomNum] = true;
graph[randomNum][i] = true;
hasEdge = true;
}
}
}
return graph;
}
/**
* Create a Spanning Tree from an undirected graph using BFS
* A custom Node structure will represent our spanning tree
* #param root root of undirected graph from 0 to numberOfNodes-1
*/
public static Node<Integer> spanningTree(int root){
Node<Integer> tree = new Node<Integer>(root);
Node<Integer> currentNode;
Integer currentNodeData;
LinkedList<Node<Integer>> discoveredNodes = new LinkedList<Node<Integer>>();
LinkedList<Node<Integer>> queue = new LinkedList<Node<Integer>>();
queue.add(tree);
discoveredNodes.add(tree);
while(queue.size() > 0){
currentNode = queue.removeFirst();
currentNodeData = currentNode.getData();
for(int i = 0; i < randomGraph.length; i++){
if(randomGraph[currentNodeData][i] && !listContainsNode(discoveredNodes, i)){
Node<Integer> newNode = new Node<Integer>(i, currentNode);
queue.add(newNode);
discoveredNodes.add(newNode);
}
}
}
return tree;
}
/* Helper Methods */
// search a list of Nodes for a value
public static boolean listContainsNode(List<Node<Integer>> list, Integer data){
for(Node<Integer> n : list)
if(n.getData() == data)
return true;
return false;
}
}
In cauda venenum
/* Helper Methods */
// search a list of Nodes for a value
public static boolean listContainsNode(List<Node<Integer>> list, Integer data){
for(Node<Integer> n : list)
if(n.getData() == data) // <-- Can you spot the bug?
return true;
return false;
}
The problem is that you compare Integer's with ==. With numbers lower than 128 it works because integers are interned, but then the comparison on objects doesn't work anymore.
Just use:
if (n.getData().equals(data))
to compare node contents (and keep up writing great code ;) - it's not easy to see such quality in StackOverflow's questions)
Well, I found a potential dangerous code, if you matrix would not be squared, so you should use
for(int i = 0; i < randomGraph[currentNodeData].length; i++){
instead of
for(int i = 0; i < randomGraph.length; i++){
And I think that I maybe found the nested exception :).
If you are using Integer instead of int, you have to care about == operator. Java makes static Integers for values -127 to 128, but when you reach it, it does not work anymore!!
This code
Integer x;
Integer y;
x = 111;
y = 111;
System.out.println(x == y);
x = 130;
y = 130;
System.out.println(x == y);
Is having this output
true
false
Using equals is safe however, this code :
Integer x;
Integer y;
x = 111;
y = 111;
System.out.println(x.equals(y));
x = 130;
y = 130;
System.out.println(x.equals(y));
Is having this output
true
true
I have some problem checking if my adjacency list has a cycle or not.
I want to make a function that checks if my adjacency list has existing at least one cycle.
Based on my program. First, I have to input the Root Node, followed by a number of nodes, the nodes in the graph, number of edges, and the adjacency list representing the edges. Each entry in the adjacency list contains a pair of nodes.
Sample input:
Root node: "A"
Number of nodes: 3
Vertices/Nodes:
A
B
C
Number of edges: 3
A
B
B
C
C
A
A --> B
B --> C
C --> A
The sample input above has a cycle: [ A --> B --> C --> A ] I want to output whether it has a cycle or not.
This is my program so far:
import java.util.Scanner;
class Neighbor {
public int vertexNum;
public Neighbor next;
public Neighbor(int vnum, Neighbor nbr) {
this.vertexNum = vnum;
next = nbr;
}
}
class Vertex {
String name;
Neighbor adjList;
Vertex(String name, Neighbor neighbors) {
this.name = name;
this.adjList = neighbors;
}
}
public class DirectedCycle {
Vertex[] adjLists;
public DirectedCycle() {
Scanner sc = new Scanner(System.in);
//Root Node
System.out.print("Root node: ");
String rn = sc.nextLine();
//Number of nodes
System.out.print("Number of vertices/nodes: ");
int nodes = sc.nextInt();
adjLists = new Vertex[nodes];
//List of nodes
System.out.println("Vertices:");
for (int v=0; v < adjLists.length; v++) {
String letter = sc.next();
adjLists[v] = new Vertex(letter, null);
}
//Number of edges
System.out.print("Number of edges: ");
int edges = sc.nextInt();
System.out.println("<v1> <v2>");
for(int i=0; i<edges; i++) {
int v1 = indexForName(sc.next());
int v2 = indexForName(sc.next());
adjLists[v1].adjList = new Neighbor(v2, adjLists[v1].adjList);
}
}
int indexForName(String name) {
for (int v=0; v < adjLists.length; v++) {
if (adjLists[v].name.equals(name)) {
return v;
}
}
return -1;
}
public void print() {
System.out.println();
for (int v=0; v < adjLists.length; v++) {
System.out.print(adjLists[v].name);
for (Neighbor nbr=adjLists[v].adjList; nbr != null; nbr=nbr.next) {
String name = adjLists[nbr.vertexNum].name;
System.out.print(" --> " + name);
}
System.out.println("\n");
}
}
public static void main(String[] args) {
DirectedCycle graph = new DirectedCycle();
graph.print();
}
}
My program above doesn't have yet a function that checks cycle and also I want to implement the root node thing.. If anyone can improve my program above just answer me and give me some code I can rely. Thanks! (I'm beginner!)
The most efficient way to detect a cycle in Floyd's Cycle detection algo., which is basically moving two pointers over the linked list, one moving at normal one step at a time slow pointer and the other with double the speed of the slow pointer, i.e fast pointer.
Java code for the same.
boolean detectloop(Node list) {
if(list == null)
return false;
Node slow, fast;
slow = fast = list;
while(true) {
slow = slow.next;
if(fast.next != null)
fast = fast.next.next;
else
return false;
if(slow == null || fast == null)
return false;
if(slow == fast)
return true;
}
}
To check a cycle of a linked list, you want to iterate though with two different pointers, one moving through the list twice as fast. If there is a cycle, it will eventually be detected using this method. Also, for the end condition, you can check to see if all nodes have been visited, and if so, there is no cycle.
I have the following homework assignment:
Add a new method retrieveAt for the class IntSLList that takes an integer index position as a parameter.
The method returns the info inside the node at the index position. The index of the first node is 0. If the list is empty or the index is invalid, then display an error message.
I have implemented a solution using the following code:
public int retrieveAt(int pos){
IntSLLNode tmp;
int count = 0;
int c;
for(tmp = head; tmp != null; tmp = tmp.next){
count++;
}
if(isEmpty()|| count<pos){
return 0;
} else {
IntSLLNode tmp1 = head;
for(int i = 1; i < pos; i++){
if(tmp1.next == null)
return 0;
tmp1 = tmp1.next;
}
return tmp1.info;
}
}
It appears to traverse the list properly, but it does not retrieve the correct element.
An example case where this does not appear to give the correct output:
IntSLList myn = new IntSLList();
myn.addToHead(10);
myn.addToHead(20);
myn.addToHead(30);
myn.addToHead(40);
myn.addToTail(60);
myn.printAll();
int x = myn.retrieveAt(4);
if(x == 0)
System.out.println("NOT VALID ");
else
System.out.println("elm : " + x);
The output is:
40
30
20
10
60
elm : 10
int x=myn.retrieveAt(4);
you get the forth element, because you used the magical number 4. I'd suggest using either the number of elements in myn, or find out if you have an easier way to do this in your implementation of the IntSLList class.
I'm not sure what addToHead is supposed to do (add at the beginning or at the end).
I created this little example class that does both, please pick the method that fits your terminology.
The example is by no means complete, does no error checking, etc.
I tried to read your code and felt the for loops are very confusing.
Maybe this is what confuses you, too? That's why I made this example, that puts you into the position of each Node to figure out what to do next and works recursively.
The basic operations involved in adding an element are:
Do I know a next node? (is this the end of the chain?)
Should I pass my own value onto the next node or the value that was passed onto me? (where should a new value be added? end or beginning?)
public class Node
{
private Node next;
private Integer value;
public Node()
{
}
public void push(Integer value)
{
if(next != null)
next.push(value);
else
{
next = new Node();
this.value = value;
}
}
public void unshift (Integer value)
{
if(next != null)
{
next.unshift(this.value);
}
else
{
next = new Node();
next.value = this.value;
}
this.value = value;
}
public Integer get(int index)
{
if(index > 0)
return next.get(--index);
else
return value;
}
public int length()
{
if(next == null)
return 0;
else
return next.length() + 1;
}
public static void main(String[] args)
{
Node pushedList = new Node();
pushedList.push(10);
pushedList.push(20);
pushedList.push(30);
pushedList.push(40);
for(int i = 0; i < pushedList.length(); ++i)
{
System.out.println("pushed element #" + i +": " + pushedList.get(i));
}
Node unshiftedList = new Node();
unshiftedList.unshift(10);
unshiftedList.unshift(20);
unshiftedList.unshift(30);
unshiftedList.unshift(40);
for(int i = 0; i < unshiftedList.length(); ++i)
{
System.out.println("unshifted element #" + i +": " + unshiftedList.get(i));
}
Node mixedList = new Node();
mixedList.unshift(10);
mixedList.push(20);
mixedList.unshift(30);
mixedList.push(40);
for(int i = 0; i < mixedList.length(); ++i)
{
System.out.println("mixed element #" + i +": " + mixedList.get(i));
}
}
}
Edit: here's the output I receive:
pushed element #0: 10
pushed element #1: 20
pushed element #2: 30
pushed element #3: 40
unshifted element #0: 40
unshifted element #1: 30
unshifted element #2: 20
unshifted element #3: 10
mixed element #0: 30
mixed element #1: 10
mixed element #2: 20
mixed element #3: 40
Consider a binary tree with the following properties:
An internal node (non-leaf node) has a value 1 if it has two children.
A leaf node has a value 0 since it has no children.
A level order traversal on the tree would generate a string of 1s and 0s (by printing the weird value at each node as they are visited). Now given this string construct the binary tree and perform a post order traversal on the tree. The post order string should be the output of the program.
For example: Input String is 111001000. Create a binary tree from this. Then perform the post order traversal on the tree which would result in an output: 001001011
The "crux" of the problem is to create the binary tree from just the level order string. How would I do this?
Taking your example of level order traversal - 111001000
The tree would be as follows
A
/ \
B C
/\ /\
D E F G
/\
H I
The logic is as follows.
1) Take first bit if its 1 (root) - then next 2^1 are values of children of that parent. So 2nd and 3rd bits are childern of A (root).
2) Go to next bit (1 for B) as its value is also 1 it also has 2 children and then next bit (1 for C) which also has 2 children. Second level is over and as we have 2 1's so 2^2 next bits are for level 3.
3) 111 001000 so this we have traversed and next 4 bits are children on 3rd level. 4th and 5th bits being 0 (D and E are leaf nodes and have no children - These will be children of B) and then F has bit value of 1 so 1110010 00 (bold figures) will be children of F. 7th bit is 0 and so G will also be leaf node.
4) Again loop through or try recusion - From 4th,5th and 6th and 7th bits only one bit is 1 so next 2^1 bits will be in next level and those will be children of F.
Once the tree is made then converting to PostFix is easy.
One possible solution (in less than an hour):
import java.util.ArrayList;
import java.util.List;
public class Main {
private static class Node {
private Node left;
private Node right;
}
private static Node buildTree(String input) {
char chars[] = input.toCharArray();
if (chars.length == 0) {
return null;
} else {
Node root = new Node();
List<Node> nodeList = new ArrayList<Node>();
nodeList.add(root);
int pos = 0;
while (!nodeList.isEmpty()) {
List<Node> nextList = new ArrayList<Node>();
for (Node n: nodeList) {
if (pos >= chars.length) {
throw new RuntimeException("Invalid input string");
}
char c = chars[pos++];
if (c == '1') {
n.left = new Node();
n.right = new Node();
nextList.add(n.left);
nextList.add(n.right);
} else if (c != '0') {
throw new RuntimeException("Invalid input string");
}
}
nodeList = nextList;
}
return root;
}
}
private static String postTraverse(Node n) {
if (n == null) {
return "";
} else if (n.left == null && n.right == null) {
return "0";
} else {
return postTraverse(n.left) + postTraverse(n.right) + "1";
}
}
public static void main(String[] args) {
Node tree = buildTree(args[0]);
System.out.println(postTraverse(tree));
}
}
If it was allowed, I would use a binary heap as a helper here. In a binary heap implemented using a standard table, given an index of an element we can easily calculate its parent's index: int parent = (index-1)/2;. Knowing this, we would need to start at the beginning of our table and do the folowing:
Set the binaryHeap[0] to the first number from the input stream;
for all the remaining elements in input stream:
do{
binaryHeap[heapIndex] = -1;
if (parent(heapIndex) = 1)
binaryHeap[heapIndex] = nextElementFromTheInputStream;
heapIndex++;
}
while(binaryHeap[heapIndex - 1] == 0);
So basically, we move through our table. We initialize each field (except root at 0) to be -1, which means there is no node there. Then we check if the parent of that field was 1. If it was, then we place next element from the input stream on our current index in the heap (heapIndex). If the parent of a current field is 0, we just go further, because that means our parent is a leaf and is not supposed to have any children.
Then we can run post-order algorithm on the heap (probably it would be worth implementing some security-code, so that no element with "-1" is placed in the output stream. Just interpret leftChild(heapIndex) == -1; or rightChild(heapIndex) == -1; to be NULL).
This algorithm is probably quite inefficient in terms of memory, but I hope it is quite easy to understand.
First, I assume that your level order traversal is basically a BFS.
Now, let's have a look at the string. Performing the BFS, we print "1" if the current node's got two sons. Otherwise, it's a leaf and we print 0, terminating the processing of the current branch.
Consequently, during the reverse task, we can remember the list of open branches' last nodes and append the incoming nodes there.
Let's demonstrate this approach on an example:
Level 1:
Tree :
1 - id 0
Open branches : 0 0 (left and right son)
Remaining string : 11001000
*********
Level 2:
Tree :
1
1 1
Open branches : 1 1 2 2
Remaining string : 001000
*********
Level 3:
Tree :
1
1 1
0 0 1 0
Open branches : 5 5
Remaining string : 00
Level 4:
Tree :
1
1 1
0 0 1 0
0 0
No more input, we're done.
Having the tree, the post-order traversal is trivial.
And the code (it assumes that the tree is quite dense, otherwise it's not very memory efficient):
import java.util.ArrayDeque;
import java.util.Queue;
public class Main {
static final int MAX_CONST = 50;
public static void main(String[] args) {
String evilString = "111001000"; // Assuming this string is a correct input
char[] treeRepr = new char[MAX_CONST];
Queue<Integer> q = new ArrayDeque<Integer>();
q.add(0);
for (int i = 0; i < evilString.length(); ++i) {
int index = q.remove();
char ch = evilString.charAt(i);
if (ch == '1') {
q.add(2*(index+1)-1);
q.add(2*(index+1));
}
treeRepr[index] = ch;
// System.out.println(q.size());
}
System.out.println(arrToString(treeRepr, 0, new StringBuilder()));
}
public static StringBuilder arrToString(char[] array, int index, StringBuilder sb) {
if (array[index] == '1')
{
arrToString(array, 2*(index+1)-1, sb);
arrToString(array, 2*(index+1), sb);
}
sb.append(array[index]);
return sb;
}
}
Here is a pretty simple solution. Not really optimal with
respect to memory though, as I build a complete/full tree first
and then I mark which nodes actually exist in our tree. So this
could be optimized a bit, I guess.
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
class Node {
public Node left;
public Node right;
public Integer id;
public boolean exists;
}
public class Test32 {
public static void main(String[] args) {
HashMap<Integer, Node> mp = new HashMap<Integer, Node>();
String str = "110101000";
int sz = (int)Math.pow(2, str.length() + 1);
for (int i=0; i<sz; i++){
Node nd = new Node();
nd.id = i;
mp.put(nd.id, nd);
}
for (int i=0; i<sz; i++){
Node nd = mp.get(i);
if (2*i < sz) nd.left = mp.get(2*i + 1);
if (2*i + 1 < sz) nd.right = mp.get(2*i + 2);
}
Queue<Integer> visit = new LinkedList<Integer>();
visit.add(0); // id = 0;
int j = 0;
int id = -1;
while (!visit.isEmpty()){
id = visit.poll();
if (str.charAt(j) == '1'){
mp.get(id).exists = true;
visit.add(2*id + 1);
visit.add(2*id + 2);
}else{
mp.get(id).exists = true;
}
j++;
}
System.out.println("NODES:");
for (int i=0; i<sz; i++){
if (mp.get(i).exists){
System.out.println(i);
}
}
System.out.println();
System.out.println("EDGES:");
for (int i=0; i<sz; i++){
if (mp.get(i).exists){
if (mp.get(2 * i + 1).exists){
System.out.println(i + " --> " + (2*i+1));
}
if (mp.get(2 * i + 2).exists){
System.out.println(i + " --> " + (2*i+2));
}
}
}
}
}
And here is the same solution simplified edition.
No trees or maps, just a boolean array. If some node
k has children these children are 2*k+1 and 2*k+2.
In the last loop while printing the edges one can also
construct an actual binary tree.
import java.util.LinkedList;
import java.util.Queue;
public class Test32 {
public static void main(String[] args) {
String str = "110101000";
int sz = (int)Math.pow(2, str.length() + 1);
boolean exists[] = new boolean[sz];
Queue<Integer> visit = new LinkedList<Integer>();
visit.add(0); // id = 0;
if (str.charAt(0) == '1'){
exists[0] = true;
}
int j = 0;
int id = -1;
while (!visit.isEmpty()){
id = visit.poll();
if (str.charAt(j) == '1'){
exists[id] = true;
visit.add(2*id + 1);
visit.add(2*id + 2);
}else{
exists[id] = true;
}
j++;
}
// System.out.println("");
System.out.println("NODES:");
for (int i=0; i<sz; i++){
if (exists[i]){
System.out.println(i);
}
}
System.out.println("");
System.out.println("EDGES:");
for (int i=0; i<sz; i++){
if (exists[i]){
if (exists[2*i+1]){
System.out.println(i + " --> " + (2*i+1));
}
if (exists[2*i+2]){
System.out.println(i + " --> " + (2*i+2));
}
}
}
}
}
Conceptually more simpler I think.
import java.util.LinkedList;
import java.util.Queue;
class WeirdBinaryTree
{
static class Node
{
private Node right;
private Node left;
private int weirdValue;
public void setWeirdValue(int value)
{
weirdValue=value;
}
}
private static Node makeTree(String str)throws Exception
{
char[] array=str.toCharArray();
Node root=new Node();
Queue<Node> list=new LinkedList();
list.add(root);
int i=0;
Queue<Node> nextList=new LinkedList<Node>();
while(!list.isEmpty())
{
if(array[i++]=='1')
{
Node temp=list.poll();
temp.left=new Node();
temp.right=new Node();
temp.setWeirdValue(1);
nextList.add(temp.left);
nextList.add(temp.right);
}
else
{
list.poll();
}
if(list.isEmpty())
{
list=nextList;
nextList=new LinkedList<Node>();
}
}
return root;
}
private static void postTraversal(Node localRoot)
{
if(localRoot!=null)
{
postTraversal(localRoot.left);
postTraversal(localRoot.right);
System.out.print(localRoot.weirdValue);
}
}
public static void main(String[] args)throws Exception
{
postTraversal(makeTree("111001000"));
}
}
I've been searching all over for some pointers and have been coming up a bit short. I have an assignment for a project where we have to make a btree implementation by extending a 234 Tree class that was given to us.
The 234Tree class is working while the tree is still a 234 tree. It seems that using the insert method from this class breaks when I try to use this as a btree. I've copied the insert method into my btree class as an override in case I have to change something, that way the 234 tree split will still work.
Here's a link to my btree class at pastebin http://pastebin.com/TcP0UMA2
I use all of this from a command prompt. Here's the output when I run it
Enter first letter of show, insert, find, change, read, or quit: s<br/>
level=0 child=0 /20/30/50/70/<br/>
level=1 child=0 /10/<br/>
level=1 child=1 /25/<br/>
level=1 child=2 /35/40/45/<br/>
level=1 child=3 /60/<br/>
level=1 child=4 /80/90/100/<br/>
Enter first letter of show, insert, find, change, read, or quit: i<br/>
Enter value to insert: 85<br/>
Moving 2 items. Those values are 50, 70.<br/>
Exception in thread "main" java.lang.NullPointerException<br/>
at frankaddeliaproject2.BTree.insert(BTree.java:115)<br/>
at frankaddeliaproject2.Tree234App.main(Tree234App.java:43)<br/>
Java Result: 1
The problem I notice ends up being when the parent node becomes full (in this instance it's order of 5, so it wants to split the node on the 5th insert). That's why when trying to insert 85 it breaks at this point.
while(true)
{
if( curNode.isFull() ) // if node full,
{
split(curNode); // split it
curNode = curNode.getParent(); // back up
// search once
curNode = getNextChild(curNode, dValue);
} // end if(node is full)
The nullPointerException is at the line that has this statement:
if( curNode.isFull())
When I look at this block of code I can figure out that it's checking if curNode is full, so it'll run through the first time and the issue seems to be coming when
curNode = getNextChild //...
Because there technically isn't a child after this one. I'm mainly unsure of how to fix it from this point.
Thanks in advance, any help is appreciated!
-Frank
EDIT:
It looks like my link to the class gets a little buried. I'll post it below if that's easier
public class BTree extends Tree234 {
public void split(Node thisNode) // split the node
{
// assumes node is full
int tmp = Node.getOrder();
int counter = 0;
//figures out number of children to move during a move (2^n < x < 2^n+1)
while(tmp >= 2)
{
tmp /= 2;
counter++;
}
DataItem[] items = new DataItem[counter + 1];
for(int x = counter; x > 0; x--)
{
items[x] = thisNode.removeItem();
}
DataItem itemB;
Node parent;
Node[] children = new Node[counter];
int itemIndex;
itemB = thisNode.removeItem(); // this node
//makes array of children to move
int tmpcount = 0;
for(int i = counter; i > 0; i--)
{
children[tmpcount] = thisNode.disconnectChild(Node.getOrder() - i);
tmpcount++;
}
Node newRight = new Node(); // make new node
if(thisNode==root) // if this is the root,
{
root = new Node(); // make new root
parent = root; // root is our parent
root.connectChild(0, thisNode); // connect to parent
}
else // this node not the root
parent = thisNode.getParent(); // get parent
// deal with parent
itemIndex = parent.insertItem(itemB); // item B to parent
int n = parent.getNumItems(); // total items?
for(int j=n-1; j>itemIndex; j--) // move parent's
{ // connections
Node temp = parent.disconnectChild(j); // one child
parent.connectChild(j+1, temp); // to the right
}
// connect newRight to parent
parent.connectChild(itemIndex+1, newRight);
// deal with newRight
// moves items to newRight
// then alerts how many items are being moved and the values
String msg = "Moving " + counter + " items. Those values are ";
for(int y = 0; y < counter + 1; y++)
{
if(items[y] == null)
{
continue;
}
newRight.insertItem(items[y]);
//build output message
if(y < counter)
msg += items[y].dData + ", ";
else
msg += items[y].dData + ". ";
}
//outputs message
System.out.println(msg);
//reconnect children to new parent
for(int j = 0; j < counter; j++)
{
newRight.connectChild(j, children[j]);
}
} // end split()
// -------------------------------------------------------------
// gets appropriate child of node during search for value
public void insert(long dValue)
{
Node curNode = root;
DataItem tempItem = new DataItem(dValue);
while(true)
{
if( curNode.isFull() ) // if node full,
{
split(curNode); // split it
curNode = curNode.getParent(); // back up
// search once
curNode = getNextChild(curNode, dValue);
} // end if(node is full)
else if( curNode.isLeaf() ) // if node is leaf,
break; // go insert
// node is not full, not a leaf; so go to lower level
else
curNode = getNextChild(curNode, dValue);
} // end while
curNode.insertItem(tempItem); // insert new DataItem
} // end insert()
// -------------------------------------------------------------
}
I don't know whether you have an underlying problem from just that snippet but you can solve the NullPointerException by simply checking curNode first.
if(curNode != null && curNode.isFull() ) // if node full,
{
split(curNode); // split it
curNode = curNode.getParent(); // back up
// search once
curNode = getNextChild(curNode, dValue);
} // end if(node is full)