Скачиваний:
7
Добавлен:
01.05.2014
Размер:
17.87 Кб
Скачать
unit BTImpl;

interface
uses BTDefs, BTNode;

Function SearchTree(Node: TBTNode; txt: String): Boolean;
procedure DisplayTree(Root: TBTNode);
procedure DeleteItem(var Root: TBTNode; txt: string);
procedure InsertItem(var Root: TBTNode; txt: String);
implementation

procedure DeleteItemFromNode(var node: TBTNode; txt: string; var too_small: boolean); forward;
procedure SwapNode(var swap_node: TBTNode; swap_spot: Integer; var target_node: TBTNode; var too_small: Boolean); forward;
procedure TooSmall(var parent: TBTNode; var node: TBTNode; spot: Integer; var too_small: Boolean); forward;
procedure InsertItemInNode(node: TBTNode; new_key: String; var up_node: TBTNode; var up_key: String; var had_split: boolean); forward;
procedure SplitNode(var node: TBTNode; spot: Integer; var up_key: String; var up_node: TBTNode); forward;

procedure DeleteItem(var Root: TBTNode; txt: string);
var
too_small: boolean;
begin
too_small := False;

// Delete the item.
DeleteItemFromNode(Root, txt, too_small);

// If the root has shrunk, see if we need to
// remove a level from the tree.
If (Root.NumKeys < 1) Then
Root := Root.Child[0];
end;

// ************************************************
// Recursively remove the item from somewhere down
// this node//s branches.
// ************************************************
procedure DeleteItemFromNode(var node: TBTNode; txt: string; var too_small: boolean);
var
match: boolean;
branch: integer;
q: TBTNode;
i: integer;
begin
branch := 0;

// If we did not find the item, say so.
If (node = nil) Then Begin
too_small := False;
Exit;
End;

// Look for the item or find the branch down which
// it lies.
match := False;
For branch := 1 To node.NumKeys Do Begin
If txt = node.Key[branch] Then Begin
match := True;
Break;
End;
If txt < node.Key[branch] Then Break;
End;

// q is the branch down which the target lies.
q := node.Child[branch - 1];

If match Then Begin
// We found the item. Remove it.
If q = nil Then Begin
// This is a leaf node. Remove the
// target.
node.NumKeys := node.NumKeys - 1;
too_small := (node.NumKeys < ORDER);
For i := branch To node.NumKeys Do
node.Key[i] := node.Key[i + 1];
End Else Begin
// Otherwise swap the item with the
// rightmost item to the left (in
// a leaf).
SwapNode(node, branch, q, too_small);

// If the child node is now too small,
// rearrange it.
If too_small Then
TooSmall(node, q, branch - 1, too_small);
End;
End Else Begin
// We have not found the target yet, continue
// down branch q.
DeleteItemFromNode(q, txt, too_small);

// If the child node is now too small, rearrange it.
If too_small Then
TooSmall(node, q, branch - 1, too_small);
End;
End;

// ************************************************
// Insert an item in a node known to have an empty
// position.
// ************************************************
procedure InsertInNodeWithRoom(var node: TBTNode; spot: Integer; new_key: String; var new_child: TBTNode);
var
i : integer;
begin
// Make room for the new entry.
node.NumKeys := node.NumKeys + 1;
For i := node.NumKeys DownTo spot + 1 Do Begin
node.Key[i] := node.Key[i - 1];
node.Child[i] := node.Child[i - 1];
End;

// Insert the new entry.
node.Key[spot] := new_key;
node.Child[spot] := new_child;
End;

// ************************************************
// Insert an item into the tree.
// ************************************************
procedure InsertItem(var Root: TBTNode; txt: String);
var
up_node: TBTNode;
up_key: string;
had_split: boolean;
old_root: TBTNode;
begin
had_split := false;
up_key := '';
up_node := nil;

// Add the new item.
InsertItemInNode(Root, txt, up_node, up_key, had_split);

