I'm implementing an Alpha-Beta pruning (MiniMax) algorithm for a board game. I have a Board class with GetAvailableMoves(), PlayMove(Move x) and UndoMove() which all modify the game position inside the Board class. To implement Alpha-Beta I need a tree structure to keep track of the alpha and beta values of every position.
Since I'll want to calculate the best move multiple times in a game, I want to reuse the part of the tree that I already calculated and throw away the rest. If I implement the tree as doubly-linked nodes, then I'll have to call delete on every node in all subtrees that I want to delete. This can be very expensive.
How can I implement a tree that allows me to quickly cut and destroy an entire branch, possibly in O(1) time?
You can implement a datapool for your data. To get an allocated node you get it from the pool, and when you delete you put it back in the pool. Then you only allocate new memory when your pool is empty, and you only delete at the end of your runtime.
This will still need to move all the out of data objects back to the pool when you cut a subtree, so not O(1). But no delete calls.
Alternatively, if you have plenty of memory available and you just want a O(1) way to delete your subtrees, you can move the root of your subtree to a ToDeleteLater queue. And at the end of your run or whenever your program has free time, it can clear out this queue by running through trees deleting.
Unless the subtrees are huge, deleting honestly should not take too long, so instead of using pointers that you need to delete. You can implement destructors that take care of the deleting (RAII) So you don't have to write a complicated deleter.
Note: It is usually recommended that you post some code or more details so users can give more specific advice.
Related
I am implementing a Monte Carlo Tree Search algorithm in C++. I create one huge tree at a time in a for loop, a different one at each iteration. My problem is that each tree is vast and if i create 12000 trees, my program crashes because all available memory in the PC is allocated.
The thing is, that the tree that i create in the iteration 5 for example, is useless in the next iterations, so i would like to free the memory it has allocated. I create each node as std::make_shared<Node<T, A, E> where Node is a class that i have created, and the tree as an instance of a class mcts = MCTS(laneFreeState(state), backpropagation, terminationCheck,scoring)
The call to std::make_shared is using new to allocate memory on the heap. So when you finish using the tree, just recursively iterate it, deleting the nodes as you go (deepest first, then work backwards).
The easiest method is removing and inserting the object, but there are probably faster methods. (If I'm overthinking this and I should just do it the simple way, let me know)
Here are some notes about my QuadTree
The objects that are moving are AABBs and may be bigger than the
smallest QuadTree node.
The objects are not removed when creating children QuadTrees. That
means the root QuadTree has a pointer to every object inside the
QuadTree.
The objects are stored as pointers in a vector outside of the QuadTree.
So far, each time an object moves it calls a function called Update() on the root QuadTree. It includes itself and its past bounding box before it moved in the parameters. I'm not sure how to make the function though.
Posting the entire code to my QuadTree here would make my post quite long, so I've created a GitHub repository for easier reading.
Edit: For anyone looking for an answer this seems to update objects by removing and deleting them and is pretty efficient judging by the test he did in the comments.
It'll be really hard to do better than remove and re-insert, especially in your case, since:
Removing seems super cheap (remove the pointer from the corresponding node's vector)
When looking for which node to move the object to, you need to traverse the tree the exact same way as when inserting, after which:
Insertion is pretty cheap
The only thing I would try if performance is really an issue is some sort of insertion from the leaves. Let's say your tree is pretty large and that objects usually move to immediately adjacent nodes, you could request insertion in the parent node, which would pass it to its parent if needed. Something like:
void insert_from_leaf(object* o) {
if (!is_in_this_subtree(o)) {
parent->insert_from_leaf(o);
return;
}
find_child_node_for_object(o)->insert(0);
}
Basically, it might be more efficient to walk the tree from the leaf the object is coming from than always starting from the root since adjacent nodes tend to share a close ancestor.
In the worse case, you'll end up doing twice the work because you'll go back all the way to the root. In the best case, both source and destination share an immediate parent.
How good a gain this would be entirely depends on the layout of your particular tree, its size, and a bunch of other factors so you should measure the performance of your code before and after implementing something like this.
There are few solutions for that:
You can recreate whole tree each update. You can also simple remove and insert object when it moves.
Another solution (in my case it gives me the best performance) is to store only static objects in quad tree. I stored dynamic objcts in list (in my game there is much less dynamic objects than static).
Also you can read about other spatial data structures like grid, it is much simplier to move objects between cells.
I'm prepping for a Google developer interview and have gotten stuck on a question about heaps. I need to implement a heap as a dynamic binary tree (not array) where each node has a pointer to the parent and two children and there is a global pointer to the root node. The book asks "why won't this be enough?"
How can the standard tree implementation be extended to support heap operations add() and deleteMin()? How can these operations be implemented in this data structure?
Can you keep the size of total nodes ? if so, it's easy to know where you should add new element, because that's an almost full tree.
About deleteMin, I think that it will be less effective because you can't access directly to all leaves, as in array (N/2).
You should travel through all paths till you get leaf and then compare them, probably it will cost O(n)
In a graph algorithm, I need to find the node with the smallest value.
In a step of the algorithm the value of this node or its neighbors can be decreased and a few of its neightbors can be removed dependent on their value.
Also, I don't want to search the whole graph for this node each time (although it is not so big (<1000 nodes)).
Therefore I looked at the STL library and found the heap structure which almost does what I want. I can insert and delete nodes very fast, but is there a method to update the heap fast when I only changed the value of one node without resorting the whole heap? I feel it would be a huge bottleneck in the program.
First the conceptual part:
If you use the heap insertion method with the element that decreased it's value as the starting point for insertion instead of starting at the back of the collection everything just works.
I haven't done that in C++ yet, but std::push_heap looks fine for that purpose.
Is there an algorithm that allows to delete multiple nodes in RB or the only algorithm to delete nodes from RB is to do it in a way:
1. Delete one and
2. if necessary fix tree
If more than half the nodes are being deleted, you can throw away the existing tree and build a new one in less time, since insertion and deletion have the same cost.
If there is no constraint that says the tree must remain balanced while you are doing a multiple node deletion, it seems reasonable to me that you could fix the tree after doing multiple deletes.
The purpose of balancing the tree after each deletion is to make sure the delete operation is consistent in its computational cost. If you do not require deletes to be consistent in this fashion, you could write your delete algorithm differently. The fixup operation will be a more lengthy computation than after just one delete, though. It will also likely be a more complicated one, too.
You might be interested in a data structure called TeardownTree. It supports delete_range operation that works in O(k + log n) time, where n is the initial number of items in the tree and k is the number of items deleted (and returned to the caller). Full disclosure: I am the author.
I have to emphasize that the data structure does not support the insert operation, but is optimized for clone and delete_range. I have written up an informal description of the algorithm. With all the optimizations the code is now significantly different from that document, but it should be enough to grasp the idea.
The way I solved this problem was to create a linked list of nodes to be deleted and to use the standard deletion method on them in succession. I would be interested to know if there is a better algorithm for mass deletion.
I would suggest using a Treap instead of a Red-Black tree, since balancing the tree in various scenarios seems easier with a Treap v/s a Red-Black tree. I'm have the same problem as you, but with Treaps. https://cstheory.stackexchange.com/questions/20495/algorithm-to-bulk-delete-nodes-from-a-treap
Am unsure if the expected height bounds remain valid post bulk-deletion (algorithm mentioned in the question).