i am currently testing a extractMinimum() method of a fibonacci heap implementation i did for a programming exercise.
The way, the method is supposed to work:
1. Delete the minimum node
2. Find a new minimum in the remaining root list elements
3. Add the children of the old minimum node, left of the new
minimum
And, i did already consider the following test cases:
1. empty-Heap
2. one heap with only one root-element and no children
3. one heap with only one root-element and one child
4. one heap with many root elements and one child
5. one heap with many root elements and multiple children
In all of these tests, i also check if the ranks are correctly computed and I also check if rootlist elements are all unmarked. And the references are set correctly.
So, my question is: Did I miss a certain edge case, is there something else i should consider while testing?
Related
In the DECREASE-KEY operation of Fibonacci Heap, whenever a node is cut from its parent and added to the root list, its mark attribute is set to FALSE. However, in the EXTRACT-MIN operation, the children of the min-node are added to the root list but their mark attributes aren't set to FALSE. Why is there such inconsistency?
Moreover, in the linking operation where a node is made the child of another node, the mark attribute of the new child is set to FALSE. The EXTRACT-MIN operation performs this linking operation multiple times. But in the amortized analysis of EXTRACT-MIN operation described in the CLRS book, the authors claim that the number of marked nodes doesn't change in EXTRACT-MIN operation. They use m(H) to denote the number of marked nodes both before and after EXTRACT-MIN operation. I am quoting the exact line from the book:
The potential before extracting the minimum node is t(H)+2m(H), and
the potential afterward is at most (D(n)+1)+2m(H).
Here D(n) is the maximum degree of any node in an n-node Fibonacci Heap, t(H) is the number of trees in the Fibonacci Heap and m(H) is the number of marked nodes in the Fibonacci Heap.
Isn't this calculation wrong?
Let's take a step back - why do we need mark bits in a Fibonacci heap in the first place?
The idea behind a Fibonacci heap is to make the DECREASE-KEY operation as fast as possible. To that end, the basic strategy of DECREASE-KEY is to take the element whose key is being decreased and to cut it from its parent if the heap property is violated. Unfortunately, if we do that, then we lose the exponential connection between the order of a tree and the number of nodes in the tree. That's a problem because the COALESCE step of an EXTRACT-MIN operation links trees based on their orders and assumes that each tree's order says something about how many nodes it contains. With that connection broken, all the nice runtime bounds we want go away.
As a compromise, we introduce mark bits. If a node loses a child, it gets marked to indicate "something was lost here." Once a marked node loses a second child, then it gets cut from its parent. Over time, if you do a huge number of cuts in a single tree, eventually the cuts propagate up to root of the tree, decreasing the tree order. That makes the tree behave differently during a COALESCE step.
With that said, the important detail here is that mark bits are only relevant for non-root nodes. If a node is a root of a tree and it loses a child, this immediately changes its order in a way that COALESCE will notice. Therefore, you can essentially ignore the mark bit of any tree root, since it never comes up. It's probably a wise idea to clear a node's mark bit before moving it up to the root list just so you don't have to clear it later, but that's more of an implementation detail than anything else.
I'm working on Minimax algorithm to build a gomoku game. My problem with Minimax is that with the same evaluation value in child nodes, which is really added to parent node or it is randomly added.
Example tree from Wiki
So as you can see from the tree above, at ply 3 of Min node, there are 2 child nodes have the value of 6. What node is really added to parent node ?
Updated question
Why at the leaves, they are separated to group of 2 or group of 3 which are corresponding to different parent nodes ??
What node is really added to parent node ?
In a word, "neither".
You evaluate the nodes, and take the maximum value. You add values, not nodes, so if the best value is shared by multiple nodes there's no need for you to pick between the nodes - you'd get the same result either way. You just take that best value.
Well, presumably you implemented the algorithm, so you can tell. And since you didn't post your code, we can't.
In general, if your evaluation function can't differentiate between moves, then there's no big problem with choosing either move at random. In fact, there are many games where this is a common event. Symmetry tends to produce situations in which two moves are equally good. And it's clear that in such situations it doesn't matter which move you choose.
As for trees, note that many trees do not order their children, and the MinMax tree is no exception. There's not such a thing as "first child" and "second child".
I was thinking about this and was encountering a lot of bugs while trying to do this. Is it possible?
I believe you are asking whether you can do the following update:
Given the update A B C, you want to add C to all elements from A to B.
The problem is to do the update on the segment tree would normally take O(N * logN) time given that N is the maximum number of elements. However, the key idea about implementing a segment tree is that you would like to suppose range queries and that normally you are not interested in all O(N^2) ranges but rather a much smaller subset of them.
You can enhance the range updates using lazy propagation which would generally mean that you do an update, but you do not update all of the nodes in the segment tree -> you update to some point, but you do not continue futher down the tree since it not needed.
Say that you have updated everything up to a node K which is responsible for the range [10; 30] for example. Later, you do a "get info" query on [20;40]. Obviously, you will have to visit node K, but you are not interested on the whole range, but rather the range [20;30], which is actually its right child.
What you have to do is "push" the update of node K to its left child and then its right child and continue as needed.
In general this would mean that when doing an update, you will do an update only until you find a suitable node(s) for the interval you update, but not go any further. This yields O(logN) time.
Then, when quering you continue propagating the updates down the tree when you reach a node for which you know you have saved some update for later. This also yields O(logN) time.
Some good material: Lazy propagation on segment trees
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)
How to find number of different elements in sorted array with O(1)?
Using in C++, multimap container (STL).
I mean O(1) exactly.
It's not really possible to know in constant time how many unique items are in a collection, even if the collection is sorted, unless you only allow one instance of the item in the collection at any given time. If you do restrict the collection to only having unique items, then the answer is trivial; it's the number of items in the collection since they all have to be distinct.
In the case where you have an ordered collection of non-distinct items, you can find the number of distinct items by iterating through the collection and finding the state changes (when the current value isn't the same as the previous one). The number of distinct items is one more than the number of state changes (or the number of state changes if you start with the "empty" state and count the first item as a change from that).
You can also augment your data structure and add/delete algorithms to track the number of distinct items in the collection so that you can "find" the this number in constant time by simply querying a value that is updated during add/delete. This shouldn't affect the efficiency of either since you only need to determine, on add, whether the new item is the first of it's type by checking if the prev/next item has the same key and, on delete, whether the removed item is the last item of its type, by the same check.
Let's consider a simple illustration.
Let's say you have a magic bag containing several different colored blocks numbered from 1 to N. The bag is magic because whenever you reach into the bag you can either determine how many blocks are in the bag (the value of N) OR look at a block with the guarantee that each time you reach into the block you get the next block in color order, all the reds, all the greens, etc. until no more are left OR you can examine any single block by its number. What you want is to find out how many different colors of blocks are in the bag by reaching into the bag some fixed number of times.
Now, getting the number of total blocks in the bag takes one reach but does you no good because you want to know the number of different colors. Getting any fixed number of randomly selected blocks (less than N) takes a fixed number of reaches but does you no good because they don't tell you anything about the rest of the blocks in the bag. The only thing you can do is pull all of the blocks out one by one in order and find the number of times that the next block is a different color from the last one.
Now if you allow me to change how I put blocks into or take them out of the bag, I could keep track of how many colors of blocks are in the bag as I go, then it again becomes trivial to tell you. I just give you the value that I'm keeping track of. Essentially I'm trading a small amount of space (the place where I keep track of the value) and a bit extra time during add/delete for a larger amount of time trying to find the number of distinct colors later. You just need to decide if the trade-off is worth it.