home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progpas / animls.arj / TREE.INC < prev    next >
Text File  |  1990-07-26  |  16KB  |  591 lines

  1.  
  2. {*************************************************************************
  3.  
  4.     This toolbox provides elementry operations on a binary tree.
  5.     the following declarations are assumed to have been made:
  6.  
  7.           type
  8.                    ElementType = ...
  9.  
  10.           PROCEDURE Print(e : ElementType);
  11.           BEGIN
  12.           .
  13.           .
  14.           .
  15.           END;
  16.  
  17.     The ElementType is used to construct nodes of the binary tree.
  18.     The PROCEDURE Print is used to display the ElementType on the screen.
  19.  
  20.     The following global variables are created:
  21.  
  22.        root   (A pointer to the root node of the tree.)
  23.        cursor (A general-purpose pointer to nodes.)
  24.  
  25.     The following FUNCTIONs and PROCEDUREs are available For use:
  26.  
  27.             PROCEDURE InitialiseTree;
  28.  
  29.     (This PROCEDURE should be called only once, beFore any
  30.      tree processing is attempted.)
  31.  
  32.              PROCEDURE FinaliseTree;
  33.  
  34.     (This PROCEDURE should be called once when all processing on the tree
  35.      has been completed.)
  36.  
  37.              FUNCTION TreeEmpty : boolean;
  38.  
  39.     (This FUNCTION returns TRUE Iff no elements exist in the tree.)
  40.  
  41.              FUNCTION InTree : boolean;
  42.  
  43.     (This FUNCTION returns TRUE Iff the cursor is presently pointing at a
  44.      valid member of the tree.)
  45.  
  46.              FUNCTION AtRoot : boolean;
  47.  
  48.     (This FUNCTION returns TRUE Iff the cursor is presently pointing at the
  49.      root node of the tree.)
  50.  
  51.              FUNCTION EmptyLeft : boolean;
  52.  
  53.     (This FUNCTION returns TRUE Iff the left successor of the cursor node
  54.      has not been defined.)
  55.  
  56.               FUNCTION EmptyRight : boolean;
  57.  
  58.     (This FUNCTION returns TRUE Iff the right successor of the cursor node
  59.      has not been defined.)
  60.  
  61.               FUNCTION IsLeaf : boolean;
  62.  
  63.     (This FUNCTION returns TRUE Iff both the left and the right successors
  64.      of the cursor node have not been defined.)
  65.  
  66.               PROCEDURE LocateAtRoot;
  67.  
  68.     (This PROCEDURE sets the cursor pointing at the root node.)
  69.  
  70.               PROCEDURE GoLeft;
  71.  
  72.     (This PROCEDURE sets the cursor to point at the left successor of the
  73.     current node. It is a terminal error If this node is empty.)
  74.  
  75.               PROCEDURE GoRight;
  76.  
  77.     (This PROCEDURE sets the cursor to point at the right successor of the
  78.     current node. It is a terminal error If this node is empty.)
  79.  
  80.                PROCEDURE GoParent;
  81.  
  82.     (This PROCEDURE sets the cursor to point at the predecessor of the
  83.     current node. It is a terminal error If this is called when the cursor
  84.     is pointing at the root node.)
  85.  
  86.                PROCEDURE GetContentsIn(var this : ElementType);
  87.  
  88.     (This PROCEDURE obtains the inFormation in the cursor node and returns
  89.     it in the parameter provided.  It is a terminal error If the cursor is not
  90.     defined.)
  91.  
  92.                 PROCEDURE ReplaceWith(this : ElementType);
  93.  
  94.     (This PROCEDURE replaces the inFormation in the cursor node with the
  95.     inFormation contained in and the parameter provided.  It is a terminal
  96.     error If the cursor is not defined.)
  97.  
  98.                  PROCEDURE InsertRoot(this : ElementType);
  99.  
  100.     (This PROCEDURE creates a new node element in an empty tree.  It is a
  101.     terminal error If the tree is not empty.)
  102.  
  103.                   PROCEDURE InsertLeft(this : ElementType);
  104.  
  105.     (This PROCEDURE creates a new node element as the left successor of the
  106.     cursor node.  The cursor does not move.  It is a terminal error If the
  107.     cursor is not defined or If a left node alReady exists.)
  108.  
  109.                   PROCEDURE InsertRight(this : ElementType);
  110.  
  111.     (This PROCEDURE creates a new node element as the right successor of the
  112.     cursor node.  The cursor does not move. It is a terminal error If the
  113.     cursor is not defined or If a right node alReady exists.)
  114.  
  115.                   PROCEDURE Remove;
  116.  
  117.     (This PROCEDURE deletes the cursor node and any tree under it.  It is a
  118.     terminal error If the tree is empty.)
  119.  
  120.                   PROCEDURE PrepareTraverse(order : TreeOrder);
  121.  
  122.     (This PROCEDURE prepares For a traverse of the tree in the order
  123.     specIfied.  This MUST be done beFore any attempt is made to traverse
  124.     the tree.  After a successful call to this PROCEDURE the cursor is
  125.     located at the first element in the traverse.)
  126.  
  127.                   PROCEDURE Traverse;
  128.  
  129.     (After the PrepareTraverse PROCEDURE is called, successive calls to this
  130.     PROCEDURE will position the cursor across the tree in the order specIfied.
  131.     The traverse is completed when the cursor is no longer in the tree.  A
  132.     terminal error occurs when a traverse call is attempted on a finished scan.)
  133.  
  134.                    PROCEDURE PrintTree(IndentIncrement : integer);
  135.  
  136.     (This PROCEDURE will print the tree sideways on the screen using the print
  137.     PROCEDURE to control the output.  The parameter specIfiies the number of
  138.     spaces to be used on each indent level.)
  139.  
  140.                    PROCEDURE SaveTree(FileName : string35);
  141.  
  142.     (This PROCEDURE will Write the tree to a disk file with the name specIfied.
  143.      If an error occurs when opening the file, no save is perFormed.)
  144.  
  145.  
  146.                    PROCEDURE ReadTree(FileName : string35);
  147.  
  148.     (This PROCEDURE will Read the tree to a disk file with the name specIfied.
  149.      If an error occurs when opening the file, no Read is perFormed.)
  150.  
  151. *************************************************************************}
  152.  
  153. Type
  154.       NodePtr = ^Nodes;
  155.       Nodes   = RECORD
  156.                    element      : ElementType;
  157.                    left, right,
  158.                    parent       : NodePtr
  159.                  END;
  160.  
  161.   TreeOrder = (preorder, inorder, postorder);
  162.   TraversePtr = ^TraverseNodes;
  163.  
  164.   TraverseNodes = RECORD
  165.                     np   : NodePtr;
  166.                     next : TraversePtr
  167.                   END;
  168.  
  169.        String35  = string[35];
  170.  
  171. Var
  172.   root, cursor    : NodePtr;
  173.   TraverseCursor,
  174.   TraverseHead    : TraversePtr;
  175.  
  176. {---------------------------------}
  177. PROCEDURE TreeError(s : String35);
  178. BEGIN
  179.   Writeln('Tree error, ',s);
  180.   halt
  181. END;
  182.  
  183. {---------------------------------}
  184. FUNCTION TreeEmpty : boolean;
  185. BEGIN
  186.   TreeEmpty := (root = nil)
  187. END;
  188.  
  189. {---------------------------------}
  190. FUNCTION InTree : boolean;
  191. BEGIN
  192.   InTree := (cursor <> nil)
  193. END;
  194.  
  195. {---------------------------------}
  196. FUNCTION AtRoot : boolean;
  197. BEGIN
  198.   AtRoot := (cursor = root);
  199. END;
  200.  
  201. {---------------------------------}
  202. FUNCTION EmptyLeft : boolean;
  203. BEGIN
  204.   If not InTree then TreeError('cursor is not defined For EmptyLeft.')
  205.   else
  206.     EmptyLeft := (cursor^.left = nil);
  207. END;
  208.  
  209. {---------------------------------}
  210. FUNCTION EmptyRight : boolean;
  211. BEGIN
  212.   If not InTree then TreeError('cursor is not defined For EmptyRight.')
  213.   else
  214.     EmptyRight := (cursor^.right = nil);
  215. END;
  216.  
  217. {---------------------------------}
  218. FUNCTION IsLeaf : boolean;
  219. BEGIN
  220.   If not InTree then TreeError('cursor is not defined For IsLeaf.')
  221.   else
  222.     IsLeaf := (EmptyRight and EmptyLeft);
  223. END;
  224.  
  225. {---------------------------------}
  226. PROCEDURE LocateAtRoot;
  227. BEGIN
  228.   cursor := root
  229. END;
  230.  
  231. {---------------------------------}
  232. PROCEDURE GoLeft;
  233. BEGIN
  234.   If not InTree then TreeError('cursor is not defined For GoLeft.')
  235.   else
  236.     cursor := cursor^.left
  237. END;
  238.  
  239. {---------------------------------}
  240. PROCEDURE GoRight;
  241. BEGIN
  242.   If not InTree then TreeError('cursor is not defined For GoRight.')
  243.   else
  244.     cursor := cursor^.right
  245. END;
  246.  
  247. {---------------------------------}
  248. PROCEDURE GoParent;
  249. BEGIN
  250.   If not InTree then TreeError('cursor is not defined For GoParent.')
  251.   else If AtRoot then TreeError('root node has no parent in GoParent.')
  252.   else
  253.     cursor := cursor^.parent
  254. END;
  255.  
  256. {---------------------------------}
  257. PROCEDURE GetContentsIn(var this : ElementType);
  258. BEGIN
  259.   If not InTree then TreeError('cursor is not defined For GetContentsIn.')
  260.   else
  261.     this := cursor^.element
  262. END;
  263.  
  264. {---------------------------------}
  265. PROCEDURE ReplaceWith(This : ElementType);
  266. BEGIN
  267.   If not InTree then TreeError('cursor is not defined For ReplaceWith.')
  268.   else
  269.     cursor^.element := this
  270. END;
  271.  
  272. {---------------------------------}
  273. PROCEDURE MakeNode(this : ElementType; ParentNode : NodePtr;
  274.                    var  NewNode : NodePtr);
  275. BEGIN
  276.   new(NewNode);
  277.   with NewNode^ do
  278.     BEGIN
  279.       element := this;
  280.       left := nil;
  281.       right := nil;
  282.       parent := ParentNode
  283.     END
  284.  END;
  285.  
  286. {---------------------------------}
  287. PROCEDURE InsertRoot(this : ElementType);
  288. BEGIN
  289.   If not TreeEmpty then TreeError('root alReady present For InsertRoot.')
  290.   else
  291.     MakeNode(this,nil,root)
  292. END;
  293.  
  294. {---------------------------------}
  295. PROCEDURE InsertLeft(this : ElementType);
  296. BEGIN
  297.   If not InTree then TreeError('cursor not defined For InsertLeft.')
  298.   else
  299.     If not EmptyLeft then TreeError('left node alReady exists in InsertLeft.')
  300.     else MakeNode(this, cursor, cursor^.left)
  301. END;
  302.  
  303. {---------------------------------}
  304. PROCEDURE InsertRight(this : ElementType);
  305. BEGIN
  306.   If not InTree then TreeError('cursor not defined For InsertRight.')
  307.   else
  308.     If not EmptyRight then TreeError('right node alReady exists in InsertRight.')
  309.     else MakeNode(this, cursor, cursor^.right)
  310. END;
  311.  
  312. {---------------------------------}
  313. PROCEDURE RemoveNodes(n : NodePtr);
  314. BEGIN
  315.   If n <> nil then
  316.     BEGIN
  317.       RemoveNodes(n^.left);
  318.       RemoveNodes(n^.right);
  319.       dispose(n)
  320.     END
  321. END;
  322.  
  323. {---------------------------------}
  324. PROCEDURE Remove;
  325. BEGIN
  326.   If TreeEmpty then TreeError('no tree to delete in Remove')
  327.   else
  328.     BEGIN
  329.       If AtRoot then root := nil
  330.       else
  331.         with cursor^.parent^ do
  332.           If cursor = left then left  := nil
  333.                            else right := nil;
  334.       RemoveNodes(cursor);
  335.       cursor := nil
  336.     END;
  337. END;
  338.  
  339. {---------------------------------}
  340. PROCEDURE EraseTraverseList;
  341. var
  342.   p,q : TraversePtr;
  343. BEGIN
  344.   If TraverseHead = nil then exit;
  345.   p := TraverseHead;
  346.   repeat
  347.     q := p;
  348.     p := p^.next;
  349.     dispose(q);
  350.   until p^.next = nil;
  351.   TraverseHead := nil;
  352.   TraverseCursor := nil
  353. END;
  354.  
  355. {---------------------------------}
  356. PROCEDURE PrepareTraverse(order : TreeOrder);
  357.  
  358.   {---------------------------------}
  359.   PROCEDURE AddTraverse(n : NodePtr);
  360.   BEGIN
  361.     If TraverseHead = nil then
  362.       BEGIN
  363.         new(TraverseHead);
  364.         TraverseCursor := TraverseHead
  365.       END
  366.     else
  367.       BEGIN
  368.         new(TraverseCursor^.next);
  369.         TraverseCursor := TraverseCursor^.next
  370.       END;
  371.     TraverseCursor^.np := n;
  372.     TraverseCursor^.next := nil
  373.   END;
  374.  
  375.   {---------------------------------}
  376.   PROCEDURE TraverseInOrder(n : NodePtr);
  377.   BEGIN
  378.     If n <> nil then
  379.       with n^ do
  380.         BEGIN
  381.           TraverseInOrder(left);
  382.           AddTraverse(n);
  383.           TraverseInOrder(right)
  384.         END
  385.   END;
  386.  
  387.   {---------------------------------}
  388.   PROCEDURE TraversePreOrder(n : NodePtr);
  389.   BEGIN
  390.     If n <> nil then
  391.       with n^ do
  392.         BEGIN
  393.           AddTraverse(n);
  394.           TraversePreOrder(left);
  395.           TraversePreOrder(right)
  396.         END
  397.   END;
  398.  
  399.   {---------------------------------}
  400.   PROCEDURE TraversePostOrder(n : NodePtr);
  401.   BEGIN
  402.     If n <> nil then
  403.       with n^ do
  404.         BEGIN
  405.           TraversePostOrder(left);
  406.           TraversePostOrder(right);
  407.           AddTraverse(n);
  408.         END
  409.   END;
  410.  
  411.  
  412. BEGIN
  413.   EraseTraverseList;
  414.   If TreeEmpty then exit;
  415.   Case order of
  416.     inorder   : TraverseInOrder(root);
  417.     preorder  : TraversePreOrder(root);
  418.     postorder : TraversePostOrder(root)
  419.   END;
  420.   TraverseCursor := TraverseHead;
  421.   cursor := TraverseCursor^.np
  422. END;
  423.  
  424. {---------------------------------}
  425. PROCEDURE Traverse;
  426. BEGIN
  427.   If TraverseCursor = nil then TreeError('traverse has been completed.')
  428.   else
  429.     BEGIN
  430.       TraverseCursor := TraverseCursor^.next;
  431.       If TraverseCursor = nil then cursor := nil
  432.                               else cursor := TraverseCursor^.np;
  433.     END
  434. END;
  435.  
  436. {---------------------------------}
  437. FUNCTION TreeDepth:integer;
  438. var
  439.   MaxDepth : integer;
  440.  
  441.   {---------------------------------}
  442.   PROCEDURE Scan(n : NodePtr; d : integer);
  443.   BEGIN
  444.     If n <> nil then
  445.       with n^ do
  446.         BEGIN
  447.           If d > MaxDepth then MaxDepth := d;
  448.           Scan(left,d+1);
  449.           Scan(right,d+1)
  450.         END
  451.   END;
  452.  
  453. BEGIN
  454.   MaxDepth := 0;
  455.   Scan(root,0);
  456.   TreeDepth := MaxDepth
  457. END;
  458.  
  459. {---------------------------------}
  460. PROCEDURE PrintTree(IndentIncrement : integer);
  461.  
  462.   {---------------------------------}
  463.   PROCEDURE TraversePrintOrder(n : NodePtr; indent : integer);
  464.   var
  465.     j : integer;
  466.   BEGIN
  467.     If n <> nil then
  468.       with n^ do
  469.         BEGIN
  470.           TraversePrintOrder(right, indent + IndentIncrement);
  471.           For j := 1 to indent do Write(' ');
  472.           Print(element);
  473.           TraversePrintOrder(left, indent + IndentIncrement);
  474.         END
  475.   END;
  476.  
  477. BEGIN
  478.   If TreeEmpty then exit;
  479.   TraversePrintOrder(root,0);
  480. END;
  481.  
  482. {---------------------------------}
  483. PROCEDURE InitialiseTree;
  484. BEGIN
  485.   root := nil;
  486.   cursor := nil;
  487.   TraverseHead := nil
  488. END;
  489.  
  490. {---------------------------------}
  491. PROCEDURE FinaliseTree;
  492. BEGIN
  493.   If root <> nil then RemoveNodes(root);
  494.   EraseTraverseList
  495. END;
  496.  
  497. {---------------------------------}
  498. PROCEDURE SaveTree(FileName : string35);
  499. type
  500.   Daughters = (L,R,LR,None);
  501.   SaveType = record
  502.                e : ElementType;
  503.                d : Daughters
  504.              END;
  505. var
  506.   sn : SaveType;
  507.   f  : file of SaveType;
  508.  
  509.   {---------------------------------}
  510.   PROCEDURE SaveScan;
  511.   BEGIN
  512.     If InTree then
  513.       BEGIN
  514.         GetContentsIn(sn.e);
  515.         If not EmptyLeft and EmptyRight then sn.d := L
  516.         else If not EmptyRight and EmptyLeft then sn.d := R
  517.         else If EmptyLeft and EmptyRight then sn.d := None
  518.         else sn.d := LR;
  519.         Write(f,sn);
  520.         Case sn.d of
  521.           L    : BEGIN GoLeft; SaveScan; GoParent END;
  522.           R    : BEGIN GoRight; SaveScan; GoParent END;
  523.           LR   : BEGIN GoLeft; SaveScan; GoParent; GoRight; SaveScan; GoParent END
  524.         END
  525.       END
  526.   END;
  527.  
  528. BEGIN
  529.   Assign(f,FileName);
  530.   {$I-}  reWrite(f); {$I+}
  531.   If IOResult <> 0 then exit;
  532.   LocateAtRoot;
  533.   SaveScan;
  534.   Close(f)
  535. END;
  536.  
  537. {---------------------------------}
  538. PROCEDURE ReadTree(FileName : string35);
  539. type
  540.   Directions = (ToLeft,ToRight);
  541.   Daughters = (L,R,LR,None);
  542.   ReadType = record
  543.                e : ElementType;
  544.                d : Daughters
  545.              END;
  546. var
  547.   rn : ReadType;
  548.   f  : file of ReadType;
  549.  
  550.   {---------------------------------}
  551.   PROCEDURE ReadScan(direction: Directions);
  552.   BEGIN
  553.     Read(f,rn);
  554.     If direction = ToLeft then
  555.       BEGIN
  556.         InsertLeft(rn.e);
  557.         GoLeft
  558.       END
  559.     else
  560.       BEGIN
  561.         InsertRight(rn.e);
  562.         GoRight
  563.       END;
  564.       Case rn.d of
  565.         L    : BEGIN ReadScan(ToLeft); GoParent END;
  566.         R    : BEGIN ReadScan(ToRight); GoParent END;
  567.         LR   : BEGIN ReadScan(ToLeft); GoParent; ReadScan(ToRight); GoParent END;
  568.       END
  569.   END;
  570.  
  571.  
  572. BEGIN
  573.   Assign(f,FileName);
  574.   {$I-}  Reset(f); {$I+}
  575.   If IOResult <> 0 then exit;
  576.   FinaliseTree;
  577.   InitialiseTree;
  578.   If not eof(f) then
  579.     BEGIN
  580.       Read(f,rn);
  581.       InsertRoot(rn.e);
  582.       LocateAtRoot;
  583.       Case rn.d of
  584.         L  : ReadScan(ToLeft);
  585.         R  : ReadScan(ToRight);
  586.         LR : BEGIN ReadScan(ToLeft); GoParent; ReadScan(ToRight); GoParent END;
  587.       END;
  588.     END;
  589.   Close(f)
  590. END;
  591.