book_components.w
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:23k
源码类别:

通讯编程

开发平台:

Visual C++

  1. % This file is part of the Stanford GraphBase (c) Stanford University 1993
  2. @i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
  3. @i gb_types.w
  4. deftitle{BOOK_kern.05emCOMPONENTS}
  5. def<#1>{$langle${rm#1}$rangle$}
  6. prerequisite{GB_,BOOKS}
  7. @* Bicomponents. This demonstration program computes the
  8. biconnected components of GraphBase graphs derived from world literature,
  9. using a variant of Hopcroft and Tarjan's algorithm [R. E. Tarjan, ``Depth-first
  10. @^Hopcroft, John Edward@>
  11. @^Tarjan, Robert Endre@>
  12. search and linear graph algorithms,'' {sl SIAM Journal on Computing/
  13. bf1} (1972), 146--160]. Articulation points and ordinary (connected)
  14. components are also obtained as byproducts of the computation.
  15. Two edges belong to the same  biconnected component---or ``bicomponent''
  16. for short---if and only if they are identical or both belong to a
  17. simple cycle. This defines an equivalence relation on edges.
  18. The bicomponents of a connected graph form a
  19. free tree, if we say that two bicomponents are adjacent when they have
  20. a common vertex (i.e., when there is a vertex belonging to at least one edge
  21. in each of the bicomponents). Such a vertex is called an {sl articulation
  22. point/}; there is a unique articulation point between any two adjacent
  23. bicomponents. If we choose one bicomponent to be the ``root'' of the
  24. free tree, the other bicomponents can be represented conveniently as
  25. lists of vertices, with the articulation point that leads toward the root
  26. listed last. This program displays the bicomponents in exactly that way.
  27. @ We permit command-line options in typical UNIX/ style so that a variety of
  28. graphs can be studied: The user can say `.{-t}<title>',
  29. `.{-n}<number>', `.{-x}<number>', `.{-f}<number>',
  30. `.{-l}<number>', `.{-i}<number>', `.{-o}<number>', and/or
  31. `.{-s}<number>' to change the default values of the parameters in
  32. the graph generated by |book(t,n,x,f,l,i,o,s)|.
  33. When the bicomponents are listed, each character in the book is identified by
  34. a two-letter code, as found in the associated data file.
  35. An explanation of these codes will appear first if the .{-v} or .{-V} option
  36. is specified. The .{-V} option prints a fuller explanation than~.{-v}; it
  37. also shows each character's weighted number of appearances.
  38. The special command-line option .{-g}$langle,$filename$,rangle$
  39. overrides all others. It substitutes an external graph previously saved by
  40. |save_graph| for the graphs produced by |book|. 
  41. @^UNIX dependencies@>
  42. @p
  43. #include "gb_graph.h" /* the GraphBase data structures */
  44. #include "gb_books.h" /* the |book| routine */
  45. #include "gb_io.h" /* the |imap_chr| routine */
  46. #include "gb_save.h" /* |restore_graph| */
  47. @h@#
  48. @<Global variables@>@;
  49. @<Subroutines@>@;
  50. main(argc,argv)
  51.   int argc; /* the number of command-line arguments */
  52.   char *argv[]; /* an array of strings containing those arguments */
  53. {@+Graph *g; /* the graph we will work on */
  54.   register Vertex *v; /* the current vertex of interest */
  55.   char *t="anna"; /* the book to use */
  56.   unsigned long n=0; /* the desired number of vertices (0 means infinity) */
  57.   unsigned long x=0; /* the number of major characters to exclude */
  58.   unsigned long f=0; /* the first chapter to include */
  59.   unsigned long l=0; /* the last chapter to include (0 means infinity) */
  60.   long i=1; /* the weight for appearances in selected chapters */
  61.   long o=1; /* the weight for appearances in unselected chapters */
  62.   long s=0; /* the random number seed */
  63.   @<Scan the command-line options@>;
  64.   if (filename) g=restore_graph(filename);
  65.   else g=book(t,n,x,f,l,i,o,s);
  66.   if (g==NULL) {
  67.     fprintf(stderr,"Sorry, can't create the graph! (error code %ld)n",
  68.              panic_code);
  69.     return -1;
  70.   }
  71.   printf("Biconnectivity analysis of %snn",g->id);
  72.   if (verbose) @<Print the cast of selected characters@>;
  73.   @<Perform the Hopcroft-Tarjan algorithm on |g|@>;
  74.   return 0; /* normal exit */
  75. }
  76. @ @<Scan the command-line options@>=
  77. while (--argc) {
  78. @^UNIX dependencies@>
  79.   if (strncmp(argv[argc],"-t",2)==0) t=argv[argc]+2;
  80.   else if (sscanf(argv[argc],"-n%lu",&n)==1) ;
  81.   else if (sscanf(argv[argc],"-x%lu",&x)==1) ;
  82.   else if (sscanf(argv[argc],"-f%lu",&f)==1) ;
  83.   else if (sscanf(argv[argc],"-l%lu",&l)==1) ;
  84.   else if (sscanf(argv[argc],"-i%ld",&i)==1) ;
  85.   else if (sscanf(argv[argc],"-o%ld",&o)==1) ;
  86.   else if (sscanf(argv[argc],"-s%ld",&s)==1) ;
  87.   else if (strcmp(argv[argc],"-v")==0) verbose=1;
  88.   else if (strcmp(argv[argc],"-V")==0) verbose=2;
  89.   else if (strncmp(argv[argc],"-g",2)==0) filename=argv[argc]+2;
  90.   else {
  91.     fprintf(stderr,
  92.          "Usage: %s [-ttitle][-nN][-xN][-fN][-lN][-iN][-oN][-sN][-v][-gfoo]n",
  93.          argv[0]);
  94.     return -2;
  95.   }
  96. }
  97. if (filename) verbose=0;
  98. @ @<Subroutines@>=
  99. char *filename=NULL; /* external graph to be restored */
  100. char code_name[3][3];
  101. char *vertex_name(v,i) /* return (as a string) the name of vertex |v| */
  102.   Vertex *v;
  103.   char i; /* |i| should be 0, 1, or 2 to avoid clash in |code_name| array */
  104. {
  105.   if (filename) return v->name; /* not a |book| graph */
  106.   code_name[i][0]=imap_chr(v->short_code/36);
  107.   code_name[i][1]=imap_chr(v->short_code%36);
  108.   return code_name[i];
  109. }
  110. @ @<Print the cast of selected characters@>=
  111. {
  112.   for (v=g->vertices;v<g->vertices+g->n;v++) {
  113.     if (verbose==1) printf("%s=%sn",vertex_name(v,0),v->name);
  114.     else printf("%s=%s, %s [weight %ld]n",vertex_name(v,0),v->name,v->desc,@|
  115.      i*v->in_count+o*v->out_count);
  116.   }
  117.   printf("n");
  118. }
  119. @*The algorithm.
  120. The Hopcroft-Tarjan algorithm is inherently recursive. We will
  121. implement the recursion explicitly via linked lists, instead of using
  122. CEE/'s runtime stack, because some computer systems bog down in the
  123. presence of deeply nested recursion.
  124. Each vertex goes through three stages during the algorithm. First it is
  125. ``unseen''; then it is ``active''; finally it becomes ``settled,'' when it
  126. has been assigned to a bicomponent.
  127. The data structures that represent the current state of the algorithm
  128. are implemented by using five of the utility fields in each vertex:
  129. |rank|, |parent|, |untagged|, |link|, and |min|. We will consider each of
  130. these in turn.
  131. @ First is the integer |rank| field, which is zero when a vertex is unseen.
  132. As soon as the vertex is first examined, it becomes active and its |rank|
  133. becomes and remains nonzero. Indeed, the $k$th vertex to become active
  134. will receive rank~$k$.
  135. It's convenient to think of the Hopcroft-Tarjan algorithm as a simple adventure
  136. game in which we want to explore all the rooms of a cave. Passageways between
  137. the rooms allow two-way travel. When we come
  138. into a room for the first time, we assign a new number to that room;
  139. this is its rank. Later on we might happen to come into the same room
  140. again, and we will notice that it has nonzero rank. Then we'll be able
  141. to make a quick exit, saying ``we've already been here.'' (The extra
  142. complexities of computer games, like dragons that might need to be
  143. vanquished, do not arise.)
  144. @d rank z.I /* the |rank| of a vertex is stored in utility field |z| */
  145. @<Glob...@>=
  146. long nn; /* the number of vertices that have been seen */
  147. @ The active vertices will always form an oriented tree, whose arcs are
  148. a subset of the arcs in the original graph. A tree arc from |u| to~|v|
  149. will be represented by |v->parent==u|. Every active vertex has a
  150. parent, which is usually another active vertex; the only exception is
  151. the root of the tree, whose |parent| is a dummy vertex called |dummy|.
  152. The dummy vertex has rank zero.
  153. In the cave analogy, the ``parent'' of room |v| is the room we were in
  154. immediately before entering |v| the first time. By following parent
  155. pointers, we will be able to leave the cave whenever we want.
  156. @d parent y.V /* the |parent| of a vertex is stored in utility field |y| */
  157. @<Glob...@>=
  158. Vertex dummy; /* imaginary parent of the root vertex */
  159. @ All edges in the original undirected graph are explored systematically during
  160. a depth-first search. Whenever we look at an edge, we tag it so that
  161. we won't need to explore it again. In a cave, for example, we might
  162. mark each passageway between rooms once we've tried to go through~it.
  163. In a GraphBase graph, undirected edges are represented as a pair of directed
  164. arcs. Each of these arcs will be examined and eventually tagged.
  165. The algorithm doesn't actually place a tag on its |Arc| records; instead,
  166. each vertex |v| has a pointer |v->untagged| that leads to all
  167. hitherto-unexplored arcs from~|v|. The arcs of the list that appear
  168. between |v->arcs| and |v->untagged| are the ones already examined.
  169. @d untagged x.A
  170.  /* the |untagged| field points to an |Arc| record, or |NULL| */ 
  171. @ The algorithm maintains a special stack, the |active_stack|, which contains
  172. all the currently active vertices. Each vertex has a |link| field that points
  173. to the vertex that is next lower on its stack, or to |NULL| if the vertex is
  174. at the bottom. The vertices on |active_stack| always appear in increasing
  175. order of rank from bottom to top.
  176. @d link w.V /* the |link| field of a vertex occupies utility field |w| */
  177. @<Glob...@>=
  178. Vertex * active_stack; /* the top of the stack of active vertices */
  179. @ Finally there's a |min| field, which is the tricky part that makes
  180. everything work. If vertex~|v| is unseen or settled, its |min| field is
  181. irrelevant. Otherwise |v->min| points to the active vertex~|u|
  182. of smallest rank having the following property:
  183. There is a directed path from |v| to |u| consisting of
  184. zero or more mature tree arcs followed by a single non-tree arc.
  185. What is a tree arc, you ask. And what is a mature arc? Good questions. At the
  186. moment when arcs of the graph are tagged, we classify them either as tree
  187. arcs (if they correspond to a new |parent| link in the tree of active
  188. nodes) or non-tree arcs (otherwise). The tree arcs therefore correspond to
  189. passageways that have led us to new territory. A tree arc becomes mature
  190. when it is no longer on the path from the root to the current vertex being
  191. explored. We also say that a vertex becomes mature when it is
  192. no longer on that path. All arcs from a mature vertex have been tagged.
  193. We said before that every vertex is initially unseen, then active, and
  194. finally settled. With our new definitions, we see further that every arc starts
  195. out untagged, then it becomes either a non-tree arc or a tree arc. In the
  196. latter case, the arc begins as an immature tree arc and eventually matures.
  197. The dummy vertex is considered to be active, and we assume that
  198. there is a non-tree arc from the root vertex back to |dummy|. Thus
  199. there is a non-tree arc from |v| to |v->parent| for all~|v|, and |v->min|
  200. will always point to a vertex whose rank is less than or equal to
  201. |v->parent->rank|. It will turn out that |v->min| is always an ancestor
  202. of~|v|.
  203. Just believe these definitions, for now. All will become clear soon.
  204. @d min v.V /* the |min| field of a vertex occupies utility field |v| */
  205. @ Depth-first search explores a graph by systematically visiting all
  206. vertices and seeing what they can lead to. In the Hopcroft-Tarjan algorithm, as
  207. we have said, the active vertices form an oriented tree. One of these
  208. vertices is called the current vertex.
  209. If the current vertex still has an arc that hasn't been tagged, we
  210. tag one such arc and there are two cases: Either the arc leads to
  211. an unseen vertex, or it doesn't. If it does, the arc becomes a tree
  212. arc; the previously unseen vertex becomes active, and it becomes the
  213. new current vertex.  On the other hand if the arc leads to a vertex
  214. that has already been seen, the arc becomes a non-tree arc and the
  215. current vertex doesn't change.
  216. Finally there will come a time when the current vertex~|v| has no
  217. untagged arcs. At this point, the
  218. algorithm might decide that |v| and all its descendants
  219. form a bicomponent, together with |v->parent|.
  220.  Indeed, this condition turns out to be true if and only if
  221. |v->min==v->parent|; a proof appears below. If so, |v| and all its descendants
  222. become settled, and they leave the tree. If not, the tree arc from
  223. |v|'s parent~|u| to~|v| becomes mature, so the value of |v->min| is
  224. used to update the value of |u->min|. In both cases, |v| becomes mature
  225. and the new current vertex will be the parent of~|v|. Notice that only the
  226. value of |u->min| needs to be updated, when the arc from |u| to~|v|
  227. matures; all other values |w->min| stay the same, because a newly
  228. mature arc has no mature predecessors.
  229. The cave analogy helps to clarify the situation: Suppose we enter
  230. room~|v| from room~|u|. If there's no way out of the subcave starting
  231. at~|v| unless we come back through~|u|, and if we can get to~|u| from
  232. all of |v|'s descendants without passing through~|v|, then room~|v|
  233. and its descendants will become a bicomponent together with~|u|.  Once
  234. such a bicomponent is identified, we close it off and don't explore
  235. that subcave any further.
  236. If |v| is the root of the tree, it always has |v->min==dummy|, so it
  237. will always define a new bicomponent at the moment it matures.  Then
  238. the depth-first search will terminate, since |v|~has no real parent.
  239. But the Hopcroft-Tarjan algorithm will press on, trying to find a
  240. vertex~|u| that is still unseen. If such a vertex exists, a
  241. new depth-first search will begin with |u| as the root. This process
  242. keeps on going until at last all vertices are happily settled.
  243. The beauty of this algorithm is that it all works very efficiently
  244. when we organize it as follows:
  245. @<Perform the Hopcroft-Tarjan algorithm on |g|@>=
  246. @<Make all vertices unseen and all arcs untagged@>;
  247. for (vv=g->vertices; vv<g->vertices+g->n; vv++)
  248.   if (vv->rank==0) /* |vv| is still unseen */
  249.     @<Perform a depth-first search with |vv| as the root, finding the
  250.       bicomponents of all unseen vertices reachable from~|vv|@>;
  251. @ @<Glob...@>=
  252. Vertex *vv; /* sweeps over all vertices, making sure none is left unseen */
  253. @ It's easy to get the data structures started, according to the
  254. conventions stipulated above.
  255. @<Make all vertices unseen...@>=
  256. for (v=g->vertices; v<g->vertices+g->n; v++) {
  257.   v->rank=0;
  258.   v->untagged=v->arcs;
  259. }
  260. nn=0;
  261. active_stack=NULL;
  262. dummy.rank=0;
  263. @ The task of starting a depth-first search isn't too bad either. Throughout
  264. this part of the algorithm, variable~|v| will point to the current vertex.
  265. @<Perform a depth-first search with |vv| as the root...@>=
  266. {
  267.   v=vv;
  268.   v->parent=&dummy;
  269.   @<Make vertex |v| active@>;
  270.   do @<Explore one step from the current vertex~|v|, possibly moving
  271.         to another current vertex and calling~it~|v|@>@;
  272.   while (v!=&dummy);
  273. }
  274. @ @<Make vertex |v| active@>=
  275. v->rank=++nn;
  276. v->link=active_stack;
  277. active_stack=v;
  278. v->min=v->parent;
  279. @ Now things get interesting. But we're just doing what any well-organized
  280. spelunker would do when calmly exploring a cave.
  281. There are three main cases,
  282. depending on whether the current vertex stays where it is, moves
  283. to a new child, or backtracks to a parent.
  284. @<Explore one step from the current vertex~|v|, possibly moving
  285.         to another current vertex and calling~it~|v|@>=
  286. {@+register Vertex *u; /* a vertex adjacent to |v| */
  287.   register Arc *a=v->untagged; /* |v|'s first remaining untagged arc, if any */
  288.   if (a) {
  289.     u=a->tip;
  290.     v->untagged = a->next; /* tag the arc from |v| to |u| */
  291.     if (u->rank) { /* we've seen |u| already */
  292.       if (u->rank < v->min->rank)
  293.         v->min=u; /* non-tree arc, just update |v->min| */
  294.     }@+else { /* |u| is presently unseen */
  295.       u->parent = v; /* the arc from |v| to |u| is a new tree arc */
  296.       v = u; /* |u| will now be the current vertex */
  297.       @<Make vertex |v| active@>;
  298.     }
  299.   }@+else { /* all arcs from |v| are tagged, so |v| matures */
  300.     u=v->parent; /* prepare to backtrack in the tree */
  301.     if (v->min==u) @<Remove |v| and all its successors on the active stack
  302.          from the tree, and report them as a bicomponent of the graph
  303.          together with~|u|@>@;
  304.     else  /* the arc from |u| to |v| has just matured,
  305.              making |v->min| visible from |u| */@,
  306.       if (v->min->rank < u->min->rank)
  307.         u->min=v->min;
  308.     v=u; /* the former parent of |v| is the new current vertex |v| */
  309.   }
  310. }
  311. @ The elements of the active stack are always in order by rank, and
  312. all children of a vertex~|v| in the tree have rank higher than~|v|.
  313. The Hopcroft-Tarjan algorithm relies on a converse property:
  314. {sl All active nodes whose rank exceeds that of the current vertex~|v|
  315. are descendants of~|v|.} (This property holds because the algorithm has
  316. constructed the tree by assigning ranks in preorder, ``the order of
  317. succession to the throne.'' First come |v|'s firstborn and descendants,
  318. then the nextborn, and so on.) Therefore the descendants of the
  319. current vertex always appear consecutively at the top of the stack.
  320. Suppose |v| is a mature, active vertex with |v->min==v->parent|, and
  321. let |u=v->parent|. We want to prove that |v| and its descendants,
  322. together with~|u| and all edges between these vertices, form a
  323. biconnected graph.  Call this subgraph~$H$. The parent links
  324. define a subtree of~$H$, rooted at~|u|, and |v| is the only vertex
  325. having |u| as a parent (because all other vertices are descendants
  326. of~|v|). Let |x| be any vertex of~$H$ different from |u| and |v|.
  327. Then there is a path from |x| to |x->min| that does not touch~|x->parent|,
  328. and |x->min| is a proper ancestor of |x->parent|. This property
  329. is sufficient to establish the biconnectedness of~$H$. (A proof appears
  330. at the conclusion of this program.) Moreover, we cannot add any
  331. more vertices to~$H$ without losing biconnectivity. If |w|~is another
  332. vertex, either |w| has been output already as a non-articulation point
  333. of a previous biconnected component, or we can prove that
  334. there is no path from |w| to~|v| that avoids the vertex~|u|.
  335. @ Therefore we are justified in settling |v| and its active descendants now.
  336. Removing them from the tree of active vertices does not remove any
  337. vertex from which there is a path to a vertex of rank less than |u->rank|.
  338. Hence their removal does not affect the validity of the |w->min| value
  339. for any vertex~|w| that remains active.
  340. A slight technicality arises with respect to whether or not
  341. the parent of~|v|, vertex~|u|, is part of the present bicomponent.
  342. When |u| is the dummy vertex, we have already printed the final bicomponent
  343. of a connected component of the original graph, unless |v| was
  344. an isolated vertex. Otherwise |u| is an
  345. articulation point that will occur in subsequent bicomponents,
  346. unless the new bicomponent is the final bicomponent of a connected component.
  347. (This aspect of the algorithm is probably its most subtle point;
  348. consideration of an example or two should clarify everything.)
  349. We print out enough information for a reader to verify the
  350. biconnectedness of the claimed component easily.
  351. @<Remove |v| and all its successors on the active stack...@>=
  352. if (u==&dummy) { /* |active_stack| contains just |v| */
  353.   if (artic_pt)
  354.     printf(" and %s (this ends a connected component of the graph)n",
  355.               vertex_name(artic_pt,0));
  356.   else printf("Isolated vertex %sn",vertex_name(v,0));
  357.   active_stack=artic_pt=NULL;
  358. }@+else {@+register Vertex *t; /* runs through the vertices of the
  359.                         new bicomponent */
  360.   if (artic_pt)
  361.     printf(" and articulation point %sn",vertex_name(artic_pt,0));
  362.   t=active_stack;
  363.   active_stack=v->link;
  364.   printf("Bicomponent %s", vertex_name(v,0));
  365.   if (t==v) putchar('n'); /* single vertex */
  366.   else {
  367.     printf(" also includes:n");
  368.     while (t!=v) {
  369.       printf(" %s (from %s; ..to %s)n",
  370.         vertex_name(t,0), vertex_name(t->parent,1),vertex_name(t->min,2));
  371.       t=t->link;
  372.     }
  373.   }
  374.   artic_pt=u; /* the printout will be finished later */
  375. }
  376. @ Like all global variables, |artic_pt| is initially zero (|NULL|).
  377. @<Glob...@>=
  378. Vertex *artic_pt; /* articulation point to be printed if the current
  379.   bicomponent isn't the last in its connected component */
  380. @*Proofs.
  381. The program is done, but we still should prove that it works.
  382. First we want to clarify the informal definition by verifying that
  383. the cycle relation between edges, as stated in the introduction, is indeed an
  384. equivalence relation.
  385. defdash{mathrel-joinreljoinrelmathrel-}
  386. Suppose $udash v$ and $wdash x$ are edges of a simple cycle~$C$, while
  387. $wdash x$ and $ydash z$ are edges of a simple cycle~$D$. We want to show
  388. that there is a simple cycle containing the edges $udash v$ and $ydash z$.
  389. There are vertices $a,bin C$ such that $adash^ast ydash zdash^ast b$
  390. is a subpath of~$D$ containing no other vertices of $C$ besides $a$ and~$b$.
  391. Join this subpath to the subpath in $C$ that runs from $b$ to~$a$ through
  392. the edge $udash v$.
  393. Therefore the stated relation between edges is transitive, and it is
  394. an equivalence relation.
  395. A graph is biconnected if it contains a single vertex, or if each of
  396. its vertices is adjacent to at least one other vertex and any two edges are
  397. equivalent.
  398. @ Next we prove the well-known fact that a graph is biconnected if and
  399. only if it is connected and, for any three distinct vertices $x$,
  400. $y$,~$z$, it contains a path from $x$ to~$y$ that does not touch~$z$.
  401. Call the latter condition property~P.
  402. Suppose $G$ is biconnected, and let $x,y$ be distinct vertices of~$G$.
  403. Then there exist edges $udash x$ and $vdash y$, which are either
  404. identical (hence $x$ and~$y$ are adjacent) or part of a simple cycle
  405. (hence there are two paths from $x$ to~$y$, having no other vertices in
  406. common). Thus $G$ has property~P.
  407. Suppose, conversely, that $G$ has property~P, and let $udash v,
  408. wdash x$ be distinct edges of~$G$. We want to show that these edges
  409. belong to some simple cycle. The proof is by induction on
  410. $k=minbigl(d(u,w),d(u,x),allowbreak d(v,w),d(v,x)bigr)$, where $d$~denotes
  411. distance. If $k=0$, property~P gives the result directly. If $k>0$,
  412. we can assume by symmetry that $k=d(u,w)$; so there's a vertex $y$
  413. with $udash y$ and $d(y,w)=k-1$. And we have $udash v$ equivalent to
  414. $udash y$ by property~P, $udash y$ equivalent to $wdash x$ by induction,
  415. hence $udash v$ is equivalent to $wdash x$ by transitivity.
  416. @ Finally, we prove that $G$ satisfies property~P if it has the
  417. following properties: (1)~There are two distinguished vertices $u$
  418. and~$v$.  (2)~Some of the edges of~$G$ form a subtree rooted at~$u$,
  419. and $v$ is the only vertex whose parent in this tree is~$u$.
  420. (3)~Every vertex~$x$ other than $u$ or $v$ has a path to its
  421. grandparent that does not go through its parent.
  422. If property P doesn't hold, there are distinct vertices $x,y,z$ such
  423. that every path from $x$ to~$y$ goes through~$z$. In particular, $z$ must be
  424. between $x$ and~$y$ in the unique path~$pi$ that joins them in the subtree.
  425. It follows that $zne u$ is the parent of some node $z'$ in that path; hence
  426. $z'ne u$ and $z'ne v$. But we can
  427. avoid $z$ by going from $z'$ to the grandparent of $z'$, which is
  428. also part of path~$pi$ unless $z$ is also the parent of another node
  429. $z''$ in~$pi$. In the latter case, however,
  430. we can avoid $z$ by going from $z'$ to the grandparent of $z'$ and from there
  431. to $z''$, since $z'$ and $z''$ have the same grandparent.
  432. @* Index. We close with a list that shows where the identifiers of this
  433. program are defined and used.