home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / alt / sources / 3075 < prev    next >
Encoding:
Text File  |  1993-01-23  |  26.7 KB  |  1,129 lines

  1. Newsgroups: alt.sources
  2. Path: sparky!uunet!cs.utexas.edu!qt.cs.utexas.edu!yale.edu!yale!gumby!destroyer!lambda.msfc.nasa.gov!decwrl!pa.dec.com!vix.com!vixie
  3. From: vixie@vix.com (Paul A Vixie)
  4. Message-ID: <9301230555.AA23768@gw.home.vix.com>
  5. Subject: new AVL library
  6. Date: Fri, 22 Jan 93 21:55:08 -0800
  7. X-Received: by usenet.pa.dec.com; id AA27287; Fri, 22 Jan 93 21:55:17 -0800
  8. X-Received: by inet-gw-2.pa.dec.com; id AA25762; Fri, 22 Jan 93 21:55:10 -0800
  9. X-Received: by gw.home.vix.com; id AA23768; Fri, 22 Jan 93 21:55:09 -0800
  10. X-Btw: vix.com is also gw.home.vix.com and vixie.sf.ca.us
  11. X-To: alt.sources.usenet@usenet.pa.dec.com
  12. X-Mts: smtp
  13. Lines: 1114
  14.  
  15. before i put this into the comp.sources.unix queue, i'd like to
  16. give people a chance to hack on the updated version.  the original
  17. had a bug in delete; this one shouldn't, but i've lost my test case
  18. so i really don't know.
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of shell archive."
  27. # Contents:  README Makefile t_trtest.c tree.c tree.h tree.man3 vixie.h
  28. # Wrapped by vixie@gw.home.vix.com on Fri Jan 22 14:03:34 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'README' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'README'\"
  32. else
  33. echo shar: Extracting \"'README'\" \(2468 characters\)
  34. sed "s/^X//" >'README' <<'END_OF_FILE'
  35. AVL Trees V2.0
  36. X22-Janulary-1993
  37. Paul Vixie
  38. X
  39. There was a small bug in tree_delete() that manifested itself by corrupting
  40. trees occasionally.  It didn't show up in 1987 because I was using a micro-
  41. computer whose malloc() wasn't all that picky; on newer UNIX systems, malloc()
  42. and free() are extremely picky and if you misuse them, they will abuse you.
  43. X
  44. I've taken the opportunity to convert the code to ANSI and POSIX.  If you
  45. don't have <stdlib.h> you will have some small porting work to do; most newer
  46. systems have this (BSDI, SYSV, Ultrix, OSF/1, OpenVMS, and so on) so you will
  47. X(statistically speaking) not have too much of a problem with the changes.  I
  48. conditionalized the ANSI'isms (function prototypes), so if you don't have a
  49. fully ANSI compiler you should still be able to get this code to compile.
  50. The one interface change I made was to change the external definition of the
  51. tree from "int *" to "void *"; had "void *" existed in 1987 I would have used
  52. it then.  I changed the delete_uar from "pointer to function returning int"
  53. to "pointer to function returning void"; I don't know why I used "int" back
  54. in 1987, those functions have never returned anything.
  55. X
  56. X--------
  57. X
  58. AVL Trees V1.0
  59. X24-July-1987
  60. Paul Vixie
  61. X
  62. This library and test program are useful for creating and using balanced
  63. binary trees (AVL trees).  The tree is held in memory, using malloc(3) to
  64. allocate storage.  A better version would allow file-based trees in 
  65. addition; once memory mapped files hit the UNIX(tm) community, this will
  66. be much easier to do.  In the meanwhile, these routines have been very
  67. useful to me for symbol tables and the like.  (Yes, I'm sure hashing is
  68. better in some way, but I've used this for symbol tables, just the same.)
  69. X
  70. I cannot take credit for the algorithms.  See "Algorithms & Data Structures,"
  71. Niklaus Wirth, Prentice-Hall 1986, ISBN 0-13-022005-1.  This is an update of
  72. Wirth's previous book, titled "Algorythms + Data Structures = Programs,"
  73. which used Pascal as the language for examples.  This later book uses the
  74. newer Modula-2 for it's examples; this tree code was created using the
  75. Modula-2 examples as guidelines.  At the time I typed this stuff in (about
  76. a year ago, in July 1987), I understood how it all worked.  Today, well...
  77. X
  78. This code is hereby placed in the public domain, unless restrictions apply
  79. from Prentice-Hall on the algorithms themselves.  If you use or redistribute
  80. this code, please leave my name (and Wirth's) in the comments.
  81. END_OF_FILE
  82. if test 2468 -ne `wc -c <'README'`; then
  83.     echo shar: \"'README'\" unpacked with wrong size!
  84. fi
  85. # end of 'README'
  86. fi
  87. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  88.   echo shar: Will not clobber existing file \"'Makefile'\"
  89. else
  90. echo shar: Extracting \"'Makefile'\" \(593 characters\)
  91. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  92. X# makefile for tree stuff
  93. X# vix 24jul87 [stripped down from as makefile]
  94. X# vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
  95. X#
  96. X# $Id:$
  97. X
  98. X#(choose a c compiler)
  99. CC        =    gcc -Wall -Wtraditional -Wshadow -Wpointer-arith \
  100. X            -Wcast-align -Wwrite-strings -pedantic
  101. X#CC        =    cc
  102. X
  103. CDEBUG        =    -g
  104. CFLAGS        =    $(CDEBUG) $(CCFLAGS)
  105. LDFLAGS        =    $(CDEBUG)
  106. X
  107. TRTEST_OBJ    =    t_trtest.o tree.o
  108. X
  109. all        :    t_trtest
  110. X
  111. t_trtest    :    $(TRTEST_OBJ)
  112. X            $(CC) -o t_trtest $(TRTEST_OBJ)
  113. X
  114. clean        :    FRC
  115. X            rm -f core a.out t_trtest $(TRTEST_OBJ)
  116. X
  117. XFRC        :
  118. X
  119. tree.o        :    tree.c tree.h vixie.h
  120. t_trtest.o    :    t_trtest.c tree.h vixie.h
  121. END_OF_FILE
  122. if test 593 -ne `wc -c <'Makefile'`; then
  123.     echo shar: \"'Makefile'\" unpacked with wrong size!
  124. fi
  125. # end of 'Makefile'
  126. fi
  127. if test -f 't_trtest.c' -a "${1}" != "-c" ; then 
  128.   echo shar: Will not clobber existing file \"'t_trtest.c'\"
  129. else
  130. echo shar: Extracting \"'t_trtest.c'\" \(2322 characters\)
  131. sed "s/^X//" >'t_trtest.c' <<'END_OF_FILE'
  132. X/* t_trtest - test the tree functions
  133. X * vix 24jul87 [documented, added savestr for net distribution]
  134. X * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
  135. X */
  136. X
  137. X#ifndef LINT
  138. static char RCSid[] = "$Id:";
  139. X#endif
  140. X
  141. X#define MAIN
  142. X
  143. X#include <stdio.h>
  144. X#include <strings.h>
  145. X#include <stdlib.h>
  146. X#include "vixie.h"
  147. X#include "tree.h"
  148. X
  149. X
  150. X#ifdef __STDC__
  151. X#define __P(x) x
  152. X#else
  153. X#define    __P(x) ()
  154. X#endif
  155. X
  156. static void    trtest        __P( (tree **, char *, int) );
  157. static void    tree_trav1    __P( (tree *, int) );
  158. static int    compar        __P( (char *, char *) );
  159. static void    duar        __P( (char *) );
  160. static char    *savestr    __P( (char *) );
  161. X
  162. X#undef __P
  163. X
  164. X
  165. int
  166. main()
  167. X{
  168. X    tree    *t;
  169. X    char    line[100];
  170. X
  171. X    tree_init(&t);
  172. X    while (printf("key (or .):  "), gets(line), line[0] != '.')
  173. X    {
  174. X        if (strncmp(line, "~r ", 3)) {
  175. X            trtest(&t, line, 1);
  176. X        }
  177. X        else {
  178. X            FILE *f;
  179. X
  180. X            if (!(f = fopen(&line[3], "r")))
  181. X                perror(&line[3]);
  182. X            else {
  183. X                while (fgets(line, 100, f)) {
  184. X                    line[strlen(line)-1] = '\0';
  185. X                    printf("(%s)\n", line);
  186. X                    trtest(&t, line, 0);
  187. X                }
  188. X                fclose(f);
  189. X            }
  190. X        }
  191. X    }
  192. X    return 0;
  193. X}
  194. X
  195. static void
  196. trtest(tt, line, inter)
  197. X    tree    **tt;
  198. X    char    *line;
  199. X    int    inter;
  200. X{
  201. X    char    opts[100], *pc, *n;
  202. X    int    opt, status;
  203. X
  204. X    pc = tree_srch(tt, compar, line);
  205. X    printf("tree_srch=%x\n", (unsigned)pc);
  206. X    if (pc)
  207. X    {
  208. X        printf("     <%s>\n", pc);
  209. X
  210. X        if (inter) {
  211. X            printf("delete? "); gets(opts); opt = (opts[0]=='y');
  212. X        }
  213. X        else
  214. X            opt = 1;
  215. X
  216. X        if (opt) {
  217. X            status = tree_delete(tt, compar, line, duar);
  218. X            printf("delete=%d\n", status);
  219. X        }
  220. X    }
  221. X    else
  222. X    {
  223. X        if (inter) {
  224. X            printf("add? "); gets(opts); opt = (opts[0]=='y');
  225. X        }
  226. X        else
  227. X            opt = 1;
  228. X
  229. X        if (opt) {
  230. X            char    *savestr();
  231. X
  232. X            n = savestr(line);
  233. X            tree_add(tt, compar, n, duar);
  234. X        }
  235. X    }
  236. X    tree_trav1(*tt, 0);
  237. X}
  238. X
  239. static void
  240. tree_trav1(t, l)
  241. X    tree    *t;
  242. X    int    l;
  243. X{
  244. X    int    i;
  245. X
  246. X    if (!t) return;
  247. X    tree_trav1(t->tree_l, l+1);
  248. X    for (i=0;  i<l;  i++) printf("  ");
  249. X    printf("%08lx (%s)\n", (unsigned)t->tree_p, (char*)t->tree_p);
  250. X    tree_trav1(t->tree_r, l+1);
  251. X}    
  252. X    
  253. static void
  254. duar(pc)
  255. X    char *pc;
  256. X{
  257. X    printf("duar called, pc=%08X: <%s>\n", (unsigned)pc, pc?pc:"");
  258. X    free(pc);
  259. X}
  260. X
  261. static int
  262. compar(l, r)
  263. X    char *l, *r;
  264. X{
  265. X    printf("compar(%s,%s)=%d\n", l, r, strcmp(l, r));
  266. X    return strcmp(l, r);
  267. X}
  268. X
  269. static char *
  270. savestr(str)
  271. X    char    *str;
  272. X{
  273. X    char    *save;
  274. X
  275. X    save = malloc(strlen(str) + 1);
  276. X    strcpy(save, str);
  277. X    return save;
  278. X}
  279. END_OF_FILE
  280. if test 2322 -ne `wc -c <'t_trtest.c'`; then
  281.     echo shar: \"'t_trtest.c'\" unpacked with wrong size!
  282. fi
  283. # end of 't_trtest.c'
  284. fi
  285. if test -f 'tree.c' -a "${1}" != "-c" ; then 
  286.   echo shar: Will not clobber existing file \"'tree.c'\"
  287. else
  288. echo shar: Extracting \"'tree.c'\" \(10780 characters\)
  289. sed "s/^X//" >'tree.c' <<'END_OF_FILE'
  290. X/* as_tree - tree library for as
  291. X * vix 14dec85 [written]
  292. X * vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221]
  293. X * vix 06feb86 [added tree_mung()]
  294. X * vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224]
  295. X * vix 23jun86 [added delete uar to add for replaced nodes]
  296. X * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
  297. X */
  298. X
  299. X
  300. X/* This program text was created by Paul Vixie using examples from the book:
  301. X * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN
  302. X * 0-13-022005-1.  This code and associated documentation is hereby placed
  303. X * in the public domain.
  304. X */
  305. X
  306. X
  307. X#ifndef LINT
  308. static char RCSid[] = "$Id:";
  309. X#endif
  310. X
  311. X
  312. X/*#define        DEBUG    "tree"*/
  313. X
  314. X
  315. X#include <stdio.h>
  316. X#include <stdlib.h>
  317. X#include "vixie.h"
  318. X#include "tree.h"
  319. X
  320. X
  321. X#ifdef DEBUG
  322. X#define        MSG(msg)    printf("DEBUG: '%s'\n", msg);
  323. X#else
  324. X#define        MSG(msg)
  325. X#endif
  326. X
  327. X
  328. X#ifdef __STDC__
  329. X#define __P(x) x
  330. X#else
  331. X#define    __P(x) ()
  332. X#endif
  333. X
  334. static void    sprout    __P( (tree **, tree_t, int *, int (*)(), void (*)()) );
  335. static int    delete    __P( (tree **, int (*)(), tree_t, void (*)(),
  336. X                  int *, int *) );
  337. static void    del    __P( (tree **, int *, tree **, void (*)(), int *) );
  338. static void    bal_L    __P( (tree **, int *) );
  339. static void    bal_R    __P( (tree **, int *) );
  340. X
  341. X#undef __P
  342. X
  343. X
  344. void
  345. tree_init(ppr_tree)
  346. X    tree    **ppr_tree;
  347. X{
  348. X    ENTER("tree_init")
  349. X    *ppr_tree = NULL;
  350. X    EXITV
  351. X}
  352. X    
  353. X
  354. tree_t
  355. tree_srch(ppr_tree, pfi_compare, p_user)
  356. X    tree    **ppr_tree;
  357. X    int    (*pfi_compare)();
  358. X    tree_t    p_user;
  359. X{
  360. X    register int    i_comp;
  361. X
  362. X    ENTER("tree_srch")
  363. X
  364. X    if (*ppr_tree)
  365. X    {
  366. X        i_comp = (*pfi_compare)(p_user, (**ppr_tree).tree_p);
  367. X        if (i_comp > 0)
  368. X            EXIT(tree_srch(
  369. X                &(**ppr_tree).tree_r,
  370. X                pfi_compare,
  371. X                p_user
  372. X            ))
  373. X        if (i_comp < 0)
  374. X            EXIT(tree_srch(
  375. X                &(**ppr_tree).tree_l,
  376. X                pfi_compare,
  377. X                p_user
  378. X            ))
  379. X
  380. X        /* not higher, not lower... this must be the one.
  381. X         */
  382. X        EXIT((**ppr_tree).tree_p)
  383. X    }
  384. X
  385. X    /* grounded. NOT found.
  386. X     */
  387. X    EXIT(NULL)
  388. X}
  389. X
  390. X
  391. void
  392. tree_add(ppr_tree, pfi_compare, p_user, pfv_uar)
  393. X    tree    **ppr_tree;
  394. X    int    (*pfi_compare)();
  395. X    tree_t    p_user;
  396. X    void    (*pfv_uar)();
  397. X{
  398. X    int    i_balance = FALSE;
  399. X
  400. X    ENTER("tree_add")
  401. X    sprout(ppr_tree, p_user, &i_balance, pfi_compare, pfv_uar);
  402. X    EXITV
  403. X}
  404. X
  405. X
  406. int
  407. tree_delete(ppr_p, pfi_compare, p_user, pfv_uar)
  408. X    tree    **ppr_p;
  409. X    int    (*pfi_compare)();
  410. X    tree_t    p_user;
  411. X    void    (*pfv_uar)();
  412. X{
  413. X    int    i_balance = FALSE,
  414. X        i_uar_called = FALSE;
  415. X
  416. X    ENTER("tree_delete");
  417. X    EXIT(delete(ppr_p, pfi_compare, p_user, pfv_uar,
  418. X            &i_balance, &i_uar_called))
  419. X}
  420. X
  421. X
  422. int
  423. tree_trav(ppr_tree, pfi_uar)
  424. X    tree    **ppr_tree;
  425. X    int    (*pfi_uar)();
  426. X{
  427. X    ENTER("tree_trav")
  428. X
  429. X    if (!*ppr_tree)
  430. X        EXIT(TRUE)
  431. X
  432. X    if (!tree_trav(&(**ppr_tree).tree_l, pfi_uar))
  433. X        EXIT(FALSE)
  434. X    if (!(*pfi_uar)((**ppr_tree).tree_p))
  435. X        EXIT(FALSE)
  436. X    if (!tree_trav(&(**ppr_tree).tree_r, pfi_uar))
  437. X        EXIT(FALSE)
  438. X    EXIT(TRUE)
  439. X}
  440. X
  441. X
  442. void
  443. tree_mung(ppr_tree, pfv_uar)
  444. X    tree    **ppr_tree;
  445. X    void    (*pfv_uar)();
  446. X{
  447. X    ENTER("tree_mung")
  448. X    if (*ppr_tree)
  449. X    {
  450. X        tree_mung(&(**ppr_tree).tree_l, pfv_uar);
  451. X        tree_mung(&(**ppr_tree).tree_r, pfv_uar);
  452. X        if (pfv_uar)
  453. X            (*pfv_uar)((**ppr_tree).tree_p);
  454. X        free(*ppr_tree);
  455. X        *ppr_tree = NULL;
  456. X    }
  457. X    EXITV
  458. X}
  459. X
  460. X
  461. static void
  462. sprout(ppr, p_data, pi_balance, pfi_compare, pfv_delete)
  463. X    tree    **ppr;
  464. X    tree_t    p_data;
  465. X    int    *pi_balance;
  466. X    int    (*pfi_compare)();
  467. X    void    (*pfv_delete)();
  468. X{
  469. X    tree    *p1, *p2;
  470. X    int    cmp;
  471. X
  472. X    ENTER("sprout")
  473. X
  474. X    /* are we grounded?  if so, add the node "here" and set the rebalance
  475. X     * flag, then exit.
  476. X     */
  477. X    if (!*ppr) {
  478. X        MSG("grounded. adding new node, setting h=true")
  479. X        *ppr = (tree *) malloc(sizeof(tree));
  480. X        (*ppr)->tree_l = NULL;
  481. X        (*ppr)->tree_r = NULL;
  482. X        (*ppr)->tree_b = 0;
  483. X        (*ppr)->tree_p = p_data;
  484. X        *pi_balance = TRUE;
  485. X        EXITV
  486. X    }
  487. X
  488. X    /* compare the data using routine passed by caller.
  489. X     */
  490. X    cmp = (*pfi_compare)(p_data, (*ppr)->tree_p);
  491. X
  492. X    /* if LESS, prepare to move to the left.
  493. X     */
  494. X    if (cmp < 0) {
  495. X        MSG("LESS. sprouting left.")
  496. X        sprout(&(*ppr)->tree_l, p_data, pi_balance,
  497. X            pfi_compare, pfv_delete);
  498. X        if (*pi_balance) {    /* left branch has grown longer */
  499. X            MSG("LESS: left branch has grown")
  500. X            switch ((*ppr)->tree_b)
  501. X            {
  502. X            case 1:    /* right branch WAS longer; balance is ok now */
  503. X                MSG("LESS: case 1.. balnce restored implicitly")
  504. X                (*ppr)->tree_b = 0;
  505. X                *pi_balance = FALSE;
  506. X                break;
  507. X            case 0:    /* balance WAS okay; now left branch longer */
  508. X                MSG("LESS: case 0.. balnce bad but still ok")
  509. X                (*ppr)->tree_b = -1;
  510. X                break;
  511. X            case -1:
  512. X                /* left branch was already too long. rebalnce */
  513. X                MSG("LESS: case -1: rebalancing")
  514. X                p1 = (*ppr)->tree_l;
  515. X                if (p1->tree_b == -1) {    /* LL */
  516. X                    MSG("LESS: single LL")
  517. X                    (*ppr)->tree_l = p1->tree_r;
  518. X                    p1->tree_r = *ppr;
  519. X                    (*ppr)->tree_b = 0;
  520. X                    *ppr = p1;
  521. X                }
  522. X                else {            /* double LR */
  523. X                    MSG("LESS: double LR")
  524. X
  525. X                    p2 = p1->tree_r;
  526. X                    p1->tree_r = p2->tree_l;
  527. X                    p2->tree_l = p1;
  528. X
  529. X                    (*ppr)->tree_l = p2->tree_r;
  530. X                    p2->tree_r = *ppr;
  531. X
  532. X                    if (p2->tree_b == -1)
  533. X                        (*ppr)->tree_b = 1;
  534. X                    else
  535. X                        (*ppr)->tree_b = 0;
  536. X
  537. X                    if (p2->tree_b == 1)
  538. X                        p1->tree_b = -1;
  539. X                    else
  540. X                        p1->tree_b = 0;
  541. X                    *ppr = p2;
  542. X                } /*else*/
  543. X                (*ppr)->tree_b = 0;
  544. X                *pi_balance = FALSE;
  545. X            } /*switch*/
  546. X        } /*if*/
  547. X        EXITV
  548. X    } /*if*/
  549. X
  550. X    /* if MORE, prepare to move to the right.
  551. X     */
  552. X    if (cmp > 0) {
  553. X        MSG("MORE: sprouting to the right")
  554. X        sprout(&(*ppr)->tree_r, p_data, pi_balance,
  555. X            pfi_compare, pfv_delete);
  556. X        if (*pi_balance) {    /* right branch has grown longer */
  557. X            MSG("MORE: right branch has grown")
  558. X
  559. X            switch ((*ppr)->tree_b)
  560. X            {
  561. X            case -1:MSG("MORE: balance was off, fixed implicitly")
  562. X                (*ppr)->tree_b = 0;
  563. X                *pi_balance = FALSE;
  564. X                break;
  565. X            case 0:    MSG("MORE: balance was okay, now off but ok")
  566. X                (*ppr)->tree_b = 1;
  567. X                break;
  568. X            case 1:    MSG("MORE: balance was off, need to rebalance")
  569. X                p1 = (*ppr)->tree_r;
  570. X                if (p1->tree_b == 1) {    /* RR */
  571. X                    MSG("MORE: single RR")
  572. X                    (*ppr)->tree_r = p1->tree_l;
  573. X                    p1->tree_l = *ppr;
  574. X                    (*ppr)->tree_b = 0;
  575. X                    *ppr = p1;
  576. X                }
  577. X                else {            /* double RL */
  578. X                    MSG("MORE: double RL")
  579. X
  580. X                    p2 = p1->tree_l;
  581. X                    p1->tree_l = p2->tree_r;
  582. X                    p2->tree_r = p1;
  583. X
  584. X                    (*ppr)->tree_r = p2->tree_l;
  585. X                    p2->tree_l = *ppr;
  586. X
  587. X                    if (p2->tree_b == 1)
  588. X                        (*ppr)->tree_b = -1;
  589. X                    else
  590. X                        (*ppr)->tree_b = 0;
  591. X
  592. X                    if (p2->tree_b == -1)
  593. X                        p1->tree_b = 1;
  594. X                    else
  595. X                        p1->tree_b = 0;
  596. X
  597. X                    *ppr = p2;
  598. X                } /*else*/
  599. X                (*ppr)->tree_b = 0;
  600. X                *pi_balance = FALSE;
  601. X            } /*switch*/
  602. X        } /*if*/
  603. X        EXITV
  604. X    } /*if*/
  605. X
  606. X    /* not less, not more: this is the same key!  replace...
  607. X     */
  608. X    MSG("I found it!  Replacing data value")
  609. X    *pi_balance = FALSE;
  610. X    if (pfv_delete)
  611. X        (*pfv_delete)((*ppr)->tree_p);
  612. X    (*ppr)->tree_p = p_data;
  613. X    EXITV
  614. X}
  615. X
  616. X
  617. static int
  618. delete(ppr_p, pfi_compare, p_user, pfv_uar, pi_balance, pi_uar_called)
  619. X    tree    **ppr_p;
  620. X    int    (*pfi_compare)();
  621. X    tree_t    p_user;
  622. X    void    (*pfv_uar)();
  623. X    int    *pi_balance;
  624. X    int    *pi_uar_called;
  625. X{
  626. X    tree    *pr_q;
  627. X    int    i_comp, i_ret;
  628. X
  629. X    ENTER("delete")
  630. X
  631. X    if (*ppr_p == NULL) {
  632. X        MSG("key not in tree")
  633. X        EXIT(FALSE)
  634. X    }
  635. X
  636. X    i_comp = (*pfi_compare)((*ppr_p)->tree_p, p_user);
  637. X    if (i_comp > 0) {
  638. X        MSG("too high - scan left")
  639. X        i_ret = delete(&(*ppr_p)->tree_l, pfi_compare, p_user, pfv_uar,
  640. X                        pi_balance, pi_uar_called);
  641. X        if (*pi_balance)
  642. X            bal_L(ppr_p, pi_balance);
  643. X    }
  644. X    else if (i_comp < 0) {
  645. X        MSG("too low - scan right")
  646. X        i_ret = delete(&(*ppr_p)->tree_r, pfi_compare, p_user, pfv_uar,
  647. X                        pi_balance, pi_uar_called);
  648. X        if (*pi_balance)
  649. X            bal_R(ppr_p, pi_balance);
  650. X    }
  651. X    else {
  652. X        MSG("equal")
  653. X        pr_q = *ppr_p;
  654. X        if (pr_q->tree_r == NULL) {
  655. X            MSG("right subtree null")
  656. X            *ppr_p = pr_q->tree_l;
  657. X            *pi_balance = TRUE;
  658. X        }
  659. X        else if (pr_q->tree_l == NULL) {
  660. X            MSG("right subtree non-null, left subtree null")
  661. X            *ppr_p = pr_q->tree_r;
  662. X            *pi_balance = TRUE;
  663. X        }
  664. X        else {
  665. X            MSG("neither subtree null")
  666. X            del(&pr_q->tree_l, pi_balance, &pr_q, pfv_uar,
  667. X                                pi_uar_called);
  668. X            if (*pi_balance)
  669. X                bal_L(ppr_p, pi_balance);
  670. X        }
  671. X        if (!*pi_uar_called && *pfv_uar)
  672. X            (*pfv_uar)(pr_q->tree_p);
  673. X        free(pr_q);    /* thanks to wuth@castrov.cuc.ab.ca */
  674. X        i_ret = TRUE;
  675. X    }
  676. X    EXIT(i_ret)
  677. X}
  678. X
  679. X
  680. static void
  681. del(ppr_r, pi_balance, ppr_q, pfv_uar, pi_uar_called)
  682. X    tree    **ppr_r;
  683. X    int    *pi_balance;
  684. X    tree    **ppr_q;
  685. X    void    (*pfv_uar)();
  686. X    int    *pi_uar_called;
  687. X{
  688. X    ENTER("del")
  689. X
  690. X    if ((*ppr_r)->tree_r != NULL) {
  691. X        del(&(*ppr_r)->tree_r, pi_balance, ppr_q,
  692. X            pfv_uar, pi_uar_called);
  693. X        if (*pi_balance)
  694. X            bal_R(ppr_r, pi_balance);
  695. X    } else {
  696. X        if (pfv_uar)
  697. X            (*pfv_uar)((*ppr_q)->tree_p);
  698. X        *pi_uar_called = TRUE;
  699. X        (*ppr_q)->tree_p = (*ppr_r)->tree_p;
  700. X        *ppr_q = *ppr_r;
  701. X        *ppr_r = (*ppr_r)->tree_l;
  702. X        *pi_balance = TRUE;
  703. X    }
  704. X
  705. X    EXITV
  706. X}
  707. X
  708. X
  709. static void
  710. bal_L(ppr_p, pi_balance)
  711. X    tree    **ppr_p;
  712. X    int    *pi_balance;
  713. X{
  714. X    tree    *p1, *p2;
  715. X    int    b1, b2;
  716. X
  717. X    ENTER("bal_L")
  718. X    MSG("left branch has shrunk")
  719. X
  720. X    switch ((*ppr_p)->tree_b)
  721. X    {
  722. X    case -1: MSG("was imbalanced, fixed implicitly")
  723. X        (*ppr_p)->tree_b = 0;
  724. X        break;
  725. X    case 0:    MSG("was okay, is now one off")
  726. X        (*ppr_p)->tree_b = 1;
  727. X        *pi_balance = FALSE;
  728. X        break;
  729. X    case 1:    MSG("was already off, this is too much")
  730. X        p1 = (*ppr_p)->tree_r;
  731. X        b1 = p1->tree_b;
  732. X        if (b1 >= 0) {
  733. X            MSG("single RR")
  734. X            (*ppr_p)->tree_r = p1->tree_l;
  735. X            p1->tree_l = *ppr_p;
  736. X            if (b1 == 0) {
  737. X                MSG("b1 == 0")
  738. X                (*ppr_p)->tree_b = 1;
  739. X                p1->tree_b = -1;
  740. X                *pi_balance = FALSE;
  741. X            } else {
  742. X                MSG("b1 != 0")
  743. X                (*ppr_p)->tree_b = 0;
  744. X                p1->tree_b = 0;
  745. X            }
  746. X            *ppr_p = p1;
  747. X        } else {
  748. X            MSG("double RL")
  749. X            p2 = p1->tree_l;
  750. X            b2 = p2->tree_b;
  751. X            p1->tree_l = p2->tree_r;
  752. X            p2->tree_r = p1;
  753. X            (*ppr_p)->tree_r = p2->tree_l;
  754. X            p2->tree_l = *ppr_p;
  755. X            if (b2 == 1)
  756. X                (*ppr_p)->tree_b = -1;
  757. X            else
  758. X                (*ppr_p)->tree_b = 0;
  759. X            if (b2 == -1)
  760. X                p1->tree_b = 1;
  761. X            else
  762. X                p1->tree_b = 0;
  763. X            *ppr_p = p2;
  764. X            p2->tree_b = 0;
  765. X        }
  766. X    }
  767. X    EXITV
  768. X}
  769. X
  770. X
  771. static void
  772. bal_R(ppr_p, pi_balance)
  773. X    tree    **ppr_p;
  774. X    int    *pi_balance;
  775. X{
  776. X    tree    *p1, *p2;
  777. X    int    b1, b2;
  778. X
  779. X    ENTER("bal_R")
  780. X    MSG("right branch has shrunk")
  781. X    switch ((*ppr_p)->tree_b)
  782. X    {
  783. X    case 1:    MSG("was imbalanced, fixed implicitly")
  784. X        (*ppr_p)->tree_b = 0;
  785. X        break;
  786. X    case 0:    MSG("was okay, is now one off")
  787. X        (*ppr_p)->tree_b = -1;
  788. X        *pi_balance = FALSE;
  789. X        break;
  790. X    case -1: MSG("was already off, this is too much")
  791. X        p1 = (*ppr_p)->tree_l;
  792. X        b1 = p1->tree_b;
  793. X        if (b1 <= 0) {
  794. X            MSG("single LL")
  795. X            (*ppr_p)->tree_l = p1->tree_r;
  796. X            p1->tree_r = *ppr_p;
  797. X            if (b1 == 0) {
  798. X                MSG("b1 == 0")
  799. X                (*ppr_p)->tree_b = -1;
  800. X                p1->tree_b = 1;
  801. X                *pi_balance = FALSE;
  802. X            } else {
  803. X                MSG("b1 != 0")
  804. X                (*ppr_p)->tree_b = 0;
  805. X                p1->tree_b = 0;
  806. X            }
  807. X            *ppr_p = p1;
  808. X        } else {
  809. X            MSG("double LR")
  810. X            p2 = p1->tree_r;
  811. X            b2 = p2->tree_b;
  812. X            p1->tree_r = p2->tree_l;
  813. X            p2->tree_l = p1;
  814. X            (*ppr_p)->tree_l = p2->tree_r;
  815. X            p2->tree_r = *ppr_p;
  816. X            if (b2 == -1)
  817. X                (*ppr_p)->tree_b = 1;
  818. X            else
  819. X                (*ppr_p)->tree_b = 0;
  820. X            if (b2 == 1)
  821. X                p1->tree_b = -1;
  822. X            else
  823. X                p1->tree_b = 0;
  824. X            *ppr_p = p2;
  825. X            p2->tree_b = 0;
  826. X        }
  827. X    }
  828. X    EXITV
  829. X}
  830. END_OF_FILE
  831. if test 10780 -ne `wc -c <'tree.c'`; then
  832.     echo shar: \"'tree.c'\" unpacked with wrong size!
  833. fi
  834. # end of 'tree.c'
  835. fi
  836. if test -f 'tree.h' -a "${1}" != "-c" ; then 
  837.   echo shar: Will not clobber existing file \"'tree.h'\"
  838. else
  839. echo shar: Extracting \"'tree.h'\" \(767 characters\)
  840. sed "s/^X//" >'tree.h' <<'END_OF_FILE'
  841. X/* tree.h - declare structures used by tree.c
  842. X * vix 27jun86 [broken out of tree.c]
  843. X * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
  844. X *
  845. X * $Id:$
  846. X */
  847. X
  848. X
  849. X#ifndef    _TREE_FLAG
  850. X#define    _TREE_FLAG
  851. X
  852. X
  853. X#ifdef __STDC__
  854. typedef    void *    tree_t;
  855. X#define __P(x) x
  856. X#else
  857. typedef    char *    tree_t;
  858. X#define    __P(x) ()
  859. X#endif
  860. X
  861. X
  862. typedef    struct    tree_s
  863. X    {
  864. X        struct    tree_s    *tree_l, *tree_r;
  865. X        short        tree_b;
  866. X        tree_t        tree_p;
  867. X    }
  868. X    tree;
  869. X
  870. X
  871. void    tree_init    __P( (tree **) );
  872. tree_t    tree_srch    __P( (tree **, int (*)(), tree_t) );
  873. void    tree_add    __P( (tree **, int (*)(), tree_t, void (*)()) );
  874. int    tree_delete    __P( (tree **, int (*)(), tree_t, void (*)()) );
  875. int    tree_trav    __P( (tree **, int (*)()) );
  876. void    tree_mung    __P( (tree **, void (*)()) );
  877. X
  878. X
  879. X#undef __P
  880. X
  881. X
  882. X#endif    /* _TREE_FLAG */
  883. END_OF_FILE
  884. if test 767 -ne `wc -c <'tree.h'`; then
  885.     echo shar: \"'tree.h'\" unpacked with wrong size!
  886. fi
  887. # end of 'tree.h'
  888. fi
  889. if test -f 'tree.man3' -a "${1}" != "-c" ; then 
  890.   echo shar: Will not clobber existing file \"'tree.man3'\"
  891. else
  892. echo shar: Extracting \"'tree.man3'\" \(4082 characters\)
  893. sed "s/^X//" >'tree.man3' <<'END_OF_FILE'
  894. X.TH TREE 3 "22 Jan 1993"
  895. X.\" from .TH TREE 2 "23 June 1986"
  896. X.UC 4
  897. X.SH NAME
  898. tree_init, tree_mung, tree_srch, tree_add, tree_delete, tree_trav
  899. X\- balanced binary tree routines
  900. X.SH SYNOPSIS
  901. X.nf
  902. X.B void
  903. X.B tree_init(tree)
  904. X.B void **tree;
  905. X.PP
  906. X.B int *
  907. X.B tree_srch(tree, compare, data)
  908. X.B void **tree;
  909. X.B int (*compare)();
  910. X.B void *data;
  911. X.PP
  912. X.B void
  913. X.B tree_add(tree, compare, data, del_uar)
  914. X.B void **tree;
  915. X.B int (*compare)();
  916. X.B void *data;
  917. X.B void (*del_uar)();
  918. X.PP
  919. X.B int
  920. X.B tree_delete(tree, compare, data, del_uar)
  921. X.B void **tree;
  922. X.B int (*compare)();
  923. X.B void *data;
  924. X.B void (*del_uar)();
  925. X.PP
  926. X.B int
  927. X.B tree_trav(tree, trav_uar)
  928. X.B void **tree;
  929. X.B int (*trav_uar)();
  930. X.PP
  931. X.B void
  932. X.B tree_mung(tree, del_uar)
  933. X.B void **tree;
  934. X.B void (*del_uar)();
  935. X.fi
  936. X.SH DESCRIPTION
  937. These functions create and manipulate a balanced binary (AVL) tree.  Each node
  938. of the tree contains the expected left & right subtree pointers, a short-int
  939. balance indicator, and a pointer to the user-data.  On a 32-bit system, this
  940. means an overhead of 4+4+2+4 bytes per node (or, on a RISC or otherwise
  941. alignment-constrained system with implied padding, 4+4+4+4 bytes per node).
  942. There is no key data type enforced by this package; a caller-supplied
  943. compare routine is used to compare user-data blocks.
  944. X.PP
  945. Balanced binary trees are very fast on searches and replacements, but have a
  946. moderately high cost for additions and deletions.  If your application does a
  947. lot more searches and replacements than it does additions and deletions, the
  948. balanced (AVL) binary tree is a good choice for a data structure.
  949. X.PP
  950. X.I Tree_init
  951. creates an empty tree and binds it to
  952. X.I tree
  953. X(which for this and all other routines in this package should be declared as
  954. a pointer to void or int, and passed by reference), which can then be used by
  955. other routines in this package.  Note that more than one
  956. X.I tree
  957. variable can exist at once; thus multiple trees can be manipulated
  958. simultaneously.
  959. X.PP
  960. X.I Tree_srch
  961. searches a tree for a specific node and returns either
  962. X.I NULL
  963. if no node was found, or the value of the user-data pointer if the node
  964. was found.
  965. X.I compare
  966. is the address of a function to compare two user-data blocks.  This routine
  967. should work much the way 
  968. X.IR strcmp 2
  969. does; in fact,
  970. X.I strcmp
  971. could be used if the user-data was a null-terminated string.
  972. X.I data
  973. is the address of a user-data block to be used by
  974. X.I compare
  975. as the search criteria.  The tree is searched for a node where
  976. X.I compare
  977. returns 0.
  978. X.PP
  979. X.I Tree_add
  980. inserts or replaces a node in the specified tree.  The tree specified by
  981. X.I tree
  982. is searched as in
  983. X.I tree_srch,
  984. and if a node is found to match
  985. X.I data,
  986. then the
  987. X.I del_uar
  988. function is called with the address of the user-data block for the node
  989. X(this routine should deallocate any dynamic memory which is referenced
  990. exclusively by the node); the user-data pointer for the node is then
  991. replaced by the value of
  992. X.I data.
  993. If no node is found to match, a new node is added (which may or may not
  994. cause a transparent rebalance operation), with a user-data pointer equal to
  995. X.I data.
  996. A rebalance may or may not occur, depending on where the node is added
  997. and what the rest of the tree looks like.
  998. X.PP
  999. X.I Tree_delete
  1000. deletes a node from
  1001. X.I tree.
  1002. A rebalance may or may not occur, depending on where the node is removed from
  1003. and what the rest of the tree looks like.
  1004. X.I Tree_delete
  1005. returns TRUE if a node was deleted, FALSE otherwise.
  1006. X.PP
  1007. X.I Tree_trav
  1008. traverses all of
  1009. X.I tree,
  1010. calling
  1011. X.I trav_uar
  1012. with the address of each user-data block.  If
  1013. X.I trav_uar
  1014. returns FALSE at any time,
  1015. X.I tree_trav
  1016. will immediately return FALSE to its caller.  Otherwise all nodes will be 
  1017. reached and
  1018. X.I tree_trav
  1019. will return TRUE.
  1020. X.PP
  1021. X.I Tree_mung
  1022. deletes every node in
  1023. X.I tree,
  1024. calling
  1025. X.I del_uar
  1026. with the user-data address from each node (see
  1027. X.I tree_add
  1028. and
  1029. X.I tree_delete
  1030. above).  The tree is left in the same state that
  1031. X.I tree_init
  1032. leaves it in \- i.e., empty.
  1033. X.SH AUTHOR
  1034. Paul Vixie, converted and augumented from Modula-2 examples in
  1035. X.I Algorithms & Data Structures,
  1036. Niklaus Wirth, Prentice-Hall, ISBN 0-13-022005-1.
  1037. END_OF_FILE
  1038. if test 4082 -ne `wc -c <'tree.man3'`; then
  1039.     echo shar: \"'tree.man3'\" unpacked with wrong size!
  1040. fi
  1041. # end of 'tree.man3'
  1042. fi
  1043. if test -f 'vixie.h' -a "${1}" != "-c" ; then 
  1044.   echo shar: Will not clobber existing file \"'vixie.h'\"
  1045. else
  1046. echo shar: Extracting \"'vixie.h'\" \(1555 characters\)
  1047. sed "s/^X//" >'vixie.h' <<'END_OF_FILE'
  1048. X/* vixie.h - include file to define general vixie-type things
  1049. X * v1.0 vix 21jun86 [broken out of as.h]
  1050. X */
  1051. X
  1052. X#ifdef    DOCUMENTATION
  1053. X
  1054. There are two macros you can define before including this file which can
  1055. change the things defined by this file.
  1056. X
  1057. DEBUG:    if defined, will cause enter/exit messages to be printed by the
  1058. X    ENTER/EXIT/EXITV macros.  If not defined, causes ENTER to do nothing,
  1059. X    and EXIT/EXITV to generate 'return' without any messages.
  1060. X
  1061. X    If defined, should be set to the name of the including module.
  1062. X
  1063. MAIN:    Should be defined for a program containing a main() function which
  1064. X    is linked with other modules which include this file.
  1065. X
  1066. X    Value is not important, only existence/nonexistence matters.
  1067. X
  1068. X#endif    /* DOCUMENTATION */
  1069. X
  1070. X
  1071. X#ifndef    _VIXIE_FLAG
  1072. X#define    _VIXIE_FLAG
  1073. X
  1074. X
  1075. X                        /*--- debugging stuff ---*/
  1076. X#define    MAXPROC    256
  1077. X
  1078. X#ifdef DEBUG
  1079. X#define    ENTER(proc) { \
  1080. X            APC_PROCS[I_PROC] = proc; \
  1081. X            printf("ENTER(%d:%s.%s)\n", \
  1082. X                I_PROC, DEBUG, APC_PROCS[I_PROC]); \
  1083. X            I_PROC++; \
  1084. X        }
  1085. X#define    EXIT(value) { \
  1086. X            I_PROC--; \
  1087. X            printf("EXIT(%d:%s.%s)\n", \
  1088. X                I_PROC, DEBUG, \
  1089. X                APC_PROCS[I_PROC]); \
  1090. X            return value; \
  1091. X        }
  1092. X#define    EXITV { \
  1093. X            I_PROC--; \
  1094. X            printf("EXITV(%d:%s.%s)\n", \
  1095. X                I_PROC, DEBUG, \
  1096. X                APC_PROCS[I_PROC]); \
  1097. X            return; \
  1098. X        }
  1099. X#else
  1100. X#define    ENTER(proc)
  1101. X#define    EXIT(value)    {return value;}
  1102. X#define    EXITV        return;
  1103. X#endif
  1104. X
  1105. X#ifdef MAIN
  1106. int    I_PROC = 0;
  1107. char    *APC_PROCS[MAXPROC];
  1108. X#else
  1109. extern    int    I_PROC;
  1110. extern    char    *APC_PROCS[MAXPROC];
  1111. X#endif
  1112. X
  1113. X
  1114. X#ifndef TRUE
  1115. X#define    TRUE        1
  1116. X#define    FALSE        0
  1117. X#endif
  1118. X
  1119. X
  1120. X#endif    /* _VIXIE_FLAG */
  1121. END_OF_FILE
  1122. if test 1555 -ne `wc -c <'vixie.h'`; then
  1123.     echo shar: \"'vixie.h'\" unpacked with wrong size!
  1124. fi
  1125. # end of 'vixie.h'
  1126. fi
  1127. echo shar: End of shell archive.
  1128. exit 0
  1129.