Artifact Content
Not logged in
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2018 Conference, Houston/TX, US, Oct 15-19
Send your abstracts to tclconference@googlegroups.com or submit via the online form
by Aug 20.

Artifact 822483fd556b93ba17510c8bbe1a6c5c40d3946b:


     1  ##
     2  ## This file implements an in-memory balanced binary tree.  This code
     3  ## was originally brought in to implement an efficient priority queue
     4  ## for the Dijkstra's shortest path algorithm in crewroute.c.
     5  ##
     6  ## This file contains code imported into READI from another project.
     7  ## The text of the original header comment follows:
     8  ##
     9  ##
    10  ## A package of routines for handling balanced binary trees.
    11  ## Copyright (c) 1990 by D. Richard Hipp
    12  ##
    13  
    14  my code public-structure {
    15  typedef struct Tree Tree;
    16  /* A complete binary tree is defined by an instance of the following
    17  ** structure
    18  */
    19  struct Tree {
    20    int (*xCompare)(const void*, const void*); /* Comparison function */
    21    void *(*xCopy)(const void*);               /* Key copy function, or NULL */
    22    void (*xFree)(void*);                      /* Key delete function */
    23    struct TreeElem *top;                      /* The top-most node of the tree */
    24  };
    25  
    26  /* Each node in the binary tree is represented by a single instance
    27  ** of the following structure
    28  */
    29  typedef struct TreeElem TreeElem;
    30  struct TreeElem {
    31    void *data;             /* Pointer to the user's data */
    32    void *key;              /* The key associated with this element */
    33    TreeElem *left;         /* Left daughter */
    34    TreeElem *right;        /* Right daughter */
    35    int weight;             /* Weight of this node */
    36  };
    37  }
    38  
    39  my c_function {void TreeInit(Tree *tree, int (*xCompare)(const void*, const void*),void *(*xCopy)(const void*),void (*xFree)(void*))} {
    40  /* Turn bulk memory into a Tree structure
    41    Tree *tree,                                 Tree object to initialize
    42    int (*xCompare)(const void*, const void*),  Comparison function
    43    void *(*xCopy)(const void*),                Key copy function or NULL 
    44    void (*xFree)(void*)                        Key delete function or NULL
    45  */
    46    tree->xCompare = xCompare;
    47    tree->xCopy = xCopy;
    48    tree->xFree = xFree;
    49    tree->top = 0;
    50  }
    51  
    52  my c_function {int TreeCount(Tree *pTree)} {
    53    /* Return the number of elements in the tree. */
    54    if( pTree && pTree->top ){
    55      return pTree->top->weight;
    56    }else{
    57      return 0;
    58    }
    59  }
    60  
    61  my c_function {static void TreeClearNode(TreeElem *p, void (*xFree)(void*))} {
    62    /* Delete a single node of the binary tree and all of its children */
    63    if( p==0 ) return;
    64    if( p->left ) TreeClearNode(p->left, xFree);
    65    if( p->right ) TreeClearNode(p->right, xFree);
    66    if( xFree ){
    67      xFree(p->key);
    68    }
    69    Tcl_Free((char *)p);
    70  }
    71  
    72  my c_function {void TreeClear(Tree *tree)} {
    73    /* Remove all nodes from a tree */
    74    if( tree->top ){
    75      TreeClearNode(tree->top, tree->xFree);
    76    }
    77    tree->top = 0;
    78  }
    79  
    80  my c_function {void *TreeFind(Tree *tree, const void *key)} {
    81  /* Find the element of the tree (if any) whose key matches "key".
    82  ** Return a pointer to the data for that element.  If no match
    83  ** is found, return NULL.
    84  */
    85    TreeElem *p;
    86  
    87    p = tree->top;
    88    while( p ){
    89      int c = tree->xCompare(p->key, key);
    90      if( c==0 ){
    91        return p->data;
    92      }else if( c<0 ){
    93        p = p->right;
    94      }else{
    95        p = p->left;
    96      }
    97    }
    98    return 0;
    99  }
   100  
   101  my c_function {int TreeRank(Tree *tree, const void *key)} {
   102    /* If the node with key "key" is the left-most element of the tree, 
   103    ** return 0.  If it is the second to the left, return 1.  And so
   104    ** forth.
   105    **
   106    ** If there is no node in the tree with the key "key", then return
   107    ** the number that would have been returned if such a node were
   108    ** inserted.
   109    */
   110    TreeElem *p;
   111    int rank = 0;
   112  
   113    p = tree->top;
   114    while( p ){
   115      int c = tree->xCompare(p->key, key);
   116      if( c==0 ){
   117        rank += p->left ? p->left->weight: 0;
   118        break;
   119      }else if( c<0 ){
   120        rank += (p->left ? p->left->weight: 0) + 1;
   121        p = p->right;
   122      }else{
   123        p = p->left;
   124      }
   125    }
   126    return rank;
   127  }
   128  
   129  my c_function {static TreeElem *TreeFindNthElem(Tree *tree, int n)} {
   130    /* Return a pointer to the N-th element of a tree.  (The left-most
   131    ** element is number 0, the next is number 1 and so forth.)
   132    */
   133    TreeElem *p;
   134  
   135    p = tree->top;
   136    while( p ){
   137      int c = p->left ? p->left->weight : 0;
   138      if( n==c ){
   139        return p;
   140      }else if( n>c ){
   141        n -= c+1;
   142        p = p->right;
   143      }else{
   144        p = p->left;
   145      }
   146    }
   147    return 0;
   148  }
   149  
   150  my c_function {void *TreeData(Tree *tree, int n)} {
   151    /* Return the data associated with the N-th element of the tree.  Return
   152    ** NULL if there is no N-th element.
   153    */
   154    TreeElem *p = TreeFindNthElem(tree,n);
   155    return p ? p->data : 0;
   156  }
   157  
   158  my c_function {const void *TreeKey(Tree *tree, int n)} {
   159    /* Return the key associated with the N-th element of the tree.  Return
   160    ** NULL if there is no N-th element.
   161    */
   162    TreeElem *p = TreeFindNthElem(tree,n);
   163    if( p ){
   164      return p->key;
   165    }else{
   166      return 0;
   167    }
   168  }
   169  
   170  my c_function {static void TreeBalance(TreeElem **ppElem)} {
   171    /*
   172    ** Definitions:
   173    ** WEIGHT
   174    **   The weight of a node is the total number of children for the node
   175    **   plus 1.  Leaf nodes have a weight of 1.  The root node has a weight
   176    **   which equals the number of nodes in the tree.
   177    **
   178    ** BALANCE
   179    **   A node is balanced if the weight of the one child is not more than
   180    **   twice the weight of the other child.
   181    */
   182  
   183    /* The following routine rebalances the tree rooted at *ppElem after
   184    ** the insertion or deletion of a single ancestor.
   185    */
   186    TreeElem *n;     /* Pointer to self */
   187    int l,r;         /* Weight of left and right daughters */
   188    int a,b;         /* Weights of various nodes */
   189  
   190    if( ppElem==0 || (n=*ppElem)==0 ) return;
   191    l = n->left ? n->left->weight: 0;
   192    r = n->right ? n->right->weight: 0;
   193    if( l>r*2 ){    /* Too heavy on the left side */
   194      TreeElem *nl;     /* Pointer to left daughter */
   195      TreeElem *nr;     /* Pointer to right daughter */
   196      int ll, lr;       /* Weight of left daughter's left and right daughter */
   197      nl = n->left;
   198      ll = nl->left ? nl->left->weight: 0;
   199      lr = nl->right ? nl->right->weight: 0;
   200      if( ll>lr || nl->right==0 ){
   201        /*
   202        ** Convert from:  n     to:  nl
   203        **               / \        /  \
   204        **              nl  c      a    n
   205        **             /  \            / \
   206        **            a    b          b   c
   207        */
   208        n->left = nl->right;
   209        nl->right = n;
   210        n->weight = a = r + lr + 1;
   211        nl->weight = a + ll + 1;
   212        *ppElem = nl;
   213      }else{
   214        /*
   215        ** Convert from:  n        to:  nr
   216        **               / \           /  \
   217        **             nl   d        nl    n
   218        **            /  \          / \   / \
   219        **           a    nr       a   b c   d
   220        **               /  \
   221        **              b    c
   222        */
   223        int lrl, lrr;    /* Weight of Great-granddaughter nodes */
   224        nr = nl->right;
   225        lrl = nr->left ? nr->left->weight: 0;
   226        lrr = nr->right ? nr->right->weight: 0;
   227        nl->right = nr->left;
   228        nr->left = nl;
   229        n->left = nr->right;
   230        nr->right = n;
   231        n->weight = a = lrr + r + 1;
   232        nl->weight = b = ll + lrl + 1;
   233        nr->weight = a + b + 1;
   234        *ppElem = nr;
   235      }
   236    }else if( r>l*2 ){/* Too deep on the right side */
   237      TreeElem *nl;     /* Pointer to left daughter */
   238      TreeElem *nr;     /* Pointer to right daughter */
   239      int rl, rr;       /* Weight of right daughter's left and right daughter */
   240      nr = n->right;
   241      rl = nr->left ? nr->left->weight: 0;
   242      rr = nr->right ? nr->right->weight: 0;
   243      if( rr>rl || nr->left==0 ){
   244        /*
   245        ** Convert from:  n         to:  nr
   246        **               / \            /  \
   247        **              a   nr         n    c 
   248        **                 /  \       / \
   249        **                b    c     a   b
   250        */
   251        n->right = nr->left;
   252        nr->left = n;
   253        n->weight = a = l + rl + 1;
   254        nr->weight = a + rr + 1;
   255        *ppElem = nr;
   256      }else{
   257        /*
   258        ** Convert from:  n         to:  nl
   259        **               / \            /  \
   260        **              a   nr         n    nr
   261        **                 /  \       / \   / \
   262        **               nl    d     a   b c   d
   263        **              /  \
   264        **             b    c
   265        */
   266        int rll,rlr;    /* Weights of great-granddaughter nodes */
   267        nl = nr->left;
   268        rll = nl->left ? nl->left->weight: 0;
   269        rlr = nl->right ? nl->right->weight: 0;
   270        nr->left = nl->right;
   271        nl->right = nr;
   272        n->right = nl->left;
   273        nl->left = n;
   274        n->weight = a = l + rll + 1;
   275        nr->weight = b = rr + rlr + 1;
   276        nl->weight = a + b + 1;
   277        *ppElem = nl;
   278      }
   279    }else{ /* Node is already balanced.  Just recompute its weight. */
   280      n->weight = l + r + 1;
   281    }
   282  }
   283  
   284  my c_function {static void *TreeInsertElement(Tree *pTree, void *key, void *data)} {
   285    /*
   286    Tree *pTree,              The root of the tree
   287    void *key,                Insert data at this key
   288    void *data                Data to be inserted
   289    */
   290    /* This routine either changes the data on an existing node in the tree,
   291    ** or inserts a new node.  "key" identifies the node.  If the data on
   292    ** an existing node is changed, then the function returns the old data.
   293    ** If a new node is created, NULL is returned.
   294    */
   295    TreeElem *n;
   296    void *old = 0;
   297    TreeElem **h[100];  /* Sufficient for a tree with up to 4.0E+17 nodes */
   298    int level = 0;
   299  
   300  
   301    h[0] = &pTree->top;
   302    level = 1;
   303    n = pTree->top;
   304    while( n ){
   305      int c;
   306      c = pTree->xCompare(key, n->key);
   307      if( c<0 ){
   308        h[level++] = &(n->left);
   309        n = n->left;
   310      }else if( c>0 ){
   311        h[level++] = &(n->right);
   312        n = n->right;
   313      }else{
   314        old = n->data;
   315        n->data = data;                /* Replace data in an existing node */
   316        break;
   317      }
   318    }
   319    if( n==0 ){                     /* Insert a leaf node */
   320      level--;
   321      n = *h[level] = (TreeElem *)Tcl_Alloc( sizeof(TreeElem) );
   322      if( n==0 ){
   323        return data;
   324      }
   325      n->data = data;
   326      if( pTree->xCopy ){
   327        n->key = pTree->xCopy(key);
   328      }else{
   329        n->key = key;
   330      }
   331      n->left = n->right = 0;
   332      while( level>=0 ) TreeBalance(h[level--]);
   333    }
   334    return old;
   335  }
   336  
   337  my c_function {static TreeElem *TreeDeleteNthElem(TreeElem **ppTop, int N)} {
   338    /* Unlink the N-th node of the tree and return a pointer to that
   339    ** node.  (The left-most node is 0, the next node to the right is
   340    ** 1 and so forth.)
   341    */
   342    TreeElem *p;        /* For walking the tree */
   343    int level = 0;      /* Depth of the blancing stack */
   344    TreeElem **h[100];  /* Balance stack.  100 is sufficient for balancing
   345                        ** a tree with up to 4.0E+17 nodes */
   346  
   347    h[0] = ppTop;
   348    level = 1;
   349    p = *ppTop;
   350    while( p ){
   351      int w;
   352      w = (p->left ? p->left->weight: 0);
   353      if( N>w ){
   354        h[level++] = &(p->right);
   355        p = p->right;
   356        N -= w+1;
   357      }else if( N<w ){
   358        h[level++] = &(p->left);
   359        p = p->left;
   360      }else{
   361        break;
   362      }
   363    }
   364    if( p ){
   365      level--;
   366      if( p->left==0 ){
   367        *h[level] = p->right;
   368        level--;
   369      }else if( p->right==0 ){
   370        *h[level] = p->left;
   371        level--;
   372      }else{
   373        TreeElem *x;
   374        x = TreeDeleteNthElem(&(p->right),0);
   375        x->right = p->right;
   376        x->left = p->left;
   377        *h[level] = x;
   378      }
   379      while( level>=0 ) TreeBalance(h[level--]);
   380    }
   381    return p;
   382  }
   383  
   384  my c_function {static TreeElem *TreeDeleteElem(Tree *tree, const void *key)} {
   385    /* Unlink the node of the tree corresponding to key and return a pointer 
   386    ** to that node.
   387    */
   388    TreeElem *p;        /* For walking the tree */
   389    int level = 0;      /* Depth of the blancing stack */
   390    TreeElem **h[100];  /* Balance stack.  100 is sufficient for balancing
   391                        ** a tree with up to 4.0E+17 nodes */
   392  
   393    h[0] = &tree->top;
   394    level = 1;
   395    p = tree->top;
   396    while( p ){
   397      int w;
   398      w = tree->xCompare(p->key, key);
   399      if( w<0 ){
   400        h[level++] = &(p->right);
   401        p = p->right;
   402      }else if( w>0 ){
   403        h[level++] = &(p->left);
   404        p = p->left;
   405      }else{
   406        break;
   407      }
   408    }
   409    if( p ){
   410      level--;
   411      if( p->left==0 ){
   412        *h[level] = p->right;
   413        level--;
   414      }else if( p->right==0 ){
   415        *h[level] = p->left;
   416        level--;
   417      }else{
   418        TreeElem *x;
   419        x = TreeDeleteNthElem(&(p->right),0);
   420        x->right = p->right;
   421        x->left = p->left;
   422        *h[level] = x;
   423      }
   424      while( level>=0 ) TreeBalance(h[level--]);
   425    }
   426    return p;
   427  }
   428  
   429  my c_function {void *TreeInsert(Tree *tree, void *key, void *data)} {
   430    /* Insert new data into a node of the tree.  The node is identified
   431    ** by "key".
   432    **
   433    ** If the new data is NULL, then node is deleted.
   434    **
   435    ** If the node aready exists, the new data overwrites the old and
   436    ** the old data is returned.  If the node doesn't already exist, then
   437    ** a new node is created and the function returns NULL.
   438    */
   439  
   440    void *old;
   441    if( data==0 ){
   442      TreeElem *elem = TreeDeleteElem(tree, key);
   443      if( elem ){
   444        if( tree->xFree ){
   445          tree->xFree(elem->key);
   446        }
   447        old = elem->data;
   448        Tcl_Free((char *)elem);
   449      }else{
   450        old = 0;
   451      }
   452    }else{
   453      old = TreeInsertElement(tree,key,data);
   454    }
   455    return old;
   456  }
   457  
   458  my c_function {void *TreeChangeNth(Tree *tree, int n, void *data)} {
   459    /* Change the data on the n-th node of the tree.  The old data
   460    ** is returned.
   461    **
   462    ** If data==NULL, then the n-th node of the tree is deleted.  (The
   463    ** data associated with that node is still returned.)
   464    **
   465    ** If the value N is out-of-bounds, then no new node is created.
   466    ** Instead, the "data" parameter is returned.
   467    */
   468    void *old;
   469    if( data==0 ){
   470      TreeElem *elem = TreeDeleteNthElem(&tree->top,n);
   471      if( elem ){
   472        if( tree->xFree ){
   473          tree->xFree(elem->key);
   474        }
   475        old = elem->data;
   476        Tcl_Free((char *)elem);
   477      }else{
   478        old = 0;
   479      }
   480    }else{
   481      TreeElem *elem = TreeFindNthElem(tree,n);
   482      if( elem ){
   483        old = elem->data;
   484        elem->data = data;
   485      }else{
   486        old = data;
   487      }
   488    }
   489    return old;
   490  }