Пример #1
0
 /// <summary>
 /// Initialises a new instance of the MoreComplexDataStructures.WeightBalancedTreeNode class.
 /// </summary>
 /// <param name="item">The item held by the node.</param>
 /// <param name="parentNode">The parent node of this node.</param>
 public WeightBalancedTreeNode(T item, WeightBalancedTreeNode <T> parentNode)
     : base(item)
 {
     this.parentNode  = parentNode;
     leftChildNode    = null;
     rightChildNode   = null;
     leftSubtreeSize  = 0;
     rightSubtreeSize = 0;
 }
Пример #2
0
        /// <summary>
        /// Checks whether an item with the specified priority exists in the queue.
        /// </summary>
        /// <param name="priority">The priority to check for.</param>
        /// <returns>True if the an item with the specified priority exists in the queue.  False otherwise.</returns>
        public Boolean ContainsPriority(Double priority)
        {
            WeightBalancedTreeNode <PriorityAndItems <T> > priorityNode = tree.TraverseDownToNodeHoldingItem(new PriorityAndItems <T>(priority));

            if (priorityNode == null)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
Пример #3
0
        /// <summary>
        /// Returns the number of items enqueued with the specified priority in the queue.
        /// </summary>
        /// <param name="priority">The priority to return the count for.</param>
        /// <returns>The number of items enqueued with the specified priority in the queue.</returns>
        public Int32 GetItemCountByPriority(Double priority)
        {
            WeightBalancedTreeNode <PriorityAndItems <T> > priorityNode = tree.TraverseDownToNodeHoldingItem(new PriorityAndItems <T>(priority));

            if (priorityNode == null)
            {
                return(0);
            }
            else
            {
                return(GetTotalItemCount(priorityNode.Item));
            }
        }
Пример #4
0
        /// <summary>
        /// Stores an item in the queue with the specified priority.
        /// </summary>
        /// <param name="item">The item to enqueue.</param>
        /// <param name="priority">The priority of the item.</param>
        /// <exception cref="System.ArgumentException">The parameter 'priority' cannot be NaN.</exception>
        /// <exception cref="System.InvalidOperationException">The queue cannot hold more than Int32.MaxValue items.</exception>
        public void Enqueue(T item, Double priority)
        {
            if (Double.IsNaN(priority))
            {
                throw new ArgumentException($"Parameter '{nameof(priority)}' cannot be '{nameof(Double.NaN)}'.", nameof(priority));
            }
            if (count == Int32.MaxValue)
            {
                throw new InvalidOperationException($"The queue cannot hold greater than {Int32.MaxValue} items.");
            }

            // Add the item to the tree
            var newNode = new PriorityAndItems <T>(priority);
            WeightBalancedTreeNode <PriorityAndItems <T> > priorityNode = tree.TraverseDownToNodeHoldingItem(newNode);

            if (priorityNode == null)
            {
                newNode.Items.Add(item, 1);
                tree.Add(newNode);
            }
            else
            {
                if (priorityNode.Item.Items.ContainsKey(item))
                {
                    priorityNode.Item.Items[item]++;
                }
                else
                {
                    priorityNode.Item.Items.Add(item, 1);
                }
            }
            // Add the item to the item to priority map
            if (itemToPriorityMap.ContainsKey(item))
            {
                if (itemToPriorityMap[item].Contains(priority) == false)
                {
                    itemToPriorityMap[item].Add(priority);
                }
            }
            else
            {
                itemToPriorityMap.Add(item, new HashSet <Double>()
                {
                    priority
                });
            }
            count++;
        }
 /// <summary>
 /// Traverses upwards from the specified node, performing node rotations to balance the tree.
 /// </summary>
 /// <param name="inputNode">The node at which to start balancing.</param>
 public new void BalanceTreeUpFromNode(WeightBalancedTreeNode <RangeAndSubtreeCounts> inputNode)
 {
     base.BalanceTreeUpFromNode(inputNode);
 }
 /// <summary>
 /// Traverses up the tree starting at the specified node, invoking the predicate function at each node to decide whether to continue traversing.  Returns the node traversal stopped at.
 /// </summary>
 /// <param name="startNode">The node to start traversing at.</param>
 /// <param name="traversePredicateFunc">A function used to decide whether traversal should continue.  Accepts 2 parameters: the node to perform the action on, and a boolean indicating whether the current node was traversed to from the left or right (true if from the left, false if from the right, and null if the current node is the start node).  Returns a boolean indicating whether traversal should continue.</param>
 /// <returns>The node of the tree where traversal stopped.</returns>
 public new WeightBalancedTreeNode <RangeAndSubtreeCounts> TraverseUpToNode(WeightBalancedTreeNode <RangeAndSubtreeCounts> startNode, Func <WeightBalancedTreeNode <RangeAndSubtreeCounts>, Nullable <Boolean>, Boolean> traversePredicateFunc)
 {
     return(base.TraverseUpToNode(startNode, traversePredicateFunc));
 }
 /// <summary>
 /// Traverses up the tree from the specified node to the root, invoking an action at each node.
 /// </summary>
 /// <param name="startNode">The node to start traversing at.</param>
 /// <param name="nodeAction">The action to perform at each node.  Accepts 2 parameters: the node to perform the action on, and a boolean indicating whether the current node was traversed to from the left or right (true if from the left, false if from the right, and null if the current node is the start node).</param>
 public new void TraverseUpFromNode(WeightBalancedTreeNode <RangeAndSubtreeCounts> startNode, Action <WeightBalancedTreeNode <RangeAndSubtreeCounts>, Nullable <Boolean> > nodeAction)
 {
     base.TraverseUpFromNode(startNode, nodeAction);
 }
 /// <summary>
 /// Gets the node in the tree with the next range greater than the range of the specified start node.
 /// </summary>
 /// <param name="startNode">The node to retrieve the next greater of.</param>
 /// <returns>The node with the next range greater, or null if no greater range exists.</returns>
 public new WeightBalancedTreeNode <RangeAndSubtreeCounts> GetNextGreaterThan(WeightBalancedTreeNode <RangeAndSubtreeCounts> startNode)
 {
     return(base.GetNextGreaterThan(startNode));
 }
        /// <summary>
        /// Returns a unique random number from within the range.
        /// </summary>
        /// <returns>The random number.</returns>
        /// <exception cref="System.InvalidOperationException">No further unique numbers remain in the range.</exception>
        public Int64 Generate()
        {
            if (NumbersRemainingCount == 0)
            {
                throw new InvalidOperationException("Cannot generate a random number as no further unique numbers exist in the specified range.");
            }

            WeightBalancedTreeNode <RangeAndSubtreeCounts> currentNode = rangeTree.RootNode;
            Int64 returnNumber = 0;

            while (true)
            {
                // Decide whether to stop at this node, or to move left or right
                Int64 randomRange  = currentNode.Item.LeftSubtreeRangeCount + currentNode.Item.Range.Length + currentNode.Item.RightSubtreeRangeCount;
                Int64 randomNumber = randomGenerator.Next(randomRange);
                if (randomNumber < currentNode.Item.LeftSubtreeRangeCount)
                {
                    // Move to the left child node
                    currentNode.Item.LeftSubtreeRangeCount--;
                    currentNode = currentNode.LeftChildNode;
                }
                else if (randomNumber >= (currentNode.Item.LeftSubtreeRangeCount + currentNode.Item.Range.Length))
                {
                    // Move to the right child node
                    currentNode.Item.RightSubtreeRangeCount--;
                    currentNode = currentNode.RightChildNode;
                }
                else
                {
                    // Stop traversing at the current node
                    returnNumber = (randomNumber - currentNode.Item.LeftSubtreeRangeCount) + currentNode.Item.Range.StartValue;
                    break;
                }
            }
            if (returnNumber == currentNode.Item.Range.StartValue)
            {
                if (currentNode.Item.Range.Length == 1)
                {
                    if (currentNode.LeftChildNode != null && currentNode.RightChildNode != null)
                    {
                        // The current node will be swapped with the next less than or next greater than, so need to update the subtree range counts between the current and swapped nodes
                        WeightBalancedTreeNode <RangeAndSubtreeCounts> swapNode = null;
                        if (currentNode.LeftSubtreeSize > currentNode.RightSubtreeSize)
                        {
                            // The current node will be swapped with the next less than
                            swapNode = rangeTree.GetNextLessThan(currentNode);
                            swapNode.Item.LeftSubtreeRangeCount  = currentNode.Item.LeftSubtreeRangeCount - swapNode.Item.Range.Length;
                            swapNode.Item.RightSubtreeRangeCount = currentNode.Item.RightSubtreeRangeCount;
                        }
                        else
                        {
                            // The current node will be swapped with the next greater than
                            swapNode = rangeTree.GetNextGreaterThan(currentNode);
                            swapNode.Item.LeftSubtreeRangeCount  = currentNode.Item.LeftSubtreeRangeCount;
                            swapNode.Item.RightSubtreeRangeCount = currentNode.Item.RightSubtreeRangeCount - swapNode.Item.Range.Length;
                        }
                        // Update the subtree range counts
                        Func <WeightBalancedTreeNode <RangeAndSubtreeCounts>, Nullable <Boolean>, Boolean> updateSubtreeRangeCountFunc = (node, nodeTraversedToFromLeft) =>
                        {
                            if (node == currentNode)
                            {
                                return(false);
                            }
                            if (nodeTraversedToFromLeft.HasValue)
                            {
                                if (nodeTraversedToFromLeft == true)
                                {
                                    node.Item.LeftSubtreeRangeCount -= swapNode.Item.Range.Length;
                                }
                                else
                                {
                                    node.Item.RightSubtreeRangeCount -= swapNode.Item.Range.Length;
                                }
                            }
                            return(true);
                        };
                        rangeTree.TraverseUpToNode(swapNode, updateSubtreeRangeCountFunc);
                    }

                    rangeTree.Remove(currentNode.Item);
                }
                else
                {
                    // Shorten the range on the left side
                    currentNode.Item.Range.StartValue++;
                    currentNode.Item.Range.Length--;
                }
            }
            else if (returnNumber == (currentNode.Item.Range.StartValue + currentNode.Item.Range.Length - 1))
            {
                // Shorten the range on the right side
                currentNode.Item.Range.Length--;
            }
            else
            {
                // Split the range
                var leftSideRange = new LongIntegerRange(currentNode.Item.Range.StartValue, returnNumber - currentNode.Item.Range.StartValue);
                var newNodeItem   = new RangeAndSubtreeCounts(leftSideRange, currentNode.Item.LeftSubtreeRangeCount, currentNode.Item.RightSubtreeRangeCount);
                var newNode       = new WeightBalancedTreeNode <RangeAndSubtreeCounts>(newNodeItem, null);
                currentNode.Item.Range.Length    -= (returnNumber - currentNode.Item.Range.StartValue + 1);
                currentNode.Item.Range.StartValue = returnNumber + 1;
                WeightBalancedTreeNode <RangeAndSubtreeCounts> upperNode = null;
                if (currentNode.LeftSubtreeSize > currentNode.RightSubtreeSize)
                {
                    // 'Push' the current node down right
                    if (currentNode == rangeTree.RootNode)
                    {
                        rangeTree.RootNode = newNode;
                    }
                    else
                    {
                        if (currentNode.ParentNode.LeftChildNode == currentNode)
                        {
                            currentNode.ParentNode.LeftChildNode = newNode;
                        }
                        else
                        {
                            currentNode.ParentNode.RightChildNode = newNode;
                        }
                        newNode.ParentNode = currentNode.ParentNode;
                    }
                    newNode.LeftChildNode = currentNode.LeftChildNode;
                    currentNode.LeftChildNode.ParentNode = newNode;
                    newNode.RightChildNode                 = currentNode;
                    newNode.LeftSubtreeSize                = currentNode.LeftSubtreeSize;
                    newNode.RightSubtreeSize               = 1 + currentNode.RightSubtreeSize;
                    newNode.Item.LeftSubtreeRangeCount     = currentNode.Item.LeftSubtreeRangeCount;;
                    newNode.Item.RightSubtreeRangeCount    = currentNode.Item.Range.Length + currentNode.Item.RightSubtreeRangeCount;
                    currentNode.ParentNode                 = newNode;
                    currentNode.LeftChildNode              = null;
                    currentNode.LeftSubtreeSize            = 0;
                    currentNode.Item.LeftSubtreeRangeCount = 0;
                    upperNode = newNode;
                }
                else
                {
                    // 'Push' the new node down left
                    newNode.LeftChildNode               = currentNode.LeftChildNode;
                    newNode.RightChildNode              = null;
                    newNode.LeftSubtreeSize             = currentNode.LeftSubtreeSize;
                    newNode.RightSubtreeSize            = 0;
                    newNode.Item.LeftSubtreeRangeCount  = currentNode.Item.LeftSubtreeRangeCount;
                    newNode.Item.RightSubtreeRangeCount = 0;
                    newNode.ParentNode = currentNode;
                    if (newNode.LeftChildNode != null)
                    {
                        newNode.LeftChildNode.ParentNode = newNode;
                    }
                    currentNode.LeftChildNode = newNode;
                    currentNode.LeftSubtreeSize++;
                    currentNode.Item.LeftSubtreeRangeCount += newNode.Item.Range.Length;
                    upperNode = currentNode;
                }

                // Update the subtree sizes
                Action <WeightBalancedTreeNode <RangeAndSubtreeCounts>, Nullable <Boolean> > incrementSubtreeSizeAction = (node, nodeTraversedToFromLeft) =>
                {
                    if (nodeTraversedToFromLeft.HasValue)
                    {
                        if (nodeTraversedToFromLeft.Value == true)
                        {
                            node.LeftSubtreeSize++;
                        }
                        else
                        {
                            node.RightSubtreeSize++;
                        }
                    }
                };
                rangeTree.TraverseUpFromNode(upperNode, incrementSubtreeSizeAction);
                // Balance the tree
                rangeTree.BalanceTreeUpFromNode(upperNode);
            }

            numbersGeneratedCount++;

            return(returnNumber);
        }