I have a binary tree that I need to search through. I'm not searching for one specific node of the tree, but rather over every node of the tree to gain information about them. I have a simple recursive search right now, but every time it runs I get a stack overflow error. It's a full binary tree of depth 7...
if (curDepth < 6 && !searchedNodes[curID * 2])
depthSearch(curNode.getRight());
if (curDepth < 6 && !searchedNodes[curID * 2 + 1])
depthSearch(curNode.getLeft());
if (curID != 1 && !searchedNodes[(int) (curID / 2)])
depthSearch(curNode.getParent());
The curID == 1 corresponds to the root node, so I need to check that it's
not the parent. The searchedNodes thing is to make sure i don't search
the same node twice. Any ideas on how to do this?
edit: here's the entire search method
public void depthSearch(AntTree curNode) {
boolean[] searchedNodes = new boolean[128];
if (curNode == null)
return;
int curID = curNode.getID();
searchedNodes[curID] = true;
if (curNode.getFood() > 0) {
AntScript.foodLocs[curID] = 1;
} else {
Ant6Script.foodLocs[curID] = 0;
}
Ant[] ants = curNode.getAnts();
boolean containsWorker = false, containsSoldier = false;
if (ants != null) {
for (int i = 0; i < ants.length; i++) {
if (ants[i].type().equals("Worker")
&& ants[i].teamID() != AntScript.myTeamID) {
containsWorker = true;
} else if (ants[i].type().equals("Soldier")
&& ants[i].teamID() != AntScript.myTeamID) {
containsSoldier = true;
} else if (ants[i].type().equals("Queen")
&& ants[i].teamID() != AntScript.myTeamID) {
AntScript.enemyQueenLoc = curID;
}
}
}
if (containsWorker)
AntScript.enemyWorkerLocs[curID] = 1;
else
AntScript.enemyWorkerLocs[curID] = 0;
if (containsSoldier)
AntScript.enemySoldierLocs[curID] = 1;
else
AntScript.enemySoldierLocs[curID] = 0;
AntScript.viewedNodeLocs[curID] = 1;
int curDepth = (int) (Math.log(curID) / Math.log(2));
if (AntScript.viewedNodeLocs[(int) (curID / 2)] == 0
|| (curDepth < 6 && AntScript.viewedNodeLocs[curID * 2 + 1] == 0)
|| (curDepth < 6 && AntScript.viewedNodeLocs[curID * 2] == 0)) {
if (curDepth < 6
&& AntScript.viewedNodeLocs[curID * 2] == 0
&& !searchedNodes[curID * 2]) {
depthSearch(curNode.getLeft());
}
if (curDepth < 6
&& AntScript.viewedNodeLocs[curID * 2 + 1] == 0
&& !searchedNodes[curID * 2 + 1]) {
depthSearch(curNode.getRight());
}
if (curID != 1
&& AntScript.viewedNodeLocs[(int) (curID / 2)] == 0
&& !searchedNodes[(int) (curID / 2)]) {
depthSearch(curNode.getParent());
}
} else {
if (curDepth < 6 && !searchedNodes[curID * 2]) {
depthSearch(curNode.getRight());
}
if (curDepth < 6 && !searchedNodes[curID * 2 + 1]) {
depthSearch(curNode.getLeft());
}
if (curID != 1 && !searchedNodes[(int) (curID / 2)]) {
depthSearch(curNode.getParent());
}
}
}
The purpose of the viewedNodeLocs array is because i have many ants on a board performing a search from different nodes, and it is better to search through a node that hasn't been searched before than one that has been. I can't just do one big search and then be done because my requests for next nodes are supposed to return null after 13 requests from one ant (this whole thing is from an ant AI thing I'm programming for a game)
Your data structure is most peculiar. It looks like you have flattened the tree into an array of nodes. It makes your algorithm really difficult to understand, and is almost certainly a bad idea.
Having said that, I suspect that the problem is related to the fact that each recursive call to depthSearch allocates a new searchedNodes array. Like I said, your algorithm is ... hard to understand.
I suggest that you represent your binary tree in the conventional way, with each node having a 'left' and 'right' pointer. Then implement the traversal in the way described in the wikipedia article. Better still, take a look at the Java Collections framework and see if one of the existing List/Set/Map implementations does what you are trying to do.
You can use the tree traversal technique to get get the information about all node. Check here
http://en.wikipedia.org/wiki/Pre-order_traversal.
You need traversal, not search.
for example, some psuedo code
void PrintTree( TreeNode node ){
if( node == null ) return;
if( node.Left != null ) PrintTree( node.Left );
if( node.Right != null ) PrintTree( node.Right );
Console.Printline( node.Value );
}
If you want to fire off multiple copies of this code for multiple ants and let only one ant touch any single node, you will need multiple threads and a shared data structure with locking etc.
Better for now to just share a "Map" data structure that each gets a reference to that you build by executing a traversal once. After all a tree of depth 7 is only going to have 128 nodes anyways, so it's not much memory or time to traverse. You can always improve it later if you need to, but at least get it working first.
Related
I want to implement KD tree in java for a data structure project but I have problem with special method that this project wants. In below you can see the format of method that I want.
float[][] findMNearest(float[] point, int m) {}
I implement find nearest neighbor method but for m nearest neighbor I have problem and I can't understand algorithm for solution.
In this picture you can see my implementation for nearest neighbor.
java
private void nearest(KDNode root, KDNode target, int index) {
if (root == null)
return;
visited++;
float d = root.distance(target);
if (best == null || d < bestDistance) {
bestDistance = d;
best = root;
}
if (bestDistance == 0)
return;
float dx = root.getCoordinates()[index] - target.getCoordinates()[index];
index = (index + 1) % k;
nearest(dx > 0 ? root.getLeft() : root.getRight(), target, index);
if (dx * dx >= bestDistance)
return;
nearest(dx > 0 ? root.getRight() : root.getLeft(), target, index);
}
I don't want to use ready library, too.
At the end my friend help me!
Full source of project for answer this question and other questions about kdtree and its methods at https://github.com/Iman9mo/KDTree
problem
Given an array of ints, return true if every 2 that appears in the array is next to another 2.
twoTwo({4, 2, 2, 3}) → true
twoTwo({2, 2, 4}) → true
twoTwo({2, 2, 4, 2}) → false
my code is only mising this case
twoTwo({2, 2, 7, 2, 1}) → false; but returns true;
my code
public boolean twoTwo(int[] nums) {
int notFound = 0;
int i = 0;
boolean found = false;
if (nums.length == 0) {
return true;
}
if (nums.length == 1 && (nums[0] != 2)) {
return true;
}
for (i = 0; i < nums.length - 1; i++) {
if ((nums[i] == 2 && nums[i + 1] == 2)) {
found = true;
}
if (nums[nums.length - 1] == 2 && nums[nums.length - 2] != 2) {
return false;
}
if (nums[i] != 2) {
notFound++;
}
}
if (nums[i] != 2) {
notFound++;
}
if (notFound == nums.length) {
return true;
}
return found;
}
There is never a "wrong" way to code a working solution, but there are bad ways. In your solution, I think you try to handle every individual case in chaotic ways instead of tackling the overarching problem. You have floating variables all over the place and hard coded numbers that are very specific to each case. You have unnecessary and excessive returns.
My suggestion is to work on solving your own question "Return true if all 2's are next to another 2" - instead of trying to code for each specific case. You aren't REALLY solving a problem if you are hard coding to work on a specific subset of that problem.
Just my critique; keep working at it.
Consider refactoring your for loop with this as a starting point, see if you can figure out the logic (semi pseudo code):
for(int i = 1; i < nums.length-1; i++) { // Why do I start i at 1?
if(nums[i]==2) {
if(nums[i-1] == 2 || nums[i+1] == 2) // What does this if check?
do something; // What to do here? Look up the 'continue' keyword.
else
return false;
}
}
return true;
You will find this for loop is JUST a starting point. There will be more needed to add, but hopefully a good jumping point for you.
Best of luck!
public boolean twoTwo(int[] nums)
{
if (nums.length == 1 && nums[0] == 2)
return false;
for (int i = 0; i < nums.length - 1; i++)
if (nums[i] == 2)
if (nums[i + 1] != 2 && (i > 0 && nums[i - 1] != 2))
return false;
return true;
}
Basically this goes through each number in the list, and if it finds a 2, it checks it against the previous and next numbers. That's all it does.
First time posting on here! So ive searched and searched and cant find an answer. I dont really need a table, just to have that kind of output such as
0 and 0 = 0,
0 and 1 = 1,
and so on...
I need to read from a file that will extract the numbers and they are 0 0..0 1..1 0..1 1
I need to then make the AND, OR, NAND, and NOR "table" for them.
I created an arrayList for them, so i can access them easier. the method i was going to do doesnt work and will take very long lines of code and pretty much be duplicated stuff. Im trying to think of a way to use a loop, but have mental block. can anyone help me please?
heres what im talking about the code i have
int rec3a = Integer.parseInt(list1.get(2));
int rec3b = Integer.parseInt(list1.get(3));
System.out.println("AND:");
if(rec3a == 0 && rec3b == 0)
{
System.out.println("0");
}
if(rec3a == 0 && rec3b == 1)
{
System.out.println("0");
}
if(rec3a == 1 && rec3b == 0)
{
System.out.println("0");
}
if(rec3a == 1 && rec3b == 1)
{
System.out.println("1");
}
}
this doesnt really work for the OR statement either..its just a giant mess lol..any help would be appreciated
You could use the bitwise operators,
int rec3a = 1;
int rec3b = 0;
// AND
System.out.println(rec3a & rec3b);
// OR
System.out.println(rec3a | rec3b);
// NAND
System.out.println((rec3a & rec3b) == 1 ? 0 : 1);
// NOR
System.out.println((rec3a | rec3b) == 1 ? 0 : 1);
Which (in this example) outputs
0
1
1
0
You could simplify this to:
if (rec3a == 1 && rec3b == 1)
{
System.out.println("1");
}
else
{
System.out.println("0");
}
For the OR case it would be:
if (rec3a == 1 || rec3b == 1)
{
System.out.println("1");
}
else
{
System.out.println("0");
}
With Integers 0 and 1, you can use the built in bit-wise operators:
System.out.println(rec3a & rec3b); //AND
System.out.println(rec3A | rec3b); //OR
I took a programming class, and I'm revisiting old programs that I did not quite get right. This one is a Game Of Life program, and I have a question about code cleanup.
I need to make sure that an array element is in bounds before checking whether its neighbor's boolean value is true or false. I have a statement to check if firstGen[0][0]'s top-left (up one row, left one column) is in bounds. Is there an easier or more elegant way to check if an element is in bounds or to restrict the element checks to the boundaries of a given array without using four && conditionals per if statement?
Note that I have only changed the first if statement thus far, so there may be errors elsewhere. I also excluded the boundary checks for the other neighbors.
public static boolean[][] generation(boolean[][] firstGen)
{
int length = firstGen.length;
boolean[][] newGen = new boolean[length][length];
for (int j = 0; j < firstGen[0].length; j++)
{ for (int i = 1; i < firstGen.length; i++)
{
int count = 0;
if ((i-1 >= 0) && (i-1 < length) && (j-1 >= 0) && (j-1 < length)) //top-left element exists
{ if (newGen[i-1][j-1] == true) count++; } //increment `count` if top-left element is true
if ((newGen[i][j] == false) && (count == 3)) newGen[i][j] = true;
else if ((newGen[i][j] == true) && (count == 1)) newGen[i][j] = false;
else if ((newGen[i][j] == true) && (count > 3)) newGen[i][j] = false;
else break;
}
}
return newGen;
}
If i and j are in bounds, then you know for sure that i - 1 < length and j - 1 < length are both true.
Also:
i - 1 >= 0 can be written i > 0
if (condition == true) can be rewritten if (cond)
So you could replace:
if ((i-1 >= 0) && (i-1 < length) && (j-1 >= 0) && (j-1 < length)) //top-left element exists
{ if (newGen[i-1][j-1] == true) count++; } //increment `count` if top-left element is true
by:
//increment `count` if top-left element is true
if (i > 0 && j > 0 && newGen[i-1][j-1]) count++;
That's the best way I can think of to check if its out of bounds, but an alternative method in general, and one that I think gives programs like the Game of Life more exciting outcomes, is adding periodic boundaries. Basically this means that if you walk off one edge, you end up on the other side (like in pac-man). It sounds complicated, but really all it takes is the % function, which returns the remainder of division between the two numbers given.
So:
27 % 5 = 2;
So for adding periodic boundries you would update x and y positions like this:
x = (x + xStep + horizontalSize) % horizontalSize;
y = (y + yStep + verticalSize) % verticalSize;
Where xStep and yStep are +1 or -1 depending on what direction you want to go. (this works nicely with a for loop) The addition of the size is to make sure you go below zero when you get close to borders.
Then you never have to worry about messy border conditions, everything simply overlaps. No need to check each and every border. I hope this makes sense. Please ask for clarification if not. I've used this more for random walker programs but the idea is the same.
I'm working on a recursive Ackermann function in Java. I am getting an error at may recursive line, 23.
return Ack(m - 1, Ack(m, n - 1));
Thanks so much if anyone could point out what's wrong.
-Kyle
/*enter code here
Ackerman's function, A(m, n) is defined:
A(0 , n) = n + 1 for n >= 0
A(m , 0) = A(m – 1 , 1) for m > 0
A(m , n) = A(m – 1 , A(m , n - 1)) for n >= 0
*/
public class AckFun {
public static int Ack(int m, int n) {
if (m == 0) {
return 2 * n;
} else if (m >= 1) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 2;
} else {
return Ack(m - 1, Ack(m, n - 1));
}
}
return n; // Not sure what to return here, Eclipse suggested this.
}
public static void main(String args[]) {
System.out.println(Ack(3, 4));
}
}
You need to make your stack larger:
http://thilinamb.wordpress.com/2008/12/22/how-to-increase-the-java-stack-size/
With larger stack it runs without stackoverflow, but gives 0.
EDIT: Your code is wrong, that is why it gives the error. Try to rewrite the code exactly as the definition says:
//I assume that you check that n and m are non-negative before you run this
if (m == 0) {
return n + 1;
} else if (n == 0) {
return Ack(m - 1, 1);
} else {
return Ack(m - 1, Ack(m, n - 1));
}
PS. Don't blame me for posting source code for homework problems. I believe that the best way to learn programming is by reading and understanding someone else's code.
You've exceeded the maximum recursion depth. That's one of the features of the Ackermann function. :)
If you call it with smaller numbers, like Ack(3,3), then it doesn't overflow the stack.
It's possible to increase Java's recursion depth limit, but that's not necessarily a good solution. This may be an exercise in transforming the program so that it doesn't use Java's built-in call stack, but keeps track of each call in a data structure (perhaps a Stack). You can also use memoization, where you record the result of the function call so you don't have to compute the same result over and over.
With a return in front, you don't need 'else'.
if (m == 0) return n + 1;
if (n == 0) return ack (m - 1, 1);
return ack (m - 1, ack (m, n - 1));