mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 05:35:40 +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 */
|
/* EOF */
|
||||||
|
|
|
@ -296,8 +296,30 @@ NTAPI
|
||||||
RtlDeleteElementGenericTableAvl(IN PRTL_AVL_TABLE Table,
|
RtlDeleteElementGenericTableAvl(IN PRTL_AVL_TABLE Table,
|
||||||
IN PVOID Buffer)
|
IN PVOID Buffer)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
PRTL_BALANCED_LINKS Node;
|
||||||
return FALSE;
|
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 */
|
/* EOF */
|
||||||
|
|
|
@ -24,6 +24,14 @@
|
||||||
#define RtlInsertAsLeftChildAvl RtlInsertAsLeftChild
|
#define RtlInsertAsLeftChildAvl RtlInsertAsLeftChild
|
||||||
#define RtlIsLeftChildAvl RtlIsLeftChild
|
#define RtlIsLeftChildAvl RtlIsLeftChild
|
||||||
|
|
||||||
|
VOID
|
||||||
|
FORCEINLINE
|
||||||
|
RtlpCopyAvlNodeData(IN PRTL_BALANCED_LINKS Node1,
|
||||||
|
IN PRTL_BALANCED_LINKS Node2)
|
||||||
|
{
|
||||||
|
*Node1 = *Node2;
|
||||||
|
}
|
||||||
|
|
||||||
RTL_GENERIC_COMPARE_RESULTS
|
RTL_GENERIC_COMPARE_RESULTS
|
||||||
FORCEINLINE
|
FORCEINLINE
|
||||||
RtlpAvlCompareRoutine(IN PRTL_AVL_TABLE Table,
|
RtlpAvlCompareRoutine(IN PRTL_AVL_TABLE Table,
|
||||||
|
|
|
@ -1107,4 +1107,11 @@ MiInsertNode(
|
||||||
IN PMM_AVL_TABLE Table
|
IN PMM_AVL_TABLE Table
|
||||||
);
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
MiRemoveNode(
|
||||||
|
IN PMMADDRESS_NODE Node,
|
||||||
|
IN PMM_AVL_TABLE Table
|
||||||
|
);
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -28,6 +28,16 @@
|
||||||
#define PRTL_BALANCED_LINKS PMMADDRESS_NODE
|
#define PRTL_BALANCED_LINKS PMMADDRESS_NODE
|
||||||
#define MI_ASSERT(x) ASSERT(x)
|
#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
|
RTL_GENERIC_COMPARE_RESULTS
|
||||||
FORCEINLINE
|
FORCEINLINE
|
||||||
RtlpAvlCompareRoutine(IN PRTL_AVL_TABLE Table,
|
RtlpAvlCompareRoutine(IN PRTL_AVL_TABLE Table,
|
||||||
|
|
|
@ -107,6 +107,18 @@ MiInsertNode(IN PMMADDRESS_NODE NewNode,
|
||||||
RtlpInsertAvlTreeNode(Table, NewNode, NodeOrParent, Result);
|
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
|
PMMADDRESS_NODE
|
||||||
NTAPI
|
NTAPI
|
||||||
MiGetPreviousNode(IN PMMADDRESS_NODE Node)
|
MiGetPreviousNode(IN PMMADDRESS_NODE Node)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue