internal ImMapTree(ImMapData <V> data, ImMapTree <V> left, ImMapTree <V> right) { Data = data; Left = left; Right = right; TreeHeight = left.TreeHeight > right.TreeHeight ? left.TreeHeight + 1 : right.TreeHeight + 1; }
// Adds or updates the left or right branch public ImMapTree <V> AddOrUpdateLeftOrRight(int key, V value) { if (key < Data.Key) { var left = Left; if (left is ImMapData <V> leftLeaf) { if (Right != Empty) { return(new ImMapTree <V>(Data, new ImMapBranch <V>(leftLeaf, new ImMapData <V>(key, value)), Right, 3)); } if (key > leftLeaf.Key) { return(new ImMapTree <V>(new ImMapData <V>(key, value), leftLeaf, Data)); } if (key < leftLeaf.Key) { return(new ImMapTree <V>(leftLeaf, new ImMapData <V>(key, value), Data)); } return(new ImMapTree <V>(Data, new ImMapData <V>(key, value), Right, TreeHeight)); } if (left is ImMapBranch <V> leftBranch) { if (key < leftBranch.Data.Key) { var newLeft = leftBranch.IsRightOriented // no need for rotation ? new ImMapTree <V>(leftBranch.Data, new ImMapData <V>(key, value), leftBranch.LeftOrRight) // 5 5 // 3 ? => 2 ? // 2 1 3 // 1 : key <leftBranch.LeftOrRight.Key ?new ImMapTree <V>(leftBranch.LeftOrRight, new ImMapData <V>(key, value), leftBranch.Data) // 5 5 // 3 ? => 2.5 ? // 2 2 3 // 2.5 : key> leftBranch.LeftOrRight.Key ? new ImMapTree <V>(new ImMapData <V>(key, value), leftBranch.LeftOrRight, leftBranch.Data) : (ImMap <V>) new ImMapBranch <V>(leftBranch.Data, new ImMapData <V>(key, value)); return(new ImMapTree <V>(Data, newLeft, Right, TreeHeight)); } if (key > leftBranch.Data.Key) { // 5 5 // 3 ? => 3 ? // 2 ! 2 ! var newLeft = leftBranch.IsLeftOriented ? new ImMapTree <V>(leftBranch.Data, leftBranch.LeftOrRight, new ImMapData <V>(key, value)) // 5 5 // 2 ? => 3 ? // 3 2 4 // 4 : key > leftBranch.LeftOrRight.Key ? new ImMapTree <V>(leftBranch.LeftOrRight, leftBranch.Data, new ImMapData <V>(key, value)) // 5 5 // 2 ? => 2.5 ? // 3 2 3 // 2.5 : key < leftBranch.LeftOrRight.Key ? new ImMapTree <V>(new ImMapData <V>(key, value), leftBranch.Data, leftBranch.LeftOrRight) : (ImMap <V>) new ImMapBranch <V>(leftBranch.Data, new ImMapData <V>(key, value)); return(new ImMapTree <V>(Data, newLeft, Right, TreeHeight)); } return(new ImMapTree <V>(Data, new ImMapBranch <V>(new ImMapData <V>(key, value), leftBranch.LeftOrRight), Right, TreeHeight)); } // when the left is tree the right could not be empty if (left is ImMapTree <V> leftTree) { if (key == leftTree.Data.Key) { return(new ImMapTree <V>(Data, new ImMapTree <V>(new ImMapData <V>(key, value), leftTree.Left, leftTree.Right, leftTree.TreeHeight), Right, TreeHeight)); } var newLeftTree = leftTree.AddOrUpdateLeftOrRight(key, value); if (newLeftTree.TreeHeight == leftTree.TreeHeight) { return(new ImMapTree <V>(Data, newLeftTree, Right, TreeHeight)); } var rightHeight = Right.Height; if (newLeftTree.TreeHeight - 1 > rightHeight) { // 1st fact - `leftLeft` and `leftRight` cannot be Empty otherwise we won't need to re-balance the left tree // 2nd fact - either lefLeft or leftRight or both should be a tree var leftLeftHeight = newLeftTree.Left.Height; var leftRight = newLeftTree.Right; var leftRightHeight = leftRight.Height; if (leftLeftHeight >= leftRightHeight) { var leftRightTree = new ImMapTree <V>(Data, leftRightHeight, leftRight, rightHeight, Right); newLeftTree.Right = leftRightTree; newLeftTree.TreeHeight = leftLeftHeight > leftRightTree.TreeHeight ? leftLeftHeight + 1 : leftRightTree.TreeHeight + 1; return(newLeftTree); } else { // the leftRight should a tree because its height is greater than leftLeft and the latter at least the leaf if (leftRight is ImMapTree <V> leftRightTree) { newLeftTree.Right = leftRightTree.Left; var newLeftRightHeight = newLeftTree.Right.Height; newLeftTree.TreeHeight = leftLeftHeight > newLeftRightHeight ? leftLeftHeight + 1 : newLeftRightHeight + 1; return(new ImMapTree <V>(leftRightTree.Data, newLeftTree, new ImMapTree <V>(Data, leftRightTree.Right, rightHeight, Right))); } // leftLeftHeight should be less than leftRightHeight here, // so if leftRightHeight is 2 for branch, then leftLeftHeight should be 1 to prevent re-balancing var leftRightBranch = (ImMapBranch <V>)leftRight; if (leftRightBranch.IsLeftOriented) { newLeftTree.Right = leftRightBranch.LeftOrRight; newLeftTree.TreeHeight = 2; return(new ImMapTree <V>(leftRightBranch.Data, newLeftTree, new ImMapBranch <V>(Data, (ImMapData <V>)Right), 3)); } // maybe we need to convert this to branch newLeftTree.Right = Empty; newLeftTree.TreeHeight = 2; return(new ImMapTree <V>(leftRightBranch.Data, newLeftTree, new ImMapTree <V>(Data, 1, leftRightBranch.LeftOrRight, rightHeight, Right))); } } return(new ImMapTree <V>(Data, newLeftTree.TreeHeight, newLeftTree, rightHeight, Right)); } return(new ImMapTree <V>(Data, new ImMapData <V>(key, value), Right, 2)); } else { var right = Right; if (right is ImMapData <V> rightLeaf) { if (Left != Empty) { return(new ImMapTree <V>(Data, Left, new ImMapBranch <V>(rightLeaf, new ImMapData <V>(key, value)), 3)); } if (key > rightLeaf.Key) { return(new ImMapTree <V>(rightLeaf, Data, new ImMapData <V>(key, value), 2)); } if (key < rightLeaf.Key) { return(new ImMapTree <V>(new ImMapData <V>(key, value), Data, right, 2)); } return(new ImMapTree <V>(Data, Left, new ImMapData <V>(key, value), TreeHeight)); } if (right is ImMapBranch <V> rightBranch) { if (key > rightBranch.Data.Key) { // 5 5 // ? 7 => ? 7 // 6 ! 6 ! var newLeft = rightBranch.IsLeftOriented ? new ImMapTree <V>(rightBranch.Data, rightBranch.LeftOrRight, new ImMapData <V>(key, value)) // 5 5 // ? 6 => ? 8 // 8 6 ! // ! : key > rightBranch.LeftOrRight.Key ? new ImMapTree <V>(rightBranch.LeftOrRight, rightBranch.Data, new ImMapData <V>(key, value)) // 5 5 // ? 6 => ? 7 // 8 6 8 // 7 : key < rightBranch.LeftOrRight.Key ? new ImMapTree <V>(new ImMapData <V>(key, value), rightBranch.Data, rightBranch.LeftOrRight) : (ImMap <V>) new ImMapBranch <V>(rightBranch.Data, new ImMapData <V>(key, value)); return(new ImMapTree <V>(Data, newLeft, Right, TreeHeight)); } if (key < rightBranch.Data.Key) { // 5 5 // ? 7 => ? 7 // ! 9 6 9 var newLeft = rightBranch.IsRightOriented // no need for rotation ? new ImMapTree <V>(rightBranch.Data, new ImMapData <V>(key, value), rightBranch.LeftOrRight) // 5 5 // ? 8 => ? 7 // 7 ! 8 // ! : key <rightBranch.LeftOrRight.Key ?new ImMapTree <V>(rightBranch.LeftOrRight, new ImMapData <V>(key, value), rightBranch.Data) // 5 5 // ? 9 => ? ! // 7 7 9 // ! : key> rightBranch.LeftOrRight.Key ? new ImMapTree <V>(new ImMapData <V>(key, value), rightBranch.LeftOrRight, rightBranch.Data) : (ImMap <V>) new ImMapBranch <V>(rightBranch.Data, new ImMapData <V>(key, value)); return(new ImMapTree <V>(Data, newLeft, Right, TreeHeight)); } return(new ImMapTree <V>(Data, Left, new ImMapBranch <V>(new ImMapData <V>(key, value), rightBranch.LeftOrRight), TreeHeight)); } if (right is ImMapTree <V> rightTree) { if (key == rightTree.Data.Key) { return(new ImMapTree <V>(Data, Left, new ImMapTree <V>(new ImMapData <V>(key, value), rightTree.Left, rightTree.Right, rightTree.TreeHeight), TreeHeight)); } var newRightTree = rightTree.AddOrUpdateLeftOrRight(key, value); if (newRightTree.TreeHeight == rightTree.TreeHeight) { return(new ImMapTree <V>(Data, Left, newRightTree, TreeHeight)); } // right tree is at least 3+ deep - means its either rightLeft or rightRight is tree var leftHeight = (Left as ImMapTree <V>)?.TreeHeight ?? 1; if (newRightTree.TreeHeight - 1 > leftHeight) { var rightRightHeight = (newRightTree.Right as ImMapTree <V>)?.TreeHeight ?? 1; var rightLeft = newRightTree.Left; var rightLeftHeight = rightLeft.Height; if (rightRightHeight >= rightLeftHeight) { var rightLeftTree = new ImMapTree <V>(Data, leftHeight, Left, rightLeftHeight, rightLeft); newRightTree.Left = rightLeftTree; newRightTree.TreeHeight = rightLeftTree.TreeHeight > rightRightHeight ? rightLeftTree.TreeHeight + 1 : rightRightHeight + 1; return(newRightTree); } else { if (rightLeft is ImMapTree <V> rightLeftTree) { newRightTree.Left = rightLeftTree.Right; var newRightLeftHeight = newRightTree.Left.Height; newRightTree.TreeHeight = newRightLeftHeight > rightRightHeight ? newRightLeftHeight + 1 : rightRightHeight + 1; return(new ImMapTree <V>(rightLeftTree.Data, new ImMapTree <V>(Data, leftHeight, Left, rightLeftTree.Left), newRightTree)); } var rightLeftBranch = (ImMapBranch <V>)rightLeft; if (rightLeftBranch.IsRightOriented) { newRightTree.Right = rightLeftBranch.LeftOrRight; newRightTree.TreeHeight = 2; return(new ImMapTree <V>(rightLeftBranch.Data, new ImMapBranch <V>(Data, (ImMapData <V>)Right), newRightTree, 3)); } // maybe we need to convert this to branch newRightTree.Right = Empty; newRightTree.TreeHeight = 2; return(new ImMapTree <V>(rightLeftBranch.Data, new ImMapTree <V>(Data, leftHeight, Left, 1, rightLeftBranch.LeftOrRight), newRightTree)); } } return(new ImMapTree <V>(Data, leftHeight, Left, newRightTree.TreeHeight, newRightTree)); } return(new ImMapTree <V>(Data, Left, new ImMapData <V>(key, value), 2)); } }