PROGRAM 5
-- Filename: prog4.adb Author: Anthony F. Ortiz
-- This program searches for keys in a b-tree.
-- note: I ran ch8p1 with the empmstr.dat (changing it to the relemp.dat
-- data file). When I ran the program, it gave me very big key
-- numbers. They were 5 to 10 digits instead of 4. I checked the
-- 4 digit numbers in the query file and none of them matched. Then,
-- I selected some of the big key numbers that ch8p1 produced and
-- was able to get a match.
-- Also, I made my own sequential data file for the query.
With Text_IO; Use Text_IO;
With Direct_IO;
With Sequential_IO;
With B_Tree;
Procedure main is
Package Employee_B_Tree is New B_Tree (3, Integer, ">");
Package Key_IO is new Sequential_IO (Integer); Use Key_IO;
Package Int_IO is new Integer_IO (Integer); Use Int_IO;
search_key: integer;
address: positive := 2;
address2: integer;
flag: integer;
key_file_type: Key_IO.File_Type;
Begin
Open (key_file_type, IN_FILE, "query1.txt");
Employee_B_Tree.Open_B_Tree ("a:\empbtree.dat");
Loop
flag := 1;
Exit when End_of_File (key_file_type);
Read (key_file_type, search_key);
Put ("key = ");
Put (search_key);
Begin
Employee_B_Tree.search (search_key, address);
Exception
When Employee_B_Tree.key_not_found =>
Text_IO.Put (" not found in file.");
flag := 0;
End;
If flag = 1 then
Put (" address = ");
address2 := integer (address);
Put (address2);
End If;
New_Line;
End Loop;
Employee_B_Tree.Close_B_Tree;
End main;
-- I didn't write b_tree.adb and b_tree.ads.
-- Filename: b_tree.ads
-- This is the declaration of the b_tree class.
WITH Direct_IO;
GENERIC
degree : Positive;
TYPE Key_Type Is Private;
WITH FUNCTION ">" (left_operand, right_operand : Key_Type)
Return Boolean;
PACKAGE B_Tree Is
PROCEDURE Create_B_Tree (external_b_tree_filename : String);
PROCEDURE Open_B_Tree (external_b_tree_filename : String);
PROCEDURE Insert (key : Key_Type; key_position : Positive);
PROCEDURE Delete (key : Key_Type);
PROCEDURE Search (key : Key_Type; key_position : Out Positive);
PROCEDURE Close_B_Tree ;
key_not_inserted : Exception;
key_not_deleted : Exception;
key_not_found : Exception;
END B_Tree;
-- Filename: b_tree.adb:
-- This is the implementation of the b_tree class.
PACKAGE Body B_Tree Is
TYPE A_Tuple Is Record
key : Key_Type;
address : Positive;
subtree : Natural;
End Record;
TYPE Tuple_Array Is Array (Integer Range <>) Of A_Tuple;
TYPE Node_Type Is Record
number_of_tuples : Natural;
first_subtree : Natural;
tuple : Tuple_Array (1..degree - 1);
End Record;
TYPE BigNode_Type Is Record
number_of_tuples : Natural;
first_subtree : Natural;
tuple : Tuple_Array (1..degree);
End Record;
TYPE Operation_Type Is (INSERT_KEY, DELETE_KEY, NIL, SEARCH_KEY);
Package B_Tree_IO Is New Direct_IO (Node_Type);
b_tree_file : B_Tree_IO.File_Type;
hold_tuple : A_Tuple;
key_found : Exception;
next : Positive;
PROCEDURE Create_B_Tree (external_b_tree_filename : String) Is
node : Node_Type;
BEGIN
B_Tree_IO.Create (b_tree_file, B_Tree_IO.INOUT_FILE,
external_b_tree_filename);
node.number_of_tuples := 0;
B_Tree_IO.Write (b_tree_file, node, 1);
next := 1;
END Create_B_Tree;
PROCEDURE Open_B_Tree (external_b_tree_filename : String) Is
BEGIN
B_Tree_IO.Open (b_tree_file,
B_Tree_IO.INOUT_FILE,
external_b_tree_filename);
next := Positive (B_Tree_IO.Size (b_tree_file));
END Open_B_Tree;
PROCEDURE Find_node (hold_tuple : IN OUT A_Tuple;
p : In Natural;
operation : In Out Operation_Type) Is
ith_position : Integer;
node : Node_Type;
PROCEDURE Insert_Tuple (hold_tuple : IN OUT A_Tuple;
ith_position : Positive;
node : In Out Node_Type;
operation : In Out Operation_Type) Is
PROCEDURE Split (hold_tuple : IN OUT A_Tuple;
ith_position : Positive;
node : In Out Node_Type) Is
bignode : BigNode_Type;
index : Integer;
middle : Positive;
newnode : Node_Type;
temp_tuple : A_Tuple;
BEGIN -- Split.
bignode.number_of_tuples := node.number_of_tuples;
bignode.first_subtree := node.first_subtree;
For lcv In 1..ith_position - 1 Loop
bignode.tuple(lcv) := node.tuple(lcv);
End Loop;
bignode.tuple(ith_position) := hold_tuple;
For lcv In ith_position..node.number_of_tuples Loop
bignode.tuple(lcv + 1) := node.tuple(lcv);
End Loop;
bignode.number_of_tuples := bignode.number_of_tuples + 1;
middle := (degree - 1) / 2 + 1; -- Withdraw middle tuple.
hold_tuple := bignode.tuple(middle);
next := next + 1;
hold_tuple.subtree := next;
node.first_subtree := bignode.first_subtree;
For lcv In 1..middle - 1 Loop
temp_tuple := bignode.tuple(lcv);
-- node.tuple(lcv) := bignode.tuple(lcv);
node.tuple(lcv) := temp_tuple;
End Loop;
node.number_of_tuples := middle - 1;
B_Tree_IO.Write (b_tree_file,
node,
B_Tree_IO.Positive_Count (p));
newnode.first_subtree := bignode.tuple(middle).subtree;
index := 0;
For lcv In middle + 1..bignode.number_of_tuples Loop
index := index + 1;
temp_tuple := bignode.tuple(lcv);
-- newnode.tuple(index) := bignode.tuple(lcv);
newnode.tuple(index) := temp_tuple;
End Loop;
newnode.number_of_tuples := index;
B_Tree_IO.Write (b_tree_file,
newnode,
B_Tree_IO.Positive_Count (next));
END Split;
BEGIN -- Insert_Tuple.
-- Insert hold_tuple into position
-- ith_position of node (address p).
If node.number_of_tuples < degree - 1 Then
-- Resulting node is not too big.
operation := NIL;
For lcv In Reverse ith_position..node.number_of_tuples Loop
node.tuple(lcv + 1) := node.tuple(lcv);
End Loop;
node.number_of_tuples := node.number_of_tuples + 1;
node.tuple(ith_position) := hold_tuple;
B_Tree_IO.Write (b_tree_file,
node,
B_Tree_IO.Positive_Count (p));
Else
Split (hold_tuple, ith_position , node);
End If;
END Insert_Tuple;
BEGIN -- Find_Node.
If p = 0 Then
Return;
Else
B_Tree_IO.Read (b_tree_file,
node,
B_Tree_IO.Positive_Count (p));
If hold_tuple.key >
node.tuple(node.number_of_tuples).key Then
ith_position := node.number_of_tuples + 1;
Find_Node (hold_tuple,
node.tuple(node.number_of_tuples).subtree,
operation);
If operation = INSERT_KEY Then
Insert_Tuple (hold_tuple, ith_position, node, operation);
End If;
Else -- Hold_tuple .key <= node.tuple(ith_position).
ith_position := 1;
Loop
If hold_tuple.key > node.tuple(ith_position).key Then
ith_position := ith_position + 1;
ElsIf hold_tuple.key = node.tuple(ith_position).key Then
hold_tuple.address :=
node.tuple(ith_position).address;
Raise key_found;
Else
-- Hold_tuple.key < node.tuple(ith_position).key.
If ith_position = 1 Then
Find_Node (hold_tuple,
node.first_subtree,
operation);
Else
Find_Node (hold_tuple,
node.tuple(ith_position - 1).subtree,
operation);
End If;
If operation = INSERT_KEY Then
Insert_Tuple (hold_tuple,
ith_position,
node,
operation);
End If;
Exit;
End If;
End Loop;
End If;
End If;
END Find_Node;
PROCEDURE Insert (key : Key_Type; key_position : Positive) Is
new_node : Node_Type;
new_tuple : A_Tuple;
root_node : Node_Type;
operation : Operation_Type := INSERT_KEY;
BEGIN -- Insert.
B_Tree_IO.Read (b_tree_file, root_node, 1);
new_tuple := (key, key_position, 0);
Find_Node (new_tuple, root_node.number_of_tuples, operation);
If operation = INSERT_KEY Then
new_node.number_of_tuples := 1;
B_Tree_IO.Read (b_tree_file, root_node, 1);
new_node.first_subtree := root_node.number_of_tuples;
new_node.tuple(1) := (new_tuple.key,
new_tuple.address,
new_tuple.subtree);
next := next + 1;
B_Tree_IO.Write (b_tree_file,
new_node,
B_Tree_IO.Positive_Count (next));
root_node.number_of_tuples := next;
B_Tree_IO.Write (b_tree_file, root_node, 1);
End If;
EXCEPTION
When key_found => Raise key_not_inserted;
END Insert;
PROCEDURE Delete (key : Key_Type) Is
KEY_NOT_FOUND : Exception;
MINIMUM : Positive := degree / 2;
node_undersized : Boolean := FALSE;
operation : Operation_Type := DELETE_KEY;
root_address : Positive;
root_node : Node_Type;
PROCEDURE Delete_Tuple (delete_value : Key_Type;
p : In Natural;
node_undersized : In Out Boolean) Is
-- Search node with address p for key.
child_address : Natural;
ith_position : Natural;
node : Node_Type;
PROCEDURE Under_Flow (parent_address : In Positive;
child_address : In Positive;
tuple_index : In Out Natural;
node_undersized : Out Boolean) Is
child_node : Node_Type;
left : Positive;
left_extras : Integer;
left_node : Node_Type;
parent_node : Node_Type;
right_address : Positive;
right_extras : Integer;
right_node : Node_Type;
PROCEDURE Balance_From_Right Is
BEGIN
For j In 1..right_extras - 1 Loop
child_node.tuple(child_node.number_of_tuples + j)
:= right_node.tuple(j);
End Loop;
child_node.number_of_tuples := MINIMUM - 1 + right_extras;
B_Tree_IO.Write (b_tree_file,
child_node,
B_Tree_IO.Positive_Count (child_address));
parent_node.tuple(tuple_index) :=
right_node.tuple(right_extras);
parent_node.tuple(tuple_index).subtree := right_address;
B_Tree_IO.Write (b_tree_file,
parent_node,
B_Tree_IO.Positive_Count (parent_address));
right_node.first_subtree :=
right_node.tuple(right_extras).subtree;
right_node.number_of_tuples :=
right_node.number_of_tuples - right_extras;
For j In 1..right_node.number_of_tuples Loop
right_node.tuple(j) :=
right_node.tuple(right_extras + j);
End Loop;
B_Tree_IO.Write (b_tree_file,
right_node,
B_Tree_IO.Positive_Count (right_address));
node_undersized := FALSE;
END Balance_From_Right;
PROCEDURE Balance_From_Left Is
BEGIN
For j In Reverse 1..MINIMUM Loop
-- Move tuples over 'left_extras' places to make
-- room for tuples at lower end.
child_node.tuple(j + left_extras) :=
child_node.tuple(j);
End Loop;
child_node.tuple(left_extras) :=
parent_node.tuple(tuple_index);
child_node.tuple(left_extras).subtree :=
child_node.first_subtree;
left_node.number_of_tuples := MINIMUM + 1;
For j In Reverse 1..left_extras - 1 Loop
child_node.tuple(j) :=
left_node.tuple(left_node.number_of_tuples + j);
End Loop;
child_node.first_subtree :=
left_node.tuple(left_node.number_of_tuples).subtree;
child_node.number_of_tuples := MINIMUM - 1 + left_extras;
parent_node.tuple(tuple_index) :=
left_node.tuple(left_node.number_of_tuples);
parent_node.tuple(tuple_index).subtree:= child_address;
left_node.number_of_tuples := left_node.number_of_tuples - 1;
B_Tree_IO.Write (b_tree_file,
parent_node,
B_Tree_IO.Positive_Count (parent_address));
B_Tree_IO.Write (b_tree_file,
left_node,
B_Tree_IO.Positive_Count (left));
B_Tree_IO.Write (b_tree_file,
child_node,
B_Tree_IO.Positive_Count (child_address));
node_undersized := FALSE;
END Balance_From_Left;
PROCEDURE Merge_With_Right Is
BEGIN
For j IN 1..MINIMUM Loop
child_node.tuple(MINIMUM + j) := right_node.tuple(j);
End Loop;
For j In tuple_index..parent_node.number_of_tuples - 1 Loop
parent_node.tuple(j) := parent_node.tuple(j + 1);
End Loop;
child_node.number_of_tuples := degree - 1;
right_node.number_of_tuples := 0;
B_Tree_IO.Write (b_tree_file,
right_node,
B_Tree_IO.Positive_Count (right_address));
parent_node.number_of_tuples :=
parent_node.number_of_tuples - 1;
node_undersized := parent_node.number_of_tuples < MINIMUM;
B_Tree_IO.Write (b_tree_file,
child_node,
B_Tree_IO.Positive_Count (child_address));
B_Tree_IO.Write (b_tree_file,
parent_node,
B_Tree_IO.Positive_Count (parent_address));
END Merge_With_Right;
PROCEDURE Merge_With_Left Is
BEGIN
left_node.number_of_tuples := left_node.number_of_tuples + 1;
left_node.tuple(left_node.number_of_tuples)
:= parent_node.tuple(tuple_index);
left_node.tuple(left_node.number_of_tuples).subtree
:= child_node.first_subtree;
For j In 1..child_node.number_of_tuples Loop
left_node.tuple(left_node.number_of_tuples + j)
:= child_node.tuple(j);
End Loop;
left_node.number_of_tuples := degree - 1;
parent_node.number_of_tuples := parent_node.number_of_tuples - 1;
node_undersized := parent_node.number_of_tuples < MINIMUM;
B_Tree_IO.Write (b_tree_file,
left_node,
B_Tree_IO.Positive_Count (left));
B_Tree_IO.Write (b_tree_file,
parent_node,
B_Tree_IO.Positive_Count (parent_address));
END Merge_With_Left;
PROCEDURE Choose_Left_Sibling Is
BEGIN
If tuple_index = 1 Then
left := parent_node.first_subtree;
Else
left := parent_node.tuple(tuple_index - 1).subtree;
End If;
B_Tree_IO.Read (b_tree_file,
left_node,
B_Tree_IO.Positive_Count (left));
left_extras := (left_node.number_of_tuples - MINIMUM + 1) / 2;
END Choose_Left_Sibling;
BEGIN -- Under_Flow.
B_Tree_IO.Read (b_tree_file,
child_node,
B_Tree_IO.Positive_Count (child_address));
B_Tree_IO.Read (b_tree_file,
parent_node,
B_Tree_IO.Positive_Count (parent_address));
If tuple_index < parent_node.number_of_tuples Then
-- A right sibling exists.
tuple_index := tuple_index + 1;
right_address := parent_node.tuple(tuple_index).subtree;
B_Tree_IO.Read (b_tree_file,
right_node,
B_Tree_IO.Positive_Count (right_address));
right_extras := (right_node.number_of_tuples
- MINIMUM + 1) / 2;
-- Right_extras = number of tuples over the MINIMUM
-- that can be balanced between child_node
-- and right_node.
child_node.number_of_tuples := child_node.number_of_tuples + 1;
child_node.tuple(child_node.number_of_tuples)
:= parent_node.tuple(tuple_index);
child_node.tuple(child_node.number_of_tuples).subtree
:= right_node.first_subtree;
-- Replace predecessor of node to original location.
If right_extras > 0 Then
-- Move right_extras number of tuples from right_node
-- to child_node.
Balance_From_Right;
ElsIf tuple_index /= 0 Then
-- Check to see if left sibling exists and has extras
-- left sibling exists.
Choose_Left_Sibling;
If left_extras > 0 Then
Balance_From_Left;
Else
-- Left sibling has no extras so merge child_node
-- and right_node into child_node.
Merge_With_Right;
End If;
Else
-- Left sibling does not exist so merge child_node
-- and right_node into child_node.
Merge_With_Right;
End If;
Else
-- No right sibling exists; choose left sibling.
Choose_Left_Sibling;
If left_extras > 0 Then
Balance_From_Left;
Else
Merge_With_Left;
End If;
End If;
END Under_Flow;
PROCEDURE Found_Delete_Value Is
PROCEDURE Find_Predecessor (decendant_address : In Positive;
node_undersized : In Out Boolean) Is
decendant_node : Node_Type;
n, q : Natural;
BEGIN -- Find_Predecessor.
B_Tree_IO.Read (b_tree_file,
decendant_node,
B_Tree_IO.Positive_Count
(decendant_address));
n := decendant_node.number_of_tuples;
q := decendant_node.tuple(n).subtree;
If q = 0 Then
decendant_node.tuple(n).subtree :=
node.tuple(ith_position).subtree;
node.tuple(ith_position) := decendant_node.tuple(n);
decendant_node.number_of_tuples
:= decendant_node.number_of_tuples - 1;
node_undersized := decendant_node.number_of_tuples
< MINIMUM;
B_Tree_IO.Write (b_tree_file,
node,
B_Tree_IO.Positive_Count (p));
B_Tree_IO.Write (b_tree_file,
decendant_node,
B_Tree_IO.Positive_Count
(decendant_address));
Else -- Look deeper in the tree for predecessor.
Find_Predecessor (q, node_undersized);
If node_undersized Then
Under_Flow (decendant_address,
q,
decendant_node.number_of_tuples,
node_undersized);
End If;
End If;
End Find_Predecessor;
BEGIN -- Found_Delete_Value.
If ith_position = 1 Then
child_address := node.first_subtree;
Else
child_address := node.tuple(ith_position - 1).subtree;
End If;
If child_address = 0 Then
-- Delete key(ith_position) from leaf node.
node.number_of_tuples := node.number_of_tuples - 1;
node_undersized := node.number_of_tuples < MINIMUM;
For j In ith_position..node.number_of_tuples Loop
node.tuple(j) := node.tuple(j + 1);
End Loop;
B_Tree_IO.Write (b_tree_file,
node,
B_Tree_IO.Positive_Count (p));
Else -- Delete key(ith_position) from nonterminal node;
-- Find predecessor to replace key(ith_position).
Find_Predecessor (child_address, node_undersized);
If node_undersized Then
ith_position := ith_position - 1;
Under_Flow (p,
child_address,
ith_position,
node_undersized);
End If;
End If;
END Found_Delete_Value;
BEGIN -- Delete_Tuple.
If p = 0 Then -- Not found.
Raise key_not_deleted;
Else
B_Tree_IO.Read (b_tree_file,
node,
B_Tree_IO.Positive_Count (p));
If delete_value >
node.tuple(node.number_of_tuples).key Then
ith_position := node.number_of_tuples;
child_address := node.tuple(ith_position).subtree;
Delete_Tuple (delete_value,
child_address,
node_undersized);
If node_undersized Then
Under_Flow (p,
child_address,
ith_position,
node_undersized);
End If;
Else
ith_position := 1;
Loop
If delete_value > node.tuple(ith_position).key Then
ith_position := ith_position + 1;
ElsIf delete_value = node.tuple(ith_position).key Then
Found_Delete_Value;
Exit;
Else
-- Delete_value < node.tuple(ith_position).key Then.
If ith_position > 1 Then
child_address :=
node.tuple(ith_position - 1).subtree;
Else
child_address := node.first_subtree;
End If;
Delete_Tuple (delete_value,
child_address,
node_undersized);
If node_undersized Then
ith_position := ith_position - 1;
Under_Flow (p,
child_address,
ith_position,
node_undersized);
End If;
Exit;
End If;
End Loop;
End If;
End If;
END Delete_Tuple;
BEGIN -- Delete.
If degree / 2 * 2 = degree Then -- Test for even numbered degree.
MINIMUM := MINIMUM - 1;
End If;
B_Tree_IO.Read (b_tree_file, root_node, 1);
root_address := root_node.number_of_tuples;
Delete_Tuple (key, root_address, node_undersized);
If node_undersized
And Then root_node.number_of_tuples = 0 Then
-- Reducing the height of the B_tree
root_node.number_of_tuples := root_node.first_subtree;
B_Tree_IO.Write (b_tree_file, root_node, 1);
End If;
END Delete;
PROCEDURE Search (key : Key_Type; key_position : Out Positive) Is
new_tuple : A_Tuple;
root_node : Node_Type;
operation : Operation_Type := SEARCH_KEY;
BEGIN
B_Tree_IO.Read (b_tree_file, root_node, 1);
new_tuple := (key, 1, 0);
Find_Node (new_tuple, root_node.number_of_tuples, operation);
key_position := 1;
Raise key_not_found;
EXCEPTION
When key_found =>
key_position := new_tuple.address;
END Search;
PROCEDURE Close_B_Tree Is
BEGIN
B_Tree_IO.Close (b_tree_file);
END Close_B_Tree;
END B_Tree;
-- data file: query1.txt
9878
5552
1321
7678
1112
7810
7540
-- data file: empbtree.dat
-- not a text file
-- outfile: prog4.out
-- can't run this program
BACK TO CS3660 PAGE.