home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / TREES.ZIP / TREES.PAS
Encoding:
Pascal/Delphi Source File  |  1985-12-28  |  15.1 KB  |  508 lines

  1. cat tree.pas
  2. program address (input, output, infile, outfile);
  3.  
  4. {
  5. {     Rich Gregory -- 8842041  CS 352 -- Dr. Pfaltz -- 10/15/84
  6. {
  7. {     On my honor as a student, I have neither given nor received
  8. {     help on this programming assignment.
  9. {
  10. {     Signed:
  11. {
  12. {
  13. {
  14. }
  15.  
  16. { *****************************************************
  17. { This program creates a binary tree to be used for looking
  18. { up phne numbers.  Each Node is a record that contains a Name,
  19. { phone number, and the pointers to its two daughter nodes.
  20. }
  21.  
  22. const
  23.    DASH       = 45;
  24.    MAXNAME    = 25;
  25.    MAXNUMBER  = 13;
  26.    ENDFILE    = -1;
  27.    ENDSTR     = 0;
  28.    NEWLINE    = 10;
  29.  
  30. type
  31.    character         = -1..127;             { NOTE! NOT type "char" }
  32.    name_type         = array[1..MAXNAME] of character;
  33.    phone_number_type = array[1..MAXNUMBER] of character;
  34.    info = record
  35.       name         : name_type;
  36.       phone_number : phone_number_type;
  37.       end;
  38.    ptr = ^node;
  39.    node = record                     { typical node in tree }
  40.       person : info;                 { entry for a person   }
  41.       out1   : ptr;                  { less than descendant }
  42.       out2   : ptr;                  { greater descendant   }
  43.       end;
  44.  
  45. var
  46.    tree        : ptr;                   { root of tree            }
  47.    no_links    : integer;               { to monitor performance }
  48.    infile,
  49.    outfile     : text;                  { input/output files     }
  50.  
  51. { * * * * * end of global declarations * * * * * }
  52.  
  53. procedure file_rewrite ( var name_of_file : text);
  54.  
  55. begin {file_rewrite}
  56. { assign (name_of_file, 'm:phone.dat'); }
  57. rewrite (name_of_file, 'phone.out');
  58. end; {file_rewrite}
  59.  
  60. procedure file_reset ( var name_of_file : text);
  61.  
  62. begin {file_reset}
  63. { assign (name_of_file, 'a:phone.dat'); }
  64. reset  (name_of_file, 'phone.dat');                   
  65.  
  66. end; {file_reset}
  67.  
  68. procedure free_cell (cell : ptr);
  69. begin
  70. mark (cell);
  71. release (cell);
  72. }
  73. dispose (cell);
  74. end; {free_cell}
  75.  
  76. { ***********  END OF TURBO DEPENDENT STUFF  ********************  }
  77.  
  78. FUNCTION is_digit (c: character) : boolean;
  79.    { Returns "true" if "c" is a digit }
  80.  
  81. begin {is digit}
  82. is_digit := c in [ord ('0') ..ord ('9') ]
  83. end; { is_digit }
  84.  
  85. FUNCTION is_letter (c: character) : boolean;
  86.    { Returns `true` if "c" is a letter }
  87.  
  88. begin {is letter}
  89. is_letter := c in [ord ('a') ..ord ('z') ] + [ord ('A') ..ord ('Z') ]
  90. end; { is_letter }
  91.  
  92. FUNCTION get_char (var f: text; var c: character) : character;
  93.    { get a single character from the file "f" }
  94.    var  ch : char;
  95. begin
  96. if (eof (f))
  97.    then c := ENDFILE
  98.    else if (eoln (f))
  99.            then begin
  100.                 readln (f);
  101.                 c := NEWLINE
  102.                 end
  103.            else begin
  104.                 read (f, ch);
  105.                 c := ord (ch)
  106.                 end;
  107. get_char := c;
  108. end; { get_char }
  109.  
  110. { * * * * * * * End of low-level CHARACTER procedures * * * * * * }
  111.  
  112. FUNCTION get_name (var f: text; var name: name_type) : character;
  113.    { get (read) a "name" from the file "f" }
  114.    var  i : integer;
  115.         done : boolean;
  116.         c : character;
  117. begin
  118. i := 0;
  119. done := false;
  120. while (not done) do
  121.       begin
  122.       c := get_char (f, c);
  123.       if (c = ENDFILE)
  124.          then done := true
  125.          else if (is_letter (c))
  126.                  then begin
  127.                       i := i + 1;
  128.                       name[i] := c;
  129.                       if (i = (MAXNAME - 1))
  130.                          then done := true
  131.                       end
  132.                  else if (i <> 0)
  133.                       then done := true;
  134.         end; { while }
  135.    i := i + 1;
  136.    name[i] := ENDSTR;
  137.    if ((c = ENDFILE) and (i <= 1))
  138.       then get_name := ENDFILE
  139.       else get_name := 1;
  140.    if (name[1] = ord('z')) and (name[2] = ord('z'))
  141.       then get_name := ENDFILE;
  142. end; { get_name }
  143.  
  144. FUNCTION get_number (var f: text; var number: phone_number_type) : character;
  145.    { Get (read) a phone number from the file "f" }
  146.    var  i: integer;
  147.         done : boolean;
  148.         c: character;
  149. begin
  150. i := 0;
  151. done := false;
  152. while (not done) do
  153.       begin
  154.       c := get_char (f, c);
  155.       if ((c = ENDFILE) or (c = NEWLINE))
  156.          then done := true
  157.          else if (is_digit (c) or (c = DASH))
  158.                  then begin
  159.                       i := i + 1;
  160.                       number[i] := c;
  161.                       if (i = (MAXNUMBER - 1))
  162.                          then done := true
  163.                       end
  164.                  else if (i <> 0)      { ignore leading garbage }
  165.                          then done := true;
  166.       end; { while }
  167. i := i + 1;
  168. number[i] := ENDSTR;
  169. if ((c = ENDFILE) and (i <= 1))
  170.    then get_number := ENDFILE
  171.    else get_number := 1;
  172. end; { get_number }
  173.  
  174. FUNCTION get_data (var f: text; var person: info) : character;
  175.    { This procedure reads the name and phone number from the text file f.
  176.    { Note: 1. any string of maxstring letters are the name
  177.    {       2. leading blanks are ignored.
  178.    {       3. any none alpabetic character terminates the name
  179.    }
  180. begin {get data}
  181. get_data := get_name (f, person.name);
  182. get_data := get_number (f, person.phone_number);
  183. end; { get data }
  184.  
  185. PROCEDURE put_name (var f: text; var s: name_type);
  186.    { write a "name" on file "f" }
  187.    var  i: integer;
  188.  
  189. begin {put name}
  190. i := 1;
  191. while (s[i] <> ENDSTR) do
  192.       begin
  193.       write (f, chr (s[i]));
  194.       i := i + 1
  195.       end
  196. end; { put_name }
  197.  
  198. PROCEDURE put_number (var f: text; var number : phone_number_type);
  199.    { write a phone number on the file "f" }
  200. var
  201.    i: integer;
  202.  
  203. begin {put number}
  204.    i := 1;
  205.    while (number [i] <> ENDSTR) do begin
  206.       write (f, chr (number [i]));
  207.       i := i + 1
  208.       end
  209. end; { put_number }
  210.  
  211. FUNCTION lex_equal (var nm1, nm2: name_type) : boolean;
  212.    { Returns "true" if the two names are lexicographically equal }
  213.    var
  214.      i : integer;
  215.      l_equal : boolean;
  216.  
  217. begin {lex_equal}
  218.  
  219. i := 1;
  220. while ((nm1[i] = nm2[i]) and (nm1[i] <> ENDSTR)) do
  221.     i := i + 1;
  222. l_equal := ((nm1[i] = ENDSTR) and (nm1[i] = nm2[i]));
  223. {
  224. if l_equal
  225.   then writeln ('equal')
  226.   else writeln ('not equal');
  227. }
  228. lex_equal := l_equal;
  229.  
  230. end; { lex_equal  }
  231.  
  232. FUNCTION lex_less_than (var nm1, nm2: name_type) : boolean;
  233.    { Return "true" if "nm1" is lexicographically less than "nm2" }
  234.    var  i: integer;
  235.  
  236. begin {lex_less_than}
  237.  
  238. i := 1;
  239. while ((nm1[i] = nm2[i]) and (nm1[i] <> ENDSTR)) do
  240.       i := i + 1;
  241. lex_less_than := (nm1[i] < nm2[i])
  242.  
  243. end; { lex_less_than }
  244.  
  245. { * * * * * * * * * End of NAME and NUMBER procedures * * * * * * * * }
  246.  
  247. PROCEDURE add_entry (var root_tree  : ptr;   {pointer to the root}
  248.                      var key        : info); {key is the name and number}
  249.  
  250.    { This routine looks up the given "key" in a binary-tree
  251.    { phone book, with principal point "root_tree".
  252.    { If the person has already been entered into the phone book,
  253.    { nothing is done, otherwise then a cell denoting this person
  254.    { is added to the phone book.
  255.    {
  256.    {      * * * as a class exercise only * * *
  257.    { "add_entry" should count the number of links it follows to:
  258.    { 1. find the key, or
  259.    { 2. enter a new key.  (count the newly created link as if
  260.    {                       it had been followed.)
  261.    { and return this value in the global variable "no_links".
  262.    }
  263.  
  264.   var
  265.     add         : boolean;
  266.     local_ptr,
  267.     cell        : ptr;
  268.     temp_name   : name_type;
  269.  
  270. begin {add_entry}
  271. write ('.');
  272. no_links := 0;
  273. local_ptr := root_tree;
  274. if root_tree = nil
  275.   then begin
  276.        new (root_tree);
  277.        root_tree^.person := key;
  278.        root_tree^.out1 := nil;
  279.        root_tree^.out2 := nil;
  280.        end {then}
  281.   else begin
  282.        while local_ptr <> nil do
  283.            begin {while}
  284.            add := false;
  285.            cell := local_ptr;
  286.            if lex_equal (key.name, local_ptr^.person.name)
  287.               then begin
  288.                    writeln ('Had a duplicate');
  289.                    local_ptr := nil;
  290.                    end {then}
  291.               else begin
  292.                    if lex_less_than (key.name,
  293.                                      local_ptr^.person.name)
  294.                       then local_ptr := local_ptr^.out2
  295.                       else local_ptr := local_ptr^.out1;
  296.                    no_links := no_links + 1;
  297.                    add := true;
  298.                    end; {else}
  299.            end; {while}
  300.  
  301.        if add
  302.           then begin
  303.                {NOW cell is pointing at the cell that will be KEY's parent}
  304.                local_ptr := cell;
  305.                new (cell);
  306.                if lex_less_than (key.name, local_ptr^.person.name)
  307.                   then local_ptr^.out2 := cell
  308.                   else local_ptr^.out1 := cell;
  309.                cell^.person := key;
  310.                cell^.out1 := nil;
  311.                cell^.out2 := nil;
  312.                end; {then add}
  313.        end; {else}
  314.  
  315. end; { add_entry }
  316.  
  317.                  
  318. FUNCTION name_lookup (point: ptr; var key: info) : boolean;
  319.    { Given key, this function looks up that name in the phone book.
  320.    { It returns the true if the person was in the phone book, and
  321.    { sets the pointer (record) to the phone number;
  322.    { it returns false, if the person is not in phone book.
  323.    }
  324.   var
  325.     local_ptr,
  326.     cell       : ptr;
  327.     find       : boolean;
  328.  
  329. begin {name lookup}
  330. no_links := 0;
  331. if point = nil
  332.    then find := false
  333.    else begin
  334.         local_ptr := point;
  335.         find := false;
  336.         while local_ptr <> nil do
  337.            begin {while}
  338.            cell := local_ptr;
  339.            if lex_equal (key.name, local_ptr^.person.name)
  340.               then begin
  341.                    writeln (output, ' found');
  342.                    put_name (OUTPUT, local_ptr^.person.name);
  343.                    key.phone_number := local_ptr^.person.phone_number;
  344.                    { writeln (' Found a duplicate'); }
  345.                    find := true;
  346.                    local_ptr := nil;
  347.                    end {then}
  348.               else begin
  349.                    no_links := no_links + 1;
  350.                    writeln (output, ' Not found');
  351.                    put_name (OUTPUT, local_ptr^.person.name);
  352.                    if lex_less_than (key.name,
  353.                                      local_ptr^.person.name)
  354.                       then local_ptr := local_ptr^.out2
  355.                       else local_ptr := local_ptr^.out1;
  356.                    end; {else}
  357.            end; {while}
  358.         end; {else}
  359.  
  360. name_lookup := find;
  361. end; { name_lookup }
  362.  
  363. PROCEDURE print_tree (var f: text; p: ptr; depth_number: integer);
  364.    { this procedure displays a binary tree-structured lexicon
  365.    { by printing the values assigned to each point, spaced across the
  366.    { page to indicate its depth in the tree.
  367.    }
  368.    var  i: integer;
  369. begin
  370. if (p <> nil)
  371.    then begin
  372.         print_tree (f, p^.out2, depth_number + 1);
  373.         for i := 1 to depth_number do
  374.             write (f, '          ');
  375.         write (f, ' (');
  376.         put_name (f, p^.person.name);
  377.         writeln (f);
  378.         for i := 1 to depth_number do
  379.             write (f, '          ');
  380.         write (f, '  ');
  381.         put_number (f, p^.person.phone_number);
  382.         writeln (f);
  383.         print_tree (f, p^.out1, depth_number + 1);
  384.         end;
  385. end; { print_tree }
  386.  
  387. PROCEDURE dump_structure (var f: text);
  388.    { Dump the current structure in some appropriate format }
  389.  
  390. begin {dump structure}
  391.  
  392. print_tree (f, tree, 0);
  393.  
  394. end; { dump_structure }
  395.  
  396. FUNCTION tree_depth (p: ptr) : integer;
  397.    { compute the depth of the tree }
  398.    var  less_than_depth, greater_than_depth: integer;
  399.  
  400. begin {tree depth}
  401. if (p = nil)
  402.    then tree_depth := 0
  403.    else begin
  404.         less_than_depth := tree_depth (p^.out1) + 1;
  405.         greater_than_depth := tree_depth (p^.out2) + 1;
  406.         if (less_than_depth > greater_than_depth)
  407.            then tree_depth := less_than_depth
  408.            else tree_depth := greater_than_depth
  409.         end {else}
  410. end; {tree depth}
  411.  
  412. PROCEDURE main;
  413.    { This main procedure reads a selection of natural language
  414.    { text, and creates a "lexicon" of every word that occurs
  415.    { within the text together with a count of the number of
  416.    { appearances.
  417.    { It then dump_structures the representing data structure, and prints
  418.    { out a variety of counts describing its performance.
  419.    { finally, it reads in a random selection of words, and
  420.    { looks them up in the lexicon.
  421.    }
  422.    var  done              : boolean;
  423.         phone_entry       : info;
  424.         query             : name_type;
  425.         no_entries        : integer;               { number of people processed }
  426.         max_links,
  427.         total_links       : integer;   { behavior counts }
  428.         average           : real;
  429.  
  430. begin {main}
  431. tree := nil;
  432. no_links := 0;
  433. no_entries := 0;
  434. total_links := 0;
  435. max_links := 0;
  436.  
  437.    { main while loop.   echo input words and add_entry them.            }
  438.  
  439. while (get_data (infile, phone_entry) <> ENDFILE) do
  440.       begin {while}
  441.       add_entry (tree, phone_entry);
  442.  
  443.                  { collect counts to monitor access performance }
  444.       no_entries := no_entries + 1;
  445.       total_links := total_links + no_links;
  446.       if no_links > max_links
  447.          then max_links := no_links;
  448.       no_links := 0;
  449.       end;   { main while loop }
  450. writeln('End of file on input');
  451.  
  452.                  { dump_structure data structure, and print statistics }
  453.                  { describing the access performance.        }
  454.  
  455. writeln (outfile);
  456. dump_structure (outfile);
  457. writeln (outfile, 'depth is ', tree_depth (tree));
  458. writeln (outfile);
  459. writeln (outfile, ' total number of entries = ', no_entries:3);
  460. writeln (outfile, ' total number of links followed = ', total_links:4);
  461. average := total_links / no_entries;
  462. writeln (outfile, ' average number of links per entry = ', average:8:4);
  463. writeln (outfile, ' maximum number of links followed = ', max_links:4);
  464.  
  465.                 { test the system with a sequence of random queries }
  466.  
  467. writeln (outfile);
  468.  
  469. writeln (output, '  process some sample queries');
  470. done := false;
  471. while (not done) do
  472.       begin  { look up this query word }
  473.       write ('name? (Type zz<cr> to end) ');
  474.       if (get_name (input, query) = ENDFILE)
  475.          then done := true
  476.          else begin
  477.               { put_name (output, query); }
  478.               phone_entry.name := query;
  479.               if (not name_lookup (tree, phone_entry))
  480.                  then begin
  481.                       writeln (OUTPUT);
  482.                       put_name (OUTPUT, query);
  483.                       writeln (OUTPUT, ' is not in the phone book')
  484.                       end {then}
  485.                  else begin
  486.                       writeln (OUTPUT);
  487.                       put_name (OUTPUT, query);
  488.                       write (OUTPUT, '''s phone number is ');
  489.                       put_number (OUTPUT, phone_entry.phone_number);
  490.                       writeln (OUTPUT);
  491.                       end;
  492.               writeln (OUTPUT, 'The number of links traversed was ',
  493.                        no_links);
  494.               end;
  495.     {
  496.      }
  497.       end; { while }
  498. end; { main }
  499.  
  500. begin {address}        { 2 4 6 8 0}
  501. file_reset (infile);
  502. file_rewrite (outfile);
  503. main;
  504. close (infile);
  505. close (outfile);
  506. end. {address}
  507.