I have an enormous directed graph I need to traverse in search for the shortest path to a specific node from a given starting point. The graph in question does not exist explicitly; the child nodes are determined algorithmically from the parent nodes.
(To give an illustration: imagine a graph of chess positions. Each node is a chess position and its children are all the legal moves from that position.)
So I have a queue for open nodes, and every time I process the next node in the queue I enqueue all of its children. But since the graph can have cycles I also need to maintain a hashset of all visited nodes so I can check if I have visited one before.
This works okay, but since this graph is so large, I run into memory problems. All of the nodes in the queue are also stored in the hashset, which tends to be around 50% of the total number or visited nodes in practice in my case.
Is there some magical way to get rid of this redundancy while keeping the speed of the hashset? (Obviously, I could get rid of the redundancy by NOT hashing and just doing a linear search, but that is out of the question.)
I solved it by writing a class that stores the keys in a list and stores the indices of the keys in a hashtable. The next node "in the queue" is always the the next node in the list until you find what you're looking for or you've traversed the entire graph.
class IndexMap<T>
{
private List<T> values;
private LinkedList<int>[] buckets;
public int Count { get; private set; } = 0;
public IndexMap(int capacity)
{
values = new List<T>(capacity);
buckets = new LinkedList<int>[NextPowerOfTwo(capacity)];
for (int i = 0; i < buckets.Length; ++i)
buckets[i] = new LinkedList<int>();
}
public void Add(T item) //assumes item is not yet in map
{
if (Count == buckets.Length)
ReHash();
int bucketIndex = item.GetHashCode() & (buckets.Length - 1);
buckets[bucketIndex].AddFirst(Count++);
values.Add(item);
}
public bool Contains(T item)
{
int bucketIndex = item.GetHashCode() & (buckets.Length - 1);
foreach(int i in buckets[bucketIndex])
{
if (values[i].Equals(item))
return true;
}
return false;
}
public T this[int index]
{
get => values[index];
}
private void ReHash()
{
LinkedList<int>[] newBuckets = new LinkedList<int>[2 * buckets.Length];
for (int i = 0; i < newBuckets.Length; ++i)
newBuckets[i] = new LinkedList<int>();
for (int i = 0; i < buckets.Length; ++i)
{
foreach (int index in buckets[i])
{
int bucketIndex = values[index].GetHashCode() & (newBuckets.Length - 1);
newBuckets[bucketIndex].AddFirst(index);
}
buckets[i] = null;
}
buckets = newBuckets;
}
private int NextPowerOfTwo(int n)
{
if ((n & n-1) == 0)
return n;
int output = 0;
while (n > output)
{
output <<= 1;
}
return output;
}
}
The old method of maintaining both an array of the open nodes and a hashtable of the visited nodes needed n*(1+a)*size(T) space, where a is the ratio of nodes_in_the_queue over total_nodes_found and size(T) is the size of a node.
This method needs n*(size(T) + size(int)). If your nodes are significantly larger than an int, this can save a lot.
I am trying to find the time complexity of the recursive function below. I've tried to draw the tree, but it is confusing because in the if condition the function is called once, and otherwise twice.
To give some context, the function is called on nodes of a tree. The task is to calculate the max rating of each node. The rule is that if you add some node to the rating you can't add it's children to the node, but if you don't add it than you can which children to add or don't.
Here is the function:
static int solve(Node node, boolean take) {
int result;
if(take) {
result = node.rating;
for(Node child : node.children) {
result += solve(child, false);
}
return result;
}
result = 0;
for(Node child : node.children) {
result += Math.max(solve(child, true), solve(child, false));
}
return result;
}
Hi. I am having trouble writing this method (in the photo) in a recursuve format. The method gets the amount of occurences of a given element in the binary search tree.
To solve this recursively, I was trying to implement it with a private helper method of the same name, like this:
public int count(){
count = 0;
if (root == null)
return count;
return count (root.getInfo());
private int count(T element){
(Basically the same code you see in the photo)
}
but I ended up with overflow errors. Would you mind taking a look and telling me how I can structure this method recursively?
Cheers, and thanks.
A tentative implementation may looks like this.
public int count(T element, T root){
if(element == null) {
return 0;
}
int count = 0;
int compare = element.compareTo(root.getInfo());
if(compare == 0){
count++;
}
count += count(element, root.getLeft());
count += count(element, root.getRight());
return count;
}
count(item, root);
Here is what I've done so far:
struct rep_list {
struct node *head;
struct node *tail;
}
typedef rep_list *list;
int length(const list lst) {
if (lst->head == NULL) {
return 0;
}
else {
lst->head = lst->head->next;
return 1 + length(lst);
}
}
This works, but the head of the list the function accepts as a parameter gets changed. I don't know how to fix that.
I'm not allowed to change the function definition so it should always accept a list variable.
Any ideas?
EDIT: I tried to do what Tyler S suggested in the comments but I encountered another problem. If I create a node* variable at the beginning, it should point to lst->head. But then every recursive call to the function changes the value back to lst->head and I cannot move forward.
You don't need a local node: just don't change the list head. Instead, pass the next pointer as the recursion head.
int length(const list lst) {
if (lst->head == NULL) {
return 0;
}
else {
return 1 + length(lst->head-next);
}
}
I see. Okay; this gets a bit clunky because of the chosen representation. You need a temporary variable to contain the remaining list. This iscludes changing the head.
int length(const list lst) {
if (lst->head == NULL) {
return 0;
}
else {
new_lst = new(list)
new_lst->head = lst->head->next;
var result = 1 + length(new_lst);
free(new_lst)
return result
}
}
At each recursion step, you create a new list object, point it to the 2nd element of the current list, and continue. Does this do the job for you?
Although this solution is clunky and I hate it, its the only way I can see to accomplish what you're asking without modifying the method signature. We create a temporary node * as member data of the class and modify it when we start.
struct rep_list {
struct node *head;
struct node *tail;
}
node *temp = NULL;
bool didSetHead = false;
typedef rep_list *list;
int length(const list lst) {
if ((didSetHead) && (lst->head != temp)) {
temp = lst->head;
didSetHead = false;
}
if (temp == NULL) {
didSetHead = true;
return 0;
}
else {
temp = temp->next;
return 1 + length(temp);
}
}
Please note, I haven't tested this code and you may have to play with a bit, but the idea will work.
As the title says, I have to trim a binary tree based on a given min and max value. Each node stores a value, and a left/right node. I may define private helper methods to solve this problem, but otherwise I may not call any other methods of the class nor create any data structures such as arrays, lists, etc.
An example would look like this:
overallRoot
_____[50]____________________
/ \
__________[38] _______________[90]
/ \ /
_[14] [42] [54]_____
/ \ \
[8] [20] [72]
\ / \
[26] [61] [83]
trim(52, 65);
should return:
overallRoot
[54]
\
[61]
My attempted solution has three methods:
public void trim(int min, int max) {
rootFinder(overallRoot, min, max);
}
First recursive method finds the new root perfectly.
private void rootFinder(IntTreeNode node, int min, int max) {
if (node == null)
return;
if (overallRoot.data < min) {
node = overallRoot = node.right;
rootFinder(node, min, max);
}
else if (overallRoot.data > max) {
node = overallRoot = node.left;
rootFinder(node, min, max);
}
else
cutter(overallRoot, min, max);
}
This second method should eliminate any further nodes not within the min/max, but it doesn't work as I would hope.
private void cutter(IntTreeNode node, int min, int max) {
if (node == null)
return;
if (node.data <= min) {
node.left = null;
}
if (node.data >= max) {
node.right = null;
}
if (node.data < min) {
node = node.right;
}
if (node.data > max) {
node = node.left;
}
cutter(node.left, min, max);
cutter(node.right, min, max);
}
This returns:
overallRoot
[54]_____
\
[72]
/
[61]
Any help is appreciated. Feel free to ask for further explanation as needed.
This assumes that a node x has the following values:
left (pointer to the left child)
right (pointer to the right child)
parent (pointer to parent)
You might want to make a method called CutBranch, which should simply remove a node an all it's subtrees from your tree. Let T be your tree, and let T.root be a pointer to it's root. It could then work like this:
CutBranch(x,T) {
y = T.root;
while (y.left != x && y.right != x) {
if (y < x) y = y.right;
else y = y.left;
}
if (y < x) y.right = Nil;
else y.left = Nil;
}
This assumes that your tree doesn't include nodes with equal values of course, but it takes O(lg n) time. It doesn't do any garbage collection however.
now you can iterate through the nodes, and every time you reach a node smaller than your lower bound, you can call CutBranch on it's left child, and then delete the node itself. If the node is larger than your upper bound, then you can CutBranch it's right child and delete it.
Great question, thumbs up, although I think if you consider a different approach it gets easier. Like, for every node, first "TRIM" the children, and then "TRIM" itself.
The following method assumes the tree is a BST as per the example in your question.
public Node trim(Node root, int min, int max){
if(root==null)
return root;
root.rightChild = trim (root.rightChild, min, max);
root.leftChild = trim (root.leftChild,min,max);
if(root.key>max || root.key<min){
if(root.rightChild!=null)
return root.rightChild;
return root.leftChild;
}
return root;
}
Although, if you want it to work for any Binary Tree, weather BST or not. Just make the following changes to the if statement above.
if(root.key>max || root.key<min){
if(root.rightChild==null)
return root.leftChild;
else if(root.leftChild==null)
return root.rightChild;
else{
//randomly select one of the children to be parent and add the other child to the first free space in its sub tree
//This is based on personal preferences
Node temp = root.leftChild;
while(temp.leftChild!=null || temp.rightChild!=null){
temp = temp.leftChild;
}
if(temp.leftChild==null)
temp.leftChild=root.rightChild;
else
temp.rightChild=root.rightChild;
return root.leftChild;
}
}
The method should be called like
tree.root = trim(tree.root, min, max);
When working with a tree I find it easiest to have recursive methods which take a Node and return a Node, the idea being that I can then call the method to "update" nodes beneath me by calling the method on them.
In this case, for instance, you could have Node minBound(Node) which returns the subtree of this node which is above the lower bound. If the current Node is in the bound then apply recursively to each child and return yourself. If the current Node is not in the bound then return the updated child Node in the correct direction. If the current Node is null then just return null.
An equivalent method must be written for maxBound.
Then you can just do minBound(maxBound(root)) to get the new root for the tree.
(You could combine minBound and maxBound into the one method, but for ease of explanation I decided to split them out.)
EDIT: Since it's been so long, I thought I'd actually put a code sample up to show what I mean.
public void trim(int min, int max) {
overallRoot = minBound(maxBound(overallRoot,max),min);
}
private IntTreeNode minBound(IntTreeNode node, int min) {
if (node == null) // base case of our recursion
return null;
if (node.value < min) // we're too small, but our larger children might be in
return minBound(node.right, min);
// if we make it to here then we're in bounds, so update our left child
// (our right child is bigger than us, so doesn't need to be processed)
node.left = minBound(node.left, min);
return node;
}
private IntTreeNode maxBound(IntTreeNode node, int max) {
if (node == null) // base case of our recursion
return null;
if (node.value > max) // we're too big, but our smaller children might be in
return maxBound(node.left, max);
// if we make it to here then we're in bounds, so update our right child
// (our left child is smaller than us, so doesn't need to be processed)
node.right = maxBound(node.right, max);
return node;
}