home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / SIMTEL / CPMUG / CPMUG050.ARK / HW5.PAS < prev    next >
Pascal/Delphi Source File  |  1984-04-29  |  15KB  |  442 lines

  1.  
  2. (*
  3. title    message decoding by optimal binary search tree building
  4.          using the hu-tucker algorithm
  5.          cs 321 homework 5
  6. author   robert a. van valzah   03/31/80
  7.  
  8.  
  9. this  program will build an optimal binary search tree given
  10. a set of characters and frequencies of occurance.  the  tree
  11. is constructed using the hu-tucker algorithm (see knuth, the
  12. art of computer programming, volume 3/sorting and searching,
  13. pp.  439-446).  an input sequence of 1's and 0's is then de-
  14. coded into a sequence of characters  using  this  tree.  the
  15. resulting message is printed.
  16. *)
  17.  
  18.  
  19. const
  20.    nmax     = 30; (* max number of characters *)
  21.    rl       = 9;  (* record length in words *)
  22.    dim      = 810;(* nmax * rl * 3 *)
  23.    char     = 0;  (* character value offset *)
  24.    freq     = 1;  (* character frequence offset *)
  25.    lst      = 2;  (* pointer to left  subtree offset *)
  26.    rst      = 3;  (* pointer to right subtree offset *)
  27.    lforst   = 4;  (* pointer to left  brother offset *)
  28.    rforst   = 5;  (* pointer to right brother offset *)
  29.    lev      = 6;  (* node level number *)
  30.    lexp     = 7;  (* pointer to lexicographic predecessor *)
  31.    lexs     = 8;  (* pointer to lexicographic successor *)
  32.  
  33.    nil      = 0;  (* zeroth element never used *)
  34.    sent     = '$';(* sentinal character *)
  35.    maxint   = 32767; (* kludge cause not defined by compiler *)
  36.  
  37. type
  38.    ary      = array[0..dim] of word;
  39.    boolean  = (false, true); (* kludge till compiler is done *)
  40.    
  41. var         (* global variables *)
  42.    h        : ary;  (* the heap *)
  43.    hp       : word; (* the heap pointer *)
  44.    lmost,
  45.    rmost    : word; (* left and right most ends of the list *)
  46.    lexfirst : word; (* pointer to first node in lex order *)
  47.  
  48. procedure new(var p:word);
  49.  
  50.    begin
  51.    hp:=hp+1;
  52.    p:=hp*rl;
  53.    if (p>dim-rl)
  54.       then put#1('heapover')
  55.    end; (* procedure new *)
  56.  
  57.  
  58. (*
  59. read  a  sequence of characters and weights from the standard
  60. input file and create a node for each  pair.  the  nodes  are
  61. linked into a doubly linked list to form a forest as they are
  62. read.
  63. *)
  64. procedure readtree;
  65.  
  66.    var
  67.       ch  : word;  (* node value *)
  68.       frq : word;  (* frequency *)
  69.       p   : word;  (* pointer to new node *)
  70.       prev: word;  (* pointer to previous node read (for linking) *)
  71.  
  72.    procedure readnode;
  73.  
  74.       var
  75.          c : word;
  76.  
  77.       begin
  78.       get#0(ch);    (* get node value character *)
  79.       if (ch<>sent)
  80.          then begin
  81.             get#0(c);
  82.             while (c=' ') do get#0(c);
  83.             frq:=0;
  84.             while (c>='0') and (c<='9') do begin
  85.                frq:=frq*10+c-'0';
  86.                get#0(c)
  87.                end (* while *)
  88.             end;
  89.       repeat get#0(c) until (c=10) (* ignore till lf found *)
  90.       end; (* readnode *)
  91.  
  92.    begin
  93.    readnode;        (* readln(ch, frq); *)
  94.    prev:=nil;       (* no left forest for first node *)
  95.    repeat
  96.       new(var p);
  97.       if (prev=nil) then lmost:=p; (* record pointer to first node *)
  98.       h[p+char  ]:=ch;
  99.       h[p+freq  ]:=frq;
  100.       h[p+lst   ]:=nil;  (* leaves have no subtrees *)
  101.       h[p+rst   ]:=nil;
  102.       h[p+lforst]:=prev; (* link to last node read created *)
  103.       h[p+lexp  ]:=prev; (* predecessor is also last node created *)
  104.       if (prev<>nil) then begin (* on all but first node . . . *)
  105.          h[prev+rforst  ]:=p;   (* make previous right forest pointer and *)
  106.          h[prev+lexs    ]:=p    (* lexicographic successor point to the new node *)
  107.          end;
  108.       prev:=p;
  109.       readnode
  110.    until (ch=sent);
  111.  
  112.    (* done reading nodes *)
  113.    rmost:=p;          (* record pointer to right most node *)
  114.    h[p+rforst]:=nil;  (* right most node has no right brother *)
  115.    h[p+lexs  ]:=nil   (* right most node has no lexicographic successor *)
  116.    end; (* procedure readtree *)
  117.  
  118.  
  119. (*
  120. given a forest of trees (all leaves when we start), build them
  121. into  a  single tree using phase 1 of the hu-tucker algorithm.
  122. the root of the resultant tree will be in lmost on exit.
  123.  
  124. the algorithm is implemented using two internal procedures.the
  125. first (picklr) chooses two  trees  for  combination,  and  the
  126. second  (combinelr)  combines the two chosen trees to form new
  127. internal node in the final  tree.  this  process  is  repeated
  128. unitl the forest contains only one tree.
  129. *)
  130. procedure build1tree;
  131.  
  132.    var left, rite : word; (* pointers to nodes to be combined *)
  133.  
  134.  
  135.    (*
  136.    pick  two  trees from the forest which satisfy the following
  137.    rules:
  138.  
  139.    let i and j be pointers to the left and right trees
  140.  
  141.    i)   no external nodes occur between i and j.
  142.  
  143.    ii)  the  sum of the weights of i and j is minimal for all i
  144.         and j satisfying rule (i).
  145.  
  146.    iii) the  index i is minimal for all i satisfying rules (i),
  147.         (ii).
  148.  
  149.    iv)  the  index j is minimal for all j satisfying rules (i),
  150.         (ii), (iii).
  151.  
  152.    pointers to the two trees chosen will be left  in  left  and
  153.    rite (respectivly).
  154.  
  155.    one  internal  procedure  is used to compare the minimum sum
  156.    found so far against the sum of the frequencies of the trees
  157.    under consideration.
  158.    *)
  159.    procedure picklr;
  160.  
  161.       var i,j : word; (* pointers to left and right nodes which
  162.                             are mininimum pair candidates *)
  163.           minsum : word; (* mininimum sum found so far *)
  164.  
  165.  
  166.       (*
  167.       compare  the sum of the frequencies of nodes i and j.  if
  168.       their sum is less than the minimum  found  so  far,  then
  169.       record  the  new  minimum (in minsum) and the position of
  170.       i and j as the two best candidates for combining.
  171.       *)
  172.       procedure takemin;
  173.  
  174.          begin
  175.          if (h[i+freq]+h[j+freq]<minsum) then begin
  176.             minsum:=h[i+freq]+h[j+freq];
  177.             rite:=j; left:=i
  178.             end
  179.          end; (* procedure takemin *)
  180.  
  181.  
  182.       begin (* procedure picklr *)
  183.       i:=lmost;         (* start with leftmost tree in forest *)
  184.       minsum:=maxint;
  185.       while (h[i+rforst]<>nil) do begin (* more i's to test *)
  186.          j:= h[i+rforst];
  187.  
  188.          (* compare to internal nodes till exeternal is found *)
  189.          while (h[j+char]=sent) do begin
  190.             takemin;
  191.             j:=h[j+rforst] (* on to the next tree *)
  192.             end;
  193.  
  194.          (* j now points to only external node candidate *)
  195.          takemin;
  196.          i:=h[i+rforst ]     (* move to next tree in forest *)
  197.          end (* while not out of i's *)
  198.       end; (* procedure picklr *)
  199.  
  200.  
  201.    (*
  202.    combine  the two trees pointed to by left and rite to form a
  203.    new internal node in the final  tree.  link  this  new  node
  204.    into  the  existing  forest  in place of the left tree.  the
  205.    rite tree is  deleted  from  the  forest.  pointers  to  the
  206.    leftmost  and  rightmost  (lmost and rmost, respectivly) are
  207.    updated in the process.  the frequency of the new  new  node
  208.    becomes the sum of the frequencies of its offspring.
  209.    *)
  210.    procedure combinelr;
  211.  
  212.       var newn : word; (* pointer to new node created *)
  213.  
  214.       begin
  215.       new(var newn);  (* get pointer to new node on heap *)
  216.       h[newn+char]:=sent;  (* init all internal nodes to sent char *)
  217.       h[newn+freq]:=h[left+freq]+h[rite+freq];
  218.  
  219.       (* link to left and right subtrees (offspring) *)
  220.       h[newn+lst]:=left;
  221.       h[newn+rst]:=rite;
  222.  
  223.       (* link new node into the forest in place of old left *)
  224.       (* first, make new node to point to its neighbors in the forest *)
  225.       h[newn+lforst ]:=h[left+lforst];
  226.       h[newn+rforst ]:=h[left+rforst];
  227.  
  228.       (* second, make neighbors point to new node *)
  229.       if (h[left+lforst]<>nil)
  230.          then h[h[left+lforst ]+rforst ]:=newn;
  231.       h[h[left+rforst ]+lforst ]:=newn;
  232.  
  233.       (* delete rite node *)
  234.       h[h[rite+lforst ]+rforst ]:=h[rite+rforst];
  235.       if (h[rite+rforst]<>nil)       (* rite has a right neighbor *)
  236.          then h[h[rite+rforst ]+lforst ]:=h[rite+lforst];
  237.  
  238.       (* update leftmost and rightmost pointers *)
  239.       if (lmost=left) then lmost:=newn;
  240.       if (rmost=rite) then rmost:=h[rite+lforst]
  241.       end; (* procedure combinelr *)
  242.  
  243.  
  244.    begin (* procedure build1tree *)
  245.    repeat
  246.       picklr;
  247.       combinelr;
  248.       put#1('.');      (* show progress on screen . . . *)
  249.    until (lmost=rmost) (* only one node left *)
  250.    end; (* procedure build1tree *)
  251.  
  252.  
  253. (*
  254. given the tree built in phase 1, traverse it (in order will do)
  255. and  assign  a level to each node.  then return to the original
  256. forest of trees (all leaves when we start), build them  into  a
  257. single tree using phase 3 of the hu-tucker algorithm.  the root
  258. of the resultant tree will be in lexfirst on exit.
  259.  
  260. the  algorithm  is  implemented  using two internal procedures.
  261. the first (picklr) chooses two trees for combination,  and  the
  262. second  (combinelr) combines the two chosen trees to form a new
  263. internal node in the  final  tree.  this  process  is  repeated
  264. unitl the forest contains only one tree.
  265.  
  266. the  procedure  used  is very similar to that used to build the
  267. tree in phase 1.
  268. *)
  269. procedure build3tree;
  270.  
  271.    var maxlev : word; (* largest level in tree *)
  272.        picklev: word; (* level of node now being picked *)
  273.        left : word;   (* left most node to be replaced *)
  274.  
  275.  
  276.    (*
  277.    setlev  will  traverse  the  tree  generated  in phase 1 and
  278.    assign levels to  each  of  the  nodes.  also,  the  deepest
  279.    level reached will be recorded in maxlev on exit.
  280.    *)
  281.    procedure setlev;
  282.  
  283.  
  284.       (*
  285.       traverse  a  node  of  a  tree  pointed  to  by the first
  286.       argument, assigning it the level  passed  in  the  second
  287.       argument.
  288.       *)
  289.       procedure travinord(p : word  ;  curlev : word);
  290.  
  291.          begin
  292.          if (p<>nil) then begin
  293.             if (curlev>maxlev) then maxlev:=curlev;
  294.             travinord(h[p+lst], curlev+1);
  295.             h[p+lev]:=curlev;
  296.             travinord(h[p+rst], curlev+1)
  297.             end
  298.          end; (* procedure travinord *)
  299.  
  300.  
  301.       begin  (* procedure setlev *)
  302.       maxlev:=0;
  303.       travinord(lmost, 0) (* root is leftmost node *)
  304.       end; (* procedure setlev *)
  305.  
  306.  
  307.    (*
  308.    pick  two  trees from the forest which satisfy the following
  309.    rules:
  310.  
  311.    let i and j be pointers to the left and right trees:
  312.  
  313.    i')   the  trees  i  and  j  must be adjacent in the working
  314.          sequence.
  315.  
  316.    ii')  the  levels  of  trees  i  and j must be maximal among
  317.          all remaining levels.
  318.  
  319.    iii') the  index  i  is  minimal  for all i and j satisfying
  320.          rules (i'), (ii').
  321.  
  322.    a pointer to the left most chosen will be left in left.  the
  323.    right tree chosen is its lexicographic successor.
  324.    *)
  325.    procedure picklr;
  326.  
  327.       var picked  : boolean; (* true if one picked on this lev el *)
  328.       begin
  329.       picked:=false;
  330.       while (picked=false) do begin
  331.          left:=lexfirst; (* start with first node in lexicographic order *)
  332.          while (left<>nil) and (picked<>true) do
  333.             if (h[left+lev]=picklev)
  334.                 then picked:=true
  335.                 else left:=h[left+lexs];
  336.          if (picked=false) then picklev:=picklev-1
  337.          end (* while *)
  338.       end; (* procedure picklr *)
  339.  
  340.  
  341.    (*
  342.    combine  the  tree  pointed to by left and its lexicographic
  343.    successor to form a new internal node  in  the  final  tree.
  344.    link  this new node into the existing lexicographic sequence
  345.    in place of the left tree and its successor.  the pointer to
  346.    the first node in the sequence (lexfirst), is updated in the
  347.    process.
  348.    *)
  349.    procedure combinelr;
  350.  
  351.       var newn : word; (* pointer to new node created *)
  352.           rite : word; (* pointer to right node being combined *)
  353.  
  354.       begin
  355.       new(var newn);
  356.       rite:=h[left+lexs]; (* right node is allways next in lex order *)
  357.       h[newn+char]:=sent; (* init all internal nodes to sent char *)
  358.  
  359.       (* link left and right subtrees to new node *)
  360.       h[newn+lst]:=left;
  361.       h[newn+rst]:=rite;
  362.  
  363.       (* level of new node is one less than level of its offspring *)
  364.       h[newn+lev]:=h[left+lev]-1;
  365.       h[newn+lexs]:=h[rite+lexs];
  366.       h[newn+lexp]:=h[left+lexp];
  367.  
  368.       (* link new node in place of left node from left *)
  369.       if (h[left+lexp]<>nil) then (* left has a lex predecessor *)
  370.          h[h[left+lexp]+lexs]:=newn;
  371.       if (h[rite+lexs]<>nil) then (* right has a lex successor *)
  372.          h[h[rite+lexs]+lexp]:=newn;
  373.  
  374.       if (left=lexfirst) then (* new node becomes lex first *)
  375.          lexfirst:=newn
  376.       end; (* procedure combinelr *)
  377.  
  378.  
  379.    begin (* procedure build3tree *)
  380.    setlev; (* compute node levels *)
  381.    put#1(13,10);
  382.    put#1('maxlev =',maxlev#,13,10);
  383.    picklev:=maxlev;
  384.    repeat
  385.       picklr;
  386.       combinelr;
  387.       put#1('.')      (* show progress on screen . . . *)
  388.    until (picklev<=1) (* true when all nodes have been picked *)
  389.    end; (* procedure build3tree *)
  390.  
  391.  
  392. (*
  393. decode  a  sequence of 1's an 0's read from the standard input
  394. file into a sequence of characters written to standard output.
  395. this is done by starting at the root and taking a left  when a
  396. zero  is  read, a right when a one is read.  this is continued
  397. unitl a leaf is reached, when the character in  that  leaf  is
  398. printed.  this process is repeated until end-of-file is found.
  399. *)
  400. procedure decode;
  401.  
  402.    var eof : boolean;
  403.        ch  : word;   (* last one or zero read from input *)
  404.        p   : word;   (* pointer used to traverse tree *)
  405.  
  406.  
  407.    procedure getoz;
  408.  
  409.       begin
  410.       get#0(ch);
  411.       while (ch=13) or (ch=10) or (ch=' ') do
  412.          get#0(ch);
  413.       if (ch=26) then eof:=true
  414.       end; (* procedure getoz *)
  415.  
  416.  
  417.    begin (* prodecure decode *)
  418.    put#1(13,10);
  419.    put#1('decoded ', 'message  ',13,10);
  420.    eof:=false;
  421.    getoz;
  422.    while (eof=false) do begin
  423.       p:=lexfirst;      (* start at root of phase 3 tree *)
  424.       while (h[p+char]=sent) do begin (* while at internal node *)
  425.          if (ch='0')
  426.             then p:=h[p+lst]  (* left  turn *)
  427.             else p:=h[p+rst]; (* right turn *)
  428.          getoz
  429.          end; (* while at internal node *)
  430.       put#1(h[p+char])
  431.       end (* while not eof *)
  432.    end; (* procedure decode *)
  433.  
  434. begin (* main line *)
  435.    hp:=0; (* initialize heap pointer *)
  436.    readtree;
  437.    lexfirst:=lmost; (* first node in lex order is leftmost *)
  438.    build1tree;
  439.    build3tree;
  440.    decode
  441. end.
  442.