mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 08:55:19 +00:00
[NTOS]: Implement an AVL node deletion algorithm (RtlpDeleteAvlTreeNode). Use it in MiRemoveNode, now implemeneted, and RtlDeleteElementGenericTableAvl, also now implemented. It hopefully works.
svn path=/trunk/; revision=48223
This commit is contained in:
parent
bfc2638590
commit
be9e04b5cb
6 changed files with 159 additions and 2 deletions
|
@ -292,4 +292,102 @@ RtlpInsertAvlTreeNode(IN PRTL_AVL_TABLE Table,
|
|||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FORCEINLINE
|
||||
RtlpDeleteAvlTreeNode(IN PRTL_AVL_TABLE Table,
|
||||
IN PRTL_BALANCED_LINKS Node)
|
||||
{
|
||||
PRTL_BALANCED_LINKS DeleteNode, ParentNode;
|
||||
PRTL_BALANCED_LINKS *Node1, *Node2;
|
||||
CHAR Balance;
|
||||
|
||||
/* Take one of the children if possible */
|
||||
if (!(RtlLeftChildAvl(Node)) || !(RtlRightChildAvl(Node))) DeleteNode = Node;
|
||||
|
||||
/* Otherwise, check if one side is longer */
|
||||
if (!(DeleteNode) && (RtlBalance(Node) >= RtlBalancedAvlTree))
|
||||
{
|
||||
/* Pick the successor which will be the longest side in this case */
|
||||
DeleteNode = RtlRightChildAvl(Node);
|
||||
while (RtlLeftChildAvl(DeleteNode)) DeleteNode = RtlLeftChildAvl(DeleteNode);
|
||||
}
|
||||
else if (!DeleteNode)
|
||||
{
|
||||
/* Pick the predecessor which will be the longest side in this case */
|
||||
DeleteNode = RtlLeftChildAvl(Node);
|
||||
while (RtlRightChildAvl(DeleteNode)) DeleteNode = RtlRightChildAvl(DeleteNode);
|
||||
}
|
||||
|
||||
/* Get the parent node */
|
||||
ParentNode = RtlParentAvl(DeleteNode);
|
||||
|
||||
/* Pick which now to use based on whether or not we have a left child */
|
||||
Node1 = RtlLeftChildAvl(DeleteNode) ? &DeleteNode->LeftChild : &DeleteNode->RightChild;
|
||||
|
||||
/* Pick which node to swap based on if we're already a left child or not */
|
||||
Node2 = RtlIsLeftChildAvl(DeleteNode) ? &ParentNode->LeftChild : &ParentNode->RightChild;
|
||||
|
||||
/* Pick the correct balance depending on which side will get heavier */
|
||||
Balance = RtlIsLeftChildAvl(DeleteNode) ? RtlLeftHeavyAvlTree : RtlRightHeavyAvlTree;
|
||||
|
||||
/* Swap the children nodes, making one side heavier */
|
||||
*Node2 = *Node1;
|
||||
|
||||
/* If the node has a child now, update its parent */
|
||||
if (*Node1) RtlSetParent(*Node1, ParentNode);
|
||||
|
||||
/* Assume balanced root for loop optimization */
|
||||
RtlSetBalance(&Table->BalancedRoot, RtlBalancedAvlTree);
|
||||
|
||||
/* Loop up the tree by parents */
|
||||
while (TRUE)
|
||||
{
|
||||
/* Check if the tree's balance increased */
|
||||
if (RtlBalance(ParentNode) == Balance)
|
||||
{
|
||||
/* Now the tree is balanced */
|
||||
RtlSetBalance(ParentNode, RtlBalancedAvlTree);
|
||||
}
|
||||
else if (RtlBalance(ParentNode) == RtlBalancedAvlTree)
|
||||
{
|
||||
/* The tree has now become less balanced, since it was balanced */
|
||||
RtlSetBalance(ParentNode, -Balance);
|
||||
|
||||
/* Deal with the loop optimization to detect loss of a tree level */
|
||||
if (RtlBalance(&Table->BalancedRoot) != RtlBalancedAvlTree) Table->DepthOfTree--;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The tree has become unbalanced, so a rebalance is needed */
|
||||
if (RtlpRebalanceAvlTreeNode(ParentNode)) break;
|
||||
|
||||
/* Get the new parent after the balance */
|
||||
ParentNode = RtlParentAvl(ParentNode);
|
||||
}
|
||||
|
||||
/* Choose which balance factor to use based on which side we're on */
|
||||
Balance = RtlIsRightChild(ParentNode) ?
|
||||
RtlRightHeavyAvlTree : RtlLeftHeavyAvlTree;
|
||||
|
||||
/* Iterate up the tree */
|
||||
ParentNode = RtlParentAvl(ParentNode);
|
||||
}
|
||||
|
||||
/* Check if this isn't the node we ended up deleting directly */
|
||||
if (Node == DeleteNode) return;
|
||||
|
||||
/* Copy the deleted node itself */
|
||||
RtlpCopyAvlNodeData(DeleteNode, Node);
|
||||
|
||||
/* Pick the right node to unlink */
|
||||
Node1 = RtlIsLeftChildAvl(Node) ?
|
||||
&(RtlParentAvl(DeleteNode))->LeftChild : &(RtlParentAvl(DeleteNode))->RightChild;
|
||||
*Node1 = DeleteNode;
|
||||
|
||||
/* Reparent as appropriate */
|
||||
if (RtlLeftChildAvl(DeleteNode)) RtlSetParent(RtlLeftChildAvl(DeleteNode), DeleteNode);
|
||||
if (RtlRightChildAvl(DeleteNode)) RtlSetParent(RtlRightChildAvl(DeleteNode), DeleteNode);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -296,8 +296,30 @@ NTAPI
|
|||
RtlDeleteElementGenericTableAvl(IN PRTL_AVL_TABLE Table,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
PRTL_BALANCED_LINKS Node;
|
||||
TABLE_SEARCH_RESULT SearchResult;
|
||||
|
||||
/* Find the node */
|
||||
SearchResult = RtlpFindAvlTableNodeOrParent(Table, Buffer, &Node);
|
||||
if (SearchResult != TableFoundNode) return FALSE;
|
||||
|
||||
/* If this node was the key, update it */
|
||||
if (Node == Table->RestartKey) Table->RestartKey = RtlRealPredecessorAvl(Node);
|
||||
|
||||
/* Do the delete */
|
||||
Table->DeleteCount++;
|
||||
RtlpDeleteAvlTreeNode(Table, Node);
|
||||
Table->NumberGenericTableElements--;
|
||||
|
||||
/* Reset accounting */
|
||||
Table->WhichOrderedElement = 0;
|
||||
Table->OrderedPointer = NULL;
|
||||
|
||||
/* Free the node's data */
|
||||
Table->FreeRoutine(Table, Node);
|
||||
|
||||
/* It's done */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -24,6 +24,14 @@
|
|||
#define RtlInsertAsLeftChildAvl RtlInsertAsLeftChild
|
||||
#define RtlIsLeftChildAvl RtlIsLeftChild
|
||||
|
||||
VOID
|
||||
FORCEINLINE
|
||||
RtlpCopyAvlNodeData(IN PRTL_BALANCED_LINKS Node1,
|
||||
IN PRTL_BALANCED_LINKS Node2)
|
||||
{
|
||||
*Node1 = *Node2;
|
||||
}
|
||||
|
||||
RTL_GENERIC_COMPARE_RESULTS
|
||||
FORCEINLINE
|
||||
RtlpAvlCompareRoutine(IN PRTL_AVL_TABLE Table,
|
||||
|
|
|
@ -1107,4 +1107,11 @@ MiInsertNode(
|
|||
IN PMM_AVL_TABLE Table
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiRemoveNode(
|
||||
IN PMMADDRESS_NODE Node,
|
||||
IN PMM_AVL_TABLE Table
|
||||
);
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -28,6 +28,16 @@
|
|||
#define PRTL_BALANCED_LINKS PMMADDRESS_NODE
|
||||
#define MI_ASSERT(x) ASSERT(x)
|
||||
|
||||
VOID
|
||||
FORCEINLINE
|
||||
RtlpCopyAvlNodeData(IN PRTL_BALANCED_LINKS Node1,
|
||||
IN PRTL_BALANCED_LINKS Node2)
|
||||
{
|
||||
Node1->u1.Parent = Node2->u1.Parent;
|
||||
Node1->LeftChild = Node2->LeftChild;
|
||||
Node1->RightChild = Node2->RightChild;
|
||||
}
|
||||
|
||||
RTL_GENERIC_COMPARE_RESULTS
|
||||
FORCEINLINE
|
||||
RtlpAvlCompareRoutine(IN PRTL_AVL_TABLE Table,
|
||||
|
|
|
@ -107,6 +107,18 @@ MiInsertNode(IN PMMADDRESS_NODE NewNode,
|
|||
RtlpInsertAvlTreeNode(Table, NewNode, NodeOrParent, Result);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiRemoveNode(IN PMMADDRESS_NODE Node,
|
||||
IN PMM_AVL_TABLE Table)
|
||||
{
|
||||
/* Call the AVL code */
|
||||
RtlpDeleteAvlTreeNode(Table, Node);
|
||||
|
||||
/* Decrease element count */
|
||||
Table->NumberGenericTableElements--;
|
||||
}
|
||||
|
||||
PMMADDRESS_NODE
|
||||
NTAPI
|
||||
MiGetPreviousNode(IN PMMADDRESS_NODE Node)
|
||||
|
|
Loading…
Reference in a new issue