// If the root node split, create a new root
// that contains the item that was sent up to
// the parent.
If had_split Then Begin
old_root := Root;
Root := TBTNode.Create;
Root.Key[1] := up_key;
Root.Child[0] := old_root;
Root.Child[1] := up_node;
Root.NumKeys := 1;
End;
End;

// ************************************************
// Recursively insert the item below this node. If
// there is a split, add the item passed up to this
// node. If this node is then full, split it.
// ************************************************
procedure InsertItemInNode(node: TBTNode; new_key: String; var up_node: TBTNode; var up_key: String; var had_split: boolean);
var
branch: Integer;
begin
branch := 0;

If (node = nil) Then Begin
// We're at the bottom of the tree. Pass
// the new value back up for insertion in
// the node above.
up_node := nil;
up_key := new_key;
had_split := True;
exit;
End;

// See which branch we should investigate.
For branch := 0 To node.NumKeys - 1 Do
If node.Key[branch + 1] > new_key Then Break;

// Branch.
InsertItemInNode(node.Child[branch],
new_key, up_node, up_key, had_split);

// If we had a split, deal with it.
If had_split Then Begin
If node.NumKeys < KEYS_PER_NODE Then Begin
// If there's room, just insert it.
InsertInNodeWithRoom(node, branch + 1, up_key, up_node);
had_split := False;
End Else
// The node is full. Split it.
SplitNode
(node, branch + 1, up_key, up_node);
End;
End;

// ************************************************
// Split the node plus the up_key item into two
// nodes. Variable spot indicates where in the node
// the up_key item should be placed.
//
// Return the new node through parameter
// return_node. Return the key to be passed back up
// through parameter up_key.
// ************************************************
procedure SplitNode(var node: TBTNode; spot: Integer; var up_key: String; var up_node: TBTNode);
var
i: Integer;
return_node: TBTNode;
return_key: String;
right_child_0: TBTNode;
begin
return_node := TBTNode.Create;
If spot <= ORDER + 1 Then Begin
// The new item should be in the left node
// or should be passed up.
If spot = ORDER + 1 Then Begin
return_key := up_key;
right_child_0 := up_node;
End Else Begin
// Save the ORDER-th entry.
return_key := node.Key[ORDER];
right_child_0 := node.Child[ORDER];

// Insert the new item into the left node.
For i := ORDER DownTo spot + 1 Do Begin
node.Key[i] := node.Key[i - 1];
node.Child[i] := node.Child[i - 1];
End;
node.Key[spot] := up_key;
node.Child[spot] := up_node;
End;
// Move items into the right node.
For i := 1 To ORDER Do Begin
return_node.Key[i] :=
node.Key[i + ORDER];
return_node.Child[i] :=
node.Child[i + ORDER];
End;
End Else Begin
// The new item should be in the right node.
spot := spot - ORDER - 1;

return_key := node.Key[ORDER + 1];
right_child_0 := node.Child[ORDER + 1];

// Move the first set of items into the right node.
For i := 1 To spot - 1 Do Begin
return_node.Key[i] :=
node.Key[i + ORDER + 1];
return_node.Child[i] :=
node.Child[i + ORDER + 1];
End;

// Put the up_key/up_node in the right node.
return_node.Key[spot] := up_key;
return_node.Child[spot] := up_node;

// Put the other items in the right node.
For i := spot + 1 To ORDER Do Begin
return_node.Key[i] :=
node.Key[i + ORDER];
return_node.Child[i] :=
node.Child[i + ORDER];
End;
End;

node.NumKeys := ORDER;
return_node.NumKeys := ORDER;

return_node.Child[0] := right_child_0;

up_node := return_node;
up_key := return_key;
End;

