/// <summary> /// Initialises a new instance of the MoreComplexDataStructures.DoublyLinkedTreeNode class. /// </summary> /// <param name="item">The item held by the node.</param> /// <param name="parentNode">The parent node of this node.</param> public DoublyLinkedTreeNode(T item, DoublyLinkedTreeNode <T> parentNode) : base(item) { this.parentNode = parentNode; leftChildNode = null; rightChildNode = null; }
/// <summary> /// Adds the specified item to the heap. /// </summary> /// <param name="item">The item to add.</param> public override void Insert(T item) { if (rootNode == null) { rootNode = new DoublyLinkedTreeNode <T>(item, null); } else { // Navigate to the parent of the next insert position Int32 nextInsertPositionParentHorizontalPosition = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(nextInsertHorizontalPosition) / 2.0)); DoublyLinkedTreeNode <T> parentNode = TraverseToPosition(nextInsertDepth - 1, nextInsertPositionParentHorizontalPosition); // Create the new node DoublyLinkedTreeNode <T> newNode = new DoublyLinkedTreeNode <T>(item, parentNode); // If nextInsertHorizontalPosition has a remainder after division by 2 insert on the left, otherwise insert on the right if ((Convert.ToDouble(nextInsertHorizontalPosition) % 2) != 0) { parentNode.LeftChildNode = newNode; } else { parentNode.RightChildNode = newNode; } // Traverse up the tree to preserve the correct ordering. Keep traversing and swapping values with the parent until the parent item is greater than the child item. DoublyLinkedTreeNode <T> currentNode = newNode; while (currentNode.ParentNode != null && currentNode.Item.CompareTo(currentNode.ParentNode.Item) >= 1) { // Swap the values T tempItem = currentNode.Item; currentNode.Item = currentNode.ParentNode.Item; currentNode.ParentNode.Item = tempItem; currentNode = currentNode.ParentNode; } } IncrementNextInsertPosition(); count++; }
/// <summary> /// Performs breadth-first search of the tree underlying the heap, invoking the specified action at each node. /// </summary> /// <param name="nodeAction">The action to perform at each node. Accepts a single parameter which is the current node to perform the action on.</param> public void BreadthFirstSearch(Action <DoublyLinkedTreeNode <T> > nodeAction) { Queue <DoublyLinkedTreeNode <T> > traversalQueue = new Queue <DoublyLinkedTreeNode <T> >(); if (rootNode != null) { traversalQueue.Enqueue(rootNode); } while (traversalQueue.Count > 0) { DoublyLinkedTreeNode <T> currentNode = traversalQueue.Dequeue(); nodeAction.Invoke(currentNode); if (currentNode.LeftChildNode != null) { traversalQueue.Enqueue(currentNode.LeftChildNode); } if (currentNode.RightChildNode != null) { traversalQueue.Enqueue(currentNode.RightChildNode); } } }
/// <summary> /// Removes and returns the maxmimum item in the heap. /// </summary> /// <returns>The maxmimum item in the heap.</returns> public T ExtractMax() { T returnItem = default(T); CheckNotEmpty(); if (count == 1) { returnItem = rootNode.Item; rootNode = null; } else { returnItem = rootNode.Item; // Find the position in the tree which was the last inserted to Tuple <Int32, Int32> previousPosition = CalculatePreviousPosition(nextInsertDepth, nextInsertHorizontalPosition); Int32 previoustDepth = previousPosition.Item1; Int32 previoustHorizontalPosition = previousPosition.Item2; // Get the node at this position DoublyLinkedTreeNode <T> lastInsertedNode = TraverseToPosition(previoustDepth, previoustHorizontalPosition); // Set root node's value to that of the last inserted node rootNode.Item = lastInsertedNode.Item; // Remove the last inserted node from the tree if (lastInsertedNode.ParentNode.LeftChildNode == lastInsertedNode) { lastInsertedNode.ParentNode.LeftChildNode = null; } else { lastInsertedNode.ParentNode.RightChildNode = null; } // Traverse down the tree to preserve the proper ordering DoublyLinkedTreeNode <T> currentNode = rootNode; Boolean keepTraversing = true; // Need to keep traversing until either of the following conditions are true... // Both child nodes of currentNode are null // The items of both child nodes of currentNode are less then currentNode's item while (keepTraversing == true) { // If currentNode is not the root, swap its item with its parent if (currentNode.ParentNode != null) { T tempItem = currentNode.ParentNode.Item; currentNode.ParentNode.Item = currentNode.Item; currentNode.Item = tempItem; } if (currentNode.LeftChildNode == null && currentNode.RightChildNode == null) { keepTraversing = false; } else if (currentNode.RightChildNode == null) { // Traverse to the left child if it's item is greater than currentNode's item if (currentNode.Item.CompareTo(currentNode.LeftChildNode.Item) < 0) { currentNode = currentNode.LeftChildNode; } else { keepTraversing = false; } } // TODO: If the tree structure is properly maintained, this else branch will never be used (impossible to have a tree node which has a right child, but no left child) // Consider removing this branch once functionality is solid else if (currentNode.LeftChildNode == null) { // Traverse to the right child if it's item is greater than currentNode's item if (currentNode.Item.CompareTo(currentNode.RightChildNode.Item) < 0) { currentNode = currentNode.RightChildNode; } else { keepTraversing = false; } } else { if (currentNode.Item.CompareTo(currentNode.LeftChildNode.Item) < 0 || currentNode.Item.CompareTo(currentNode.RightChildNode.Item) < 0) { // Traverse to the node with the higher value if (currentNode.LeftChildNode.Item.CompareTo(currentNode.RightChildNode.Item) > 0) { currentNode = currentNode.LeftChildNode; } else { currentNode = currentNode.RightChildNode; } } else { keepTraversing = false; } } } } DecrementNextInsertPosition(); count--; return(returnItem); }