public T Dequeue() { if (_tree == null) // return default(T) instead? { throw new InvalidOperationException("The queue is empty."); } var element = _tree.Element; _tree = _tree.DeleteMin(); _dictionary.Remove(element); return(element); }
public void Enqueue(T item) { RandomMeldablePriorityTree <T> node; if (_dictionary.TryGetValue(item, out node)) { _tree = _tree.DecreaseKey(node, item); } else { node = new RandomMeldablePriorityTree <T>(item); _tree = RandomMeldablePriorityTree <T> .Meld(_tree, node); } _dictionary[item] = node; }
/// <summary> /// Modify a node in the heap that has a new score and return the new heap. /// </summary> public RandomMeldablePriorityTree <T> DecreaseKey(RandomMeldablePriorityTree <T> elementToBeChanged, T newElement) { if (elementToBeChanged.Element.CompareTo(newElement) <= 0) { return(this); } elementToBeChanged.Element = newElement; if (elementToBeChanged.Parent != null) { BreakConnectionToParent(elementToBeChanged); return(Meld(this, elementToBeChanged)); } return(this); // we must already be the lowest value item }
private static void BreakConnectionToParent(RandomMeldablePriorityTree <T> node, RandomMeldablePriorityTree <T> replacement = null) { if (node == null) { return; } if (node.Parent == null) { return; } for (int i = 0; i < node.Parent._children.Length; i++) { if (node.Parent._children[i] == node) { node.Parent._children[i] = replacement; break; } } node.Parent = null; }
/// <summary> /// Merge two heaps into one. /// </summary> public static RandomMeldablePriorityTree <T> Meld(RandomMeldablePriorityTree <T> q1, RandomMeldablePriorityTree <T> q2, Func <int, byte> getChildIndex) { // think this through: // we will return either q1 or q2 (and if either is null, return is obvious) if (q1 == null) { BreakConnectionToParent(q2); return(q2); } if (q2 == null) { BreakConnectionToParent(q1); return(q1); } if (q1 == q2) { #if DEBUG throw new InvalidOperationException("Merging with self was not expected."); #else return(q1); #endif } // q1 > q2, swap them so that q1 is the smallest if (q1.Element.CompareTo(q2.Element) > 0) { var tmp = q1; q1 = q2; q2 = tmp; } var ret = q1; BreakConnectionToParent(ret); do { // pick a random child branch var childIdx = getChildIndex.Invoke(q1._children.Length); // at this point q2 is larger than or equal to q1 if (q1._children[childIdx] == null) { q2.Parent = q1; q1._children[childIdx] = q2; break; } // if the random child of q1 is less than or equal to q2 make that q1 the new head if (q1._children[childIdx].Element.CompareTo(q2.Element) <= 0) { q1 = q1._children[childIdx]; continue; } // our random child is larger than our q2 needing to be merged // things just got ugly: do the insert // we are going to disconnect the q1Child and replace it with q2 // we are then going to continue with q2 in place of q1 and the child that needs to be merged as q2 var tmp = q1._children[childIdx]; q1._children[childIdx] = q2; q2.Parent = q1; q1 = q2; // q1 has to be the smaller q2 = tmp; // tmp is larger than q2 } while (true); return(ret); }
/// <summary> /// Merge two heaps into one. /// </summary> public static RandomMeldablePriorityTree <T> Meld(RandomMeldablePriorityTree <T> q1, RandomMeldablePriorityTree <T> q2) { return(Meld(q1, q2, x => ThreadLocalXorShifter.NextRandom(q1._children.Length))); }
/// <summary> /// Return a new heap containing the additional element. /// </summary> public static RandomMeldablePriorityTree <T> Meld(RandomMeldablePriorityTree <T> q1, T element) { return(Meld(q1, new RandomMeldablePriorityTree <T>(element))); }
/// <summary> /// Returns the best path. /// TPosition will be used as a dictionary key. /// </summary> /// <param name="getNeighbors">Given a position, return all the neighbors directly accessible from that position.</param> public static List <TNode> FindMinimalPath <TNode, TPosition>( TNode startingNode, Func <Dictionary <TPosition, RandomMeldablePriorityTree <TNode> >, TNode, bool> isDone, Func <TNode, IEnumerable <TNode> > getNeighbors) where TNode : SearchNodeBase <TPosition> { TNode best; var lookup = new Dictionary <TPosition, RandomMeldablePriorityTree <TNode> >(); var opens = new RandomMeldablePriorityTree <TNode>(startingNode); do { var lowest = opens.Element; // for dual direction, change this ending situation to be a lambda. // spawn two instances of the search method // in their lambda to see if they're done see if their position passed // exists in the lookup table here (and is open) // if that happens they are both done if (isDone.Invoke(lookup, lowest)) { best = lowest; break; } opens = opens.DeleteMin(); #if DEBUG if (opens != null && opens.Parent != null) { throw new InvalidOperationException("Expected opens to always point to the root."); } #endif lookup[lowest.Position] = null; // keep this below the isDone check foreach (var neighbor in getNeighbors.Invoke(lowest)) { RandomMeldablePriorityTree <TNode> existing; if (lookup.TryGetValue(neighbor.Position, out existing)) { if (existing == null) { continue; } opens = opens.DecreaseKey(existing, neighbor); } else { existing = new RandomMeldablePriorityTree <TNode>(neighbor); opens = RandomMeldablePriorityTree <TNode> .Meld(opens, existing); lookup[neighbor.Position] = existing; } } if (opens == null) { best = lowest; break; } } while (true); LastExpansionCount = lookup.Count; var ret = new List <TNode>(); while (best != null) { ret.Add(best); best = best.Parent as TNode; } ret.Reverse(); return(ret); }
public void Clear() { _tree = null; _dictionary.Clear(); }