// ************************************************
// We want to remove the item in node swap_node at
// position swap_position.
//
// Recursively descend the rightmost branches of
// the tree until we come to a leaf. The node we
// are examining in the recursion is target_node.
//
// Then replace the swap item with the rightmost
// item in target_node. This will make the
// target_node smaller, possibly requiring that we
// merge it.
//
// Finally, as the recursion is unwinding, check
// nodes that are shrunk to make sure they are not
// too small.
// ************************************************
procedure SwapNode(var swap_node: TBTNode; swap_spot: Integer; var target_node: TBTNode; var too_small: Boolean);
var
q: TBTNode;
num: Integer;
begin
num := target_node.NumKeys;
q := target_node.Child[num]; // Rightmost child.
If q = nil Then Begin
// We have found a leaf. Make the swap.
swap_node.Key[swap_spot] :=
target_node.Key[num];
target_node.NumKeys := num - 1;
too_small := (target_node.NumKeys < ORDER);
End Else Begin
// We have not yet found a leaf.
SwapNode(swap_node, swap_spot, q, too_small);
If too_small Then
TooSmall (target_node, q,
target_node.NumKeys, too_small);
End;
End;

// ************************************************
// The node "node" is too small. It is located in
// position "spot" in parent "parent".
//
// If node has a right sibling, try to redistribute
// items between node and the right sibling. If the
// right sibling has too few items (if it has
// exactly ORDER items), merge node and the right
// sibling.
//
// If the node does not have a right sibling,
// perform the steps above for the left sibling.
//
// If two nodes are merged, see if the parent is
// now too small.
// ************************************************
procedure TooSmall(var parent: TBTNode; var node: TBTNode; spot: Integer; var too_small: Boolean);
var
num_in_parent: Integer;
num_in_sibling: Integer;
sibling: TBTNode;
num_to_move: Integer;
i: Integer;
begin
num_in_parent := parent.NumKeys;

// If there is a right sibling...
If spot < num_in_parent Then Begin
// Look at the right sibling.
spot := spot + 1; // Now points to the sibling.
sibling := parent.Child[spot];
num_in_sibling := sibling.NumKeys;
num_to_move := (num_in_sibling - ORDER + 1) div 2;

// Put item from parent at end of items in
// the small node. Right now it has
// ORDER - 1 keys.
node.Key[ORDER] := parent.Key[spot];
node.Child[ORDER] := sibling.Child[0];

If num_to_move > 0 Then Begin
// If we have enough items to
// redistribute, do so. Copy items from
// sibling to node.
For i := 1 To num_to_move - 1 Do Begin
node.Key[i + ORDER] :=
sibling.Key[i];
node.Child[i + ORDER] :=
sibling.Child[i];
End;

// Prepare parent
parent.Key[spot] :=
sibling.Key[num_to_move];
parent.Child[spot] := sibling;

// Fill the hole in the sibling
sibling.Child[0] :=
sibling.Child[num_to_move];
num_in_sibling :=
num_in_sibling - num_to_move;
For i := 1 To num_in_sibling Do Begin
sibling.Key[i] :=
sibling.Key[i + num_to_move];
sibling.Child[i] :=
sibling.Child[i + num_to_move];
End;

// Update the key counts.
sibling.NumKeys := num_in_sibling;
node.NumKeys := ORDER - 1 + num_to_move;
too_small := False;
End Else Begin
// End if enough items to redistribute...
// If there are not enough items to
// redistribute, merge the nodes.

// Move entries from sibling to node. It must
// contain ORDER items.
For i := 1 To ORDER Do Begin
node.Key[i + ORDER] :=
sibling.Key[i];
node.Child[i + ORDER] :=
sibling.Child[i];
End;

// Fill in the hole in the parent.
For i := spot To num_in_parent - 1 Do Begin
parent.Key[i] := parent.Key[i + 1];
parent.Child[i] :=
parent.Child[i + 1];
End;

// Update the key counts.
node.NumKeys := KEYS_PER_NODE;
parent.NumKeys := num_in_parent - 1;

// Free the sibling node.
too_small := (parent.NumKeys < ORDER);
End; // End if (can redistribute) ... else (merge)
End Else Begin
// End looking at right sibling
// There is no right sibling. Look at the
// left sibling.
sibling := parent.Child[spot - 1];
num_in_sibling := sibling.NumKeys + 1;
num_to_move := (num_in_sibling - ORDER) div 2;

If num_to_move > 0 Then Begin
// If we have enough items to
// redistribute, do so.

// Make room for the new items in
// the node.
For i := ORDER - 1 DownTo 1 Do Begin
node.Key[i + num_to_move] :=
node.Key[i];
node.Child[i + num_to_move] :=
node.Child[i];
End;

// Move an item from the parent into
// the node.
node.Key[num_to_move] :=
parent.Key[spot];
node.Child[num_to_move] :=
node.Child[0];

// Move items from the sibling into
// the node.
num_in_sibling := num_in_sibling - num_to_move;
For i := num_to_move - 1 DownTo 1 Do Begin
node.Key[i] :=
sibling.Key[i + num_in_sibling];
node.Child[i] :=
sibling.Child[i + num_in_sibling];
End;
node.Child[0] :=
sibling.Child[num_in_sibling];

// Revise the sibling//s entry in the parent.
parent.Key[spot] :=
sibling.Key[num_in_sibling];

// Update the key counts.
sibling.NumKeys := num_in_sibling - 1;
node.NumKeys := ORDER - 1 + num_to_move;
too_small := False;
End Else Begin
// End if enough items to redistribute
// Not enough items to redistribute.
// Merge the nodes.

// Put the node's parent entry in the sibling.
sibling.Key[num_in_sibling] :=
parent.Key[spot];
sibling.Child[num_in_sibling] :=
node.Child[0];

// Move items from the node into the sibling.
For i := 1 To ORDER - 1 Do Begin
sibling.Key[i + num_in_sibling] :=
node.Key[i];
sibling.Child[i + num_in_sibling] :=
node.Child[i];
End;

// Update the key counts.
sibling.NumKeys := KEYS_PER_NODE;
parent.NumKeys := num_in_parent - 1;

too_small := (parent.NumKeys < ORDER);
End; // End if (can redistribute) ... else (merge)
End; // End if (right sibling) ... else (left sibling)
End;

procedure DisplayNode(node: TBTNode; spaces: string);
var
i: integer;
begin
If node = nil Then Exit;

DisplayNode(node.Child[0], spaces + ' ');

For i := 1 To node.NumKeys Do Begin
writeln(spaces + node.Key[i]);
DisplayNode(node.Child[i], spaces + ' ');
End;
End;

// ************************************************
// Display the tree by displaying the root.
// ************************************************
procedure DisplayTree(Root: TBTNode);
begin
DisplayNode(Root, '');
End;

Function SearchTree(Node: TBTNode; txt: String): Boolean;
Var
i : Integer;
Begin
Result := False;

If (Node = nil) Then Begin
// Nothing to search in empty subtree.
Result := False;
Exit;
End;

// Search in current keys, returning when txt is encountered
For i := 1 To Node.NumKeys Do Begin
If Node.Key[i] = txt Then Begin
Result := True;
Exit;
End;
End;

// Search in sub-trees, returning when txt is encountered
For i := 0 To Node.NumKeys Do Begin
If SearchTree(Node.Child[i], txt) Then Begin
Result := True;
Exit;
End;
End;
End;

end.
Соседние файлы в папке Б-деревья заготовка для лабы
  • #
    01.05.2014383 б5BTDefs.dcu
  • #
    01.05.2014137 б6BTDefs.pas
  • #
    01.05.2014229 б5BTDefs.~pas
  • #
    01.05.20147.46 Кб5BTImpl.dcu
  • #
    01.05.201417.87 Кб7BTImpl.pas
  • #
    01.05.201417.87 Кб5BTImpl.~pas
  • #
    01.05.20142.07 Кб5BTNode.dcu
  • #
    01.05.20141.55 Кб6BTNode.pas
  • #
    01.05.20141.55 Кб5BTNode.~pas
  • #
    01.05.2014434 б5BTrees.cfg