Exemplo n.º 1
0
 /// <summary>
 /// Adds the tree specified by its head 'child' as a child of this node.
 /// </summary>
 /// <param name="child">The child.</param>
 public void AddChild(FibonacciHeapNode <TElement> child)
 {
     this.Children.AppendTail(child);
     // make this node its parent.
     child.CutFromParent();
     child.Parent = this;
 }
Exemplo n.º 2
0
        /// <summary>
        /// Checks if the element passed in violates the heap. If so, true is returned, otherwise false.
        /// </summary>
        /// <param name="elementNode">The element node.</param>
        /// <returns>true if the element violates the heap (not at the right spot in the trees), false otherwise</returns>
        private bool CheckIfElementViolatesHeap(FibonacciHeapNode <TElement> elementNode)
        {
            bool toReturn = false;

            if (elementNode.Parent != null)
            {
                // check if the parent of this elementNode is still correctly the parent.
                toReturn |= !this.ElementCompareFunc(elementNode.Parent.Contents, elementNode.Contents);
            }
            if (toReturn)
            {
                // already violates heap
                return(true);
            }
            foreach (FibonacciHeapNode <TElement> child in elementNode.Children)
            {
                toReturn |= !this.ElementCompareFunc(elementNode.Contents, child.Contents);
                if (toReturn)
                {
                    // already violates heap
                    break;
                }
            }
            return(toReturn);
        }
Exemplo n.º 3
0
 /// <summary>
 /// Removes the element-node relation from the element node mappings
 /// </summary>
 /// <param name="nodeToRemove">The node to remove.</param>
 private void RemoveElementNodeMapping(FibonacciHeapNode <TElement> nodeToRemove)
 {
     foreach (Dictionary <TElement, FibonacciHeapNode <TElement> > mappings in _elementToHeapNodeMappings)
     {
         if (mappings.Remove(nodeToRemove.Contents))
         {
             // done, the element was located in this mappings set.
             break;
         }
     }
 }
Exemplo n.º 4
0
        /// <summary>
        /// Cuts the child passed in from this node. If this node isn't a root, it will be marked after this operation.
        /// </summary>
        /// <param name="child">The child.</param>
        public void CutChild(FibonacciHeapNode <TElement> child)
        {
            bool removeSucceeded = this.Children.Remove(child);

            if (!removeSucceeded)
            {
                throw new ArgumentException("The passed in child isn't a child of the node it has to be cut from.", "child");
            }
            child.Parent = null;
            if (this.Parent != null)
            {
                // mark ourselves. This is an essential part of the algorithm: if a child is cut from a node, the node has to be marked.
                this.IsMarked = true;
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Inserts the specified element into the heap at the right spot.
        /// </summary>
        /// <param name="element">The element to insert.</param>
        /// <remarks>It's not possible to add an element twice as this leads to problems with removal and lookup routines for elements: which node to process?</remarks>
        public override void Insert(TElement element)
        {
            ArgumentVerifier.CantBeNull(element, "element");
            ArgumentVerifier.ShouldBeTrue(e => !this.Contains(e), element, "element to insert already exists in this heap.");

            FibonacciHeapNode <TElement> newNode = new FibonacciHeapNode <TElement>(element);

            // new element is the root of a new tree. We'll add it as the first node.
            newNode.BecomeTreeRoot();
            _trees.InsertHead(newNode);
            UpdateRootIfRequired(newNode);

            AddElementNodeMapping(newNode);
            _count++;
        }
Exemplo n.º 6
0
 /// <summary>
 /// Updates the root of this heap if required.
 /// </summary>
 /// <param name="node">The node to check if it should become the new root.</param>
 private void UpdateRootIfRequired(FibonacciHeapNode <TElement> node)
 {
     if (_heapRoot == null)
     {
         // Make new node the heap root, as it's the only node in the heap
         _heapRoot = node;
     }
     else
     {
         if (!this.ElementCompareFunc(_heapRoot.Contents, node.Contents))
         {
             // newNode should be the parent of the heaproot, which means the newNode is the new root
             _heapRoot = node;
         }
     }
 }
Exemplo n.º 7
0
        /// <summary>
        /// Finds the node of the element passed in.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>the node instance which contains the element passed in or null if not found</returns>
        private FibonacciHeapNode <TElement> FindNode(TElement element)
        {
            FibonacciHeapNode <TElement> toReturn = null;

            if (element != null)
            {
                foreach (Dictionary <TElement, FibonacciHeapNode <TElement> > mappings in _elementToHeapNodeMappings)
                {
                    if (mappings.TryGetValue(element, out toReturn))
                    {
                        // found it
                        break;
                    }
                }
            }
            return(toReturn);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Extracts and removes the root of the heap.
        /// </summary>
        /// <returns>
        /// the root element deleted, or null/default if the heap is empty
        /// </returns>
        public override TElement ExtractRoot()
        {
            if (this.Count <= 0)
            {
                return(null);
            }

            // as there are elements, root has a value.
            FibonacciHeapNode <TElement> rootElement = _heapRoot;
            TElement toReturn = rootElement.Contents;

            // first remove the root from the heap, this will remove it from its tree its in.
            RemoveInternal(rootElement);

            // Consolidate trees so there's at most 1 tree per tree degree. During this process a new heap root (the min/max) is found.
            ConsolidateTrees();
            return(toReturn);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Adds the element-node relation of the node passed in to the element node mappings.
        /// </summary>
        /// <param name="newNode">The new node.</param>
        /// <remarks>Assumes newNode doesn't exist in heap.</remarks>
        private void AddElementNodeMapping(FibonacciHeapNode <TElement> newNode)
        {
            // add to first mapping dictionary. It can be there are more, every merge operation adds new mappings, however for adding new nodes, we add
            // them to the first, so the find routine doesn't have to traverse all mapping dictionaries.
            Dictionary <TElement, FibonacciHeapNode <TElement> > mappings;

            if (_elementToHeapNodeMappings.Count <= 0)
            {
                mappings = new Dictionary <TElement, FibonacciHeapNode <TElement> >();
                _elementToHeapNodeMappings.Add(mappings);
            }
            else
            {
                mappings = _elementToHeapNodeMappings[0];
            }

            mappings.Add(newNode.Contents, newNode);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Removes the element specified
        /// </summary>
        /// <param name="element">The element to remove.</param>
        public override void Remove(TElement element)
        {
            FibonacciHeapNode <TElement> elementNode = FindNode(element);

            if (elementNode == null)
            {
                // not found
                return;
            }
            if (_heapRoot == elementNode)
            {
                // is heaproot, which means Remove() is the same as ExtractRoot()
                ExtractRoot();
            }
            else
            {
                // normal node which isn't the heap root, use shortcut to internal remove routine so we don't have to collide the trees.
                RemoveInternal(elementNode);
            }
        }
Exemplo n.º 11
0
        /// <summary>
        /// Merges the specified heap into this heap.
        /// </summary>
        /// <param name="toMerge">The heap to merge into this heap.</param>
        /// <remarks>Merge of two fibonacci heaps is considered O(1). This heap implementation keeps some datastructures for quickly finding elements back.
        /// Although these datastructures have an O(1) insert performance characteristic, it can be that the merge performance of this implementation is
        /// actually slightly less efficient than O(1) with large heaps
        /// <para>
        /// This routine merges objects inside toMerge into this object. This means that this object will have references to objects inside toMerge.
        /// It's therefore not recommended to alter toMerge after this operation.
        /// </para>
        /// </remarks>
        public void Merge(FibonacciHeap <TElement> toMerge)
        {
            if ((toMerge == null) || (toMerge.Count <= 0))
            {
                return;
            }

            FibonacciHeapNode <TElement> rootOfToMerge = toMerge._heapRoot;

            // obtain the data structures of the heap to merge, and merge them together. Do this by simply linking the two linked lists together, as
            // that's all that has to be done besides updating the root. All essential work is postponed till the trees have to be collided together.
            _trees.Concat(toMerge._trees);
            // add their element to node mappings to our list of mappings. We don't merge the dictionaries as that would cause this merge operation to become
            // an O(n) operation. With the addition of the list of mappings, our search routine has to check m mappings, where m is the # of merge operations
            // this heap has been through.
            _elementToHeapNodeMappings.AddRange(toMerge._elementToHeapNodeMappings);

            UpdateRootIfRequired(rootOfToMerge);
            _count += toMerge.Count;
            toMerge.Clear();
        }
Exemplo n.º 12
0
        /// <summary>
        /// Removes the heapnode passed in from the heap.
        /// </summary>
        /// <param name="nodeToRemove">The node to remove.</param>
        /// <remarks>This routine doesn't collide trees, as that's only necessary if the heaproot is removed. </remarks>
        private void RemoveInternal(FibonacciHeapNode <TElement> nodeToRemove)
        {
            if (nodeToRemove == null)
            {
                return;
            }

            // make all children separate roots in the trees list
            List <FibonacciHeapNode <TElement> > children = nodeToRemove.Children.ToList();

            foreach (FibonacciHeapNode <TElement> child in children)
            {
                ConvertToNewTreeInHeap(child);
            }

            if (nodeToRemove.Parent == null)
            {
                // a tree root
                _trees.Remove(nodeToRemove);
            }
            RemoveElementNodeMapping(nodeToRemove);
            _count--;
        }
Exemplo n.º 13
0
 /// <summary>
 /// Converts the passed in node to a new tree in heap.
 /// </summary>
 /// <param name="elementNode">The element node.</param>
 private void ConvertToNewTreeInHeap(FibonacciHeapNode <TElement> elementNode)
 {
     elementNode.BecomeTreeRoot();
     _trees.InsertHead(elementNode);
 }
Exemplo n.º 14
0
 /// <summary>
 /// Clears all elements from the heap
 /// </summary>
 public override void Clear()
 {
     _trees.Clear();
     _heapRoot = null;
     _count    = 0;
 }
Exemplo n.º 15
0
        /// <summary>
        /// Updates the key of the element passed in. Only use this method for elements where the key is a property of the element, not the element itself.
        /// This means that if you have a heap with value typed elements (e.g. integers), updating the key is updating the value of the element itself, and because
        /// a heap might contain elements with the same value, this could lead to undefined results.
        /// </summary>
        /// <typeparam name="TKeyType">The type of the key type.</typeparam>
        /// <param name="element">The element which key has to be updated</param>
        /// <param name="keyUpdateFunc">The key update func, which takes 2 parameters: the element to update and the new key value.</param>
        /// <param name="newValue">The new value for the key.</param>
        /// <remarks>First, the element to update is looked up in the heap. If the new key violates the heap property (e.g. the key is bigger than the
        /// key of the parent in a max-heap) the elements in the heap are restructured in such a way that the heap again obeys the heap property. </remarks>
        public override void UpdateKey <TKeyType>(TElement element, Action <TElement, TKeyType> keyUpdateFunc, TKeyType newValue)
        {
            FibonacciHeapNode <TElement> elementNode = FindNode(element);

            if (elementNode == null)
            {
                return;
            }

            keyUpdateFunc(element, newValue);
            if (CheckIfElementViolatesHeap(elementNode))
            {
                // As this heap can be a maxheap as well, and the action can make the root of the heap be violating the heap, we simply remove the element
                // and re-add it, if the element doesn't have a parent.
                if (elementNode.Parent == null)
                {
                    RemoveInternal(elementNode);
                    // re-add it
                    Insert(elementNode.Contents);
                }
                else
                {
                    // correct the situation: the elementNode isn't at the right spot anymore in the tree.
                    // two situations: parent is marked or unmarked. Based on that we've to perform different actions.
                    // Place the tree with the elementNode as root as a separate tree in the list of trees of this heap and first preserve the
                    // reference to the parent.
                    FibonacciHeapNode <TElement> parent = elementNode.Parent;
                    ConvertToNewTreeInHeap(elementNode);

                    if (elementNode.Parent.IsMarked)
                    {
                        FibonacciHeapNode <TElement> currentAncestor = parent.Parent;
                        while (currentAncestor != null)
                        {
                            if (currentAncestor.IsMarked)
                            {
                                // cut off node, and unmark it.
                                currentAncestor.IsMarked = false;
                                FibonacciHeapNode <TElement> currentAncestorParent = currentAncestor.Parent;
                                ConvertToNewTreeInHeap(currentAncestor);
                                currentAncestor = currentAncestorParent;
                            }
                            else
                            {
                                currentAncestor.IsMarked = true;
                                // done
                                break;
                            }
                        }
                    }
                    else
                    {
                        // we'll mark the (now cut off) parent of this element that a child was cut from it.
                        // marked nodes are nodes where modifications take place, and these are bumped up to the root level of the trees sooner or later
                        // which collides them together in new trees at the first collide operation.
                        parent.IsMarked = true;
                    }

                    UpdateRootIfRequired(elementNode);
                }
            }
        }