TREE.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:14k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /****************************** Module Header *******************************
  11. * Module Name: TREE.C
  12. *
  13. * Functions supporting an unbalanced binary tree.
  14. *
  15. * Functions:
  16. *
  17. * tree_delitem()
  18. * tree_newitem()
  19. * tree_getitem()
  20. * tree_create()
  21. * tree_delete()
  22. * tree_update()
  23. * tree_find()
  24. * tree_search()
  25. * tree_addafter()
  26. * ctree_create()
  27. * ctree_delete()
  28. * ctree_update()
  29. * ctree_getcount()
  30. * ctree_find()
  31. *
  32. * Comments:
  33. *
  34. * TREE is a data type providing a map between a KEY and a VALUE. The KEY is a
  35. * 32-bit DWORD, and the VALUE is any arbitrary area of storage.
  36. *
  37. * Mmemory is allocated from gmem_get, using hHeap as the heap handle.
  38. * hHeap must be declared and initialised elsewhere.
  39. *
  40. * Currently implemented as a unbalanced binary tree.
  41. *
  42. ****************************************************************************/
  43. #include <windows.h>
  44. #include <stdlib.h>
  45. #include <memory.h>
  46. #include "gutils.h"
  47. #include "tree.h"
  48. /* -- data types ----------------------------------------------- */
  49. /* on creating a tree, we return a TREE handle. This is in fact a pointer
  50.  * to a struct tree, defined here.
  51.  */
  52. struct tree {
  53.         HANDLE hHeap;
  54.         TREEITEM first;
  55. };
  56. /* each element in the tree is stored in a TREEITEM. a TREEITEM handle
  57.  * is a pointer to a struct treeitem, defined here
  58.  */
  59. struct treeitem {
  60.         TREE root;
  61.         TREEKEY key;
  62.         TREEITEM left, right;
  63.         UINT length;            /* length of the user's data */
  64.         LPVOID data;            /* pointer to our copy of the users data */
  65. };
  66. /***************************************************************************
  67.  * Function: tree_delitems
  68.  *
  69.  * Purpose:
  70.  *
  71.  * Free up an element of the tree. Recursively calls itself to
  72.  * free left and right children
  73.  */
  74. void
  75. tree_delitem(TREEITEM item)
  76. {
  77.         if (item == NULL) {
  78.                 return;
  79.         }
  80.         if (item->left != NULL) {
  81.                 tree_delitem(item->left);
  82.         }
  83.         if (item->right != NULL) {
  84.                 tree_delitem(item->right);
  85.         }
  86.         if (item->data != NULL) {
  87.                 gmem_free(item->root->hHeap, item->data, item->length);
  88.         }
  89.         gmem_free(item->root->hHeap, (LPSTR) item, sizeof(struct treeitem));
  90. }
  91. /***************************************************************************
  92.  * Function: tree_newitem
  93.  *
  94.  * Purpose:
  95.  *
  96.  * Creates a new treeitem, with a data block of length bytes.
  97.  * If the value pointer is not NULL, initialise the data block with
  98.  * the contents of value.
  99.  */
  100. TREEITEM
  101. tree_newitem(TREE root, TREEKEY key, LPVOID value, UINT length)
  102. {
  103.         TREEITEM item;
  104.         item = (TREEITEM) gmem_get(root->hHeap, sizeof(struct treeitem));
  105.         item->root = root;
  106.         item->key = key;
  107.         item->left = NULL;
  108.         item->right = NULL;
  109.         item->length = length;
  110.         item->data = gmem_get(root->hHeap, length);
  111.         if (value != NULL) {
  112.                 memcpy(item->data, value, length);
  113.         }
  114.         return(item);
  115. }
  116. /***************************************************************************
  117.  * Function: tree_getitem
  118.  *
  119.  * Purpose:
  120.  *
  121.  * Finds the item with the given key. If it does not exist, return
  122.  * the parent item to which it would be attached. Returns NULL if
  123.  * no items in the tree
  124.  */
  125. TREEITEM
  126. tree_getitem(TREE tree, TREEKEY key)
  127. {
  128.         TREEITEM item, prev;
  129.         prev = NULL;
  130.         for (item = tree->first; item != NULL; ) {
  131.                 
  132.                 if (item->key == key) {
  133.                         return(item);
  134.                 }
  135.                 /* not this item - go on to the correct child item.
  136.                  * remember this item as if the child is NULL, this item
  137.                  * will be the correct insertion point for the new item
  138.                  */
  139.                 prev = item;
  140.                 if (key < item->key) {
  141.                         item = item->left;
  142.                 } else {
  143.                         item = item->right;
  144.                 }
  145.         }       
  146.         /* prev is the parent - or null if nothing in tree */
  147.         return(prev);
  148. }
  149. /***************************************************************************
  150.  * Function: tree_create
  151.  *
  152.  * Purpose:
  153.  *
  154.  * Creates an empty tree. hHeap is the handle to use for all
  155.  * memory allocations for this tree.
  156.  */
  157. TREE APIENTRY
  158. tree_create(HANDLE hHeap)
  159. {
  160.         TREE tree;
  161.         tree = (TREE) gmem_get(hHeap, sizeof(struct tree));
  162.         tree->first = NULL;
  163.         tree->hHeap = hHeap;
  164.         return(tree);
  165. }
  166. /***************************************************************************
  167.  * Function: tree_delete
  168.  *
  169.  * Purpose:
  170.  *
  171.  * Deletes an entire tree, including all the user data
  172.  */
  173. void APIENTRY
  174. tree_delete(TREE tree)
  175. {
  176.         tree_delitem(tree->first);
  177.         gmem_free(tree->hHeap, (LPSTR) tree, sizeof(struct tree));
  178. }
  179. /***************************************************************************
  180.  * Function: tree_update
  181.  *
  182.  * Purpose:
  183.  *
  184.  * Adds a new element to the tree, mapping the key given to the value given.
  185.  * The value is a block of storage: a copy of this is inserted into the tree.
  186.  * We return a pointer to the copy of the data in the tree.
  187.  *
  188.  * The value pointer can be NULL: in this case, we insert a block of
  189.  * length bytes, but don't initialise it. You get a pointer to it and
  190.  * can initialise it yourself.
  191.  *
  192.  * If the key already exists, the value will be replaced with the new data.
  193.  */
  194. LPVOID APIENTRY
  195. tree_update(TREE tree, TREEKEY key, LPVOID value, UINT length)
  196. {
  197.         TREEITEM item;
  198.         /* find the place in the tree for this key to go */
  199.         item = tree_getitem(tree, key);
  200.         if (item == NULL) {
  201.                 /* there is nothing in the tree: this item should
  202.                  * go at the top
  203.                  */
  204.                 tree->first = tree_newitem(tree, key, value, length);
  205.                 return(tree->first->data);
  206.         }
  207.         /* is this the same key ? */
  208.         if (item->key == key) {
  209.                 /* this key already inserted. re-alloc the data */
  210.                 if (length != item->length) {
  211.                         gmem_free(tree->hHeap, item->data, item->length);
  212.                         item->data = gmem_get(tree->hHeap, length);
  213.                 }
  214.                 /* don't initialise block if no pointer passed */
  215.                 if (value != NULL) {
  216.                         memcpy(item->data, value, length);
  217.                 }
  218.                 return(item->data);
  219.         }
  220.         /* not the same key - getitem returned the parent for
  221.          * the new tree. insert it as a child of item.
  222.          */
  223.         return(tree_addafter(tree, &item, key, value, length));
  224. }
  225. /***************************************************************************
  226.  * Function: tree_find
  227.  *
  228.  * Purpose:
  229.  *
  230.  * Returns a pointer to the value (data block) for a given key. Returns
  231.  * null if not found.
  232.  */
  233. LPVOID APIENTRY
  234. tree_find(TREE tree, TREEKEY key)
  235. {
  236.         TREEITEM item;
  237.         /* find the correct place in the tree */
  238.         item = tree_getitem(tree, key);
  239.         if (item == NULL) {
  240.                 /* nothing in the tree */
  241.                 return(NULL);
  242.         }
  243.         if (item->key != key) {
  244.                 /* this key not in. getitem has returned parent */
  245.                 return(NULL);
  246.         }
  247.         /* found the right element - return pointer to the
  248.          * data block
  249.          */
  250.         return(item->data);
  251. }
  252. /* The next two routines are an optimisation for a common tree operation. In
  253.  * this case, the user will want to insert a new element only if
  254.  * the key is not there. If it is there, he will want to modify the
  255.  * existing value (increment a reference count, for example).
  256.  *
  257.  * If tree_search fails to find the key, it will return a TREEITEM handle
  258.  * for the parent. This can be passed to tree_addafter to insert the
  259.  * new element without re-searching the tree.
  260.  */
  261. /***************************************************************************
  262.  * Function: tree_search
  263.  *
  264.  * Purpose:
  265.  *
  266.  * Find an element. If not, find it's correct parent item
  267.  */
  268. LPVOID APIENTRY
  269. tree_search(TREE tree, TREEKEY key, PTREEITEM pplace)
  270. {
  271.         TREEITEM item;
  272.         item = tree_getitem(tree, key);
  273.         if (item == NULL) {
  274.                 /* no items in tree. set placeholder to NULL to
  275.                  * indicate insert at top of tree
  276.                  */
  277.                 *pplace = NULL;         
  278.                 /* return NULL to indicate key not found */
  279.                 return(NULL);
  280.         }
  281.         if (item->key == key) {
  282.                 /* found the key already there -
  283.                  * set pplace to null just for safety
  284.                  */
  285.                 *pplace = NULL;
  286.                 /* give the user a pointer to his data */
  287.                 return(item->data);
  288.         }
  289.         /* key was not found - getitem has returned the parent
  290.          * - set this as the place for new insertions
  291.          */
  292.         *pplace = item;         
  293.         /* return NULL to indicate that the key was not found */
  294.         return(NULL);
  295. }
  296. /***************************************************************************
  297.  * Function: tree_addafter
  298.  *
  299.  * Purpose:
  300.  *
  301.  * Insert a key in the position already found by tree_search.
  302.  *
  303.  * Return a pointer to the user's data in the tree. If the value
  304.  * pointer passed in is null, then we allocate the block, but don't
  305.  * initialise it to anything.
  306.  */
  307. LPVOID APIENTRY
  308. tree_addafter(TREE tree, PTREEITEM place, TREEKEY key, LPVOID value, UINT length)
  309. {
  310.         TREEITEM item, child;
  311.         item = *place;
  312.         if (item == NULL) {
  313.                 tree->first = tree_newitem(tree, key, value, length);
  314.                 return (tree->first->data);
  315.         }               
  316.         child = tree_newitem(tree, key, value, length);         
  317.         if (child->key < item->key ) {
  318.                 /* should go on left leg */
  319.                 item->left = child;
  320.         } else {        
  321.                 item->right = child;
  322.         }
  323.         return(child->data);
  324. }
  325. /* --- ctree ------------------------------------------------------*/
  326. /*
  327.  * ctree is a class of tree built on top of the tree interface. a
  328.  * ctree keeps count of the number of insertions of identical keys.
  329.  *
  330.  * We do this be adding a long counter to the beginning of the user
  331.  * data before inserting into the tree. If the key is not found, we set
  332.  * this to one. If the key was already there, we *do not* insert the
  333.  * data (data is always from the first insertion) - we simply increment
  334.  * the count.
  335.  */
  336. /* Create a tree for use by CTREE - same as an ordinary tree
  337.  */
  338. TREE APIENTRY
  339. ctree_create(HANDLE hHeap)
  340. {
  341.         return(tree_create(hHeap));
  342. }
  343. /*
  344.  * Delete a ctree - same as for TREE
  345.  */
  346. void APIENTRY
  347. ctree_delete(TREE tree)
  348. {
  349.         tree_delete(tree);
  350. }
  351. /***************************************************************************
  352.  * Function: ctree_update
  353.  *
  354.  * Purpose:
  355.  *
  356.  * Insert an element in the tree. If the element is not there,
  357.  * insert the data and set the reference count for this key to 1.
  358.  * If the key was there already, don't change the data, just increment
  359.  * the reference count
  360.  *
  361.  * If the value pointer is not null, we initialise the value block
  362.  * in the tree to contain this.
  363.  *
  364.  * We return a pointer to the users data in the tree
  365.  */
  366. LPVOID APIENTRY
  367. ctree_update(TREE tree, TREEKEY key, LPVOID value, UINT length)
  368. {
  369.         TREEITEM item;
  370.         long FAR * pcounter;
  371.         LPVOID datacopy;
  372.         pcounter = tree_search(tree, key, &item);
  373.         if (pcounter == NULL) {
  374.                 /* element not found - insert a new one
  375.                  * the data block for this element should be
  376.                  * the user's block with our reference count at
  377.                  * the beginning
  378.                  */
  379.                 pcounter = tree_addafter(tree, &item, key, NULL,
  380.                                 length + sizeof(long));
  381.                 *pcounter = 1;
  382.                 /* add on size of one long to get the start of the user
  383.                  * data
  384.                  */
  385.                 datacopy = pcounter + 1;
  386.                 if (value != NULL) {
  387.                         memcpy(datacopy, value, length);
  388.                 }
  389.                 return(datacopy);
  390.         }
  391.         /* key was already there - increment reference count and
  392.          * return pointer to data
  393.          */
  394.         (*pcounter)++;
  395.         /* add on size of one long to get the start of the user
  396.          * data
  397.          */
  398.         datacopy = pcounter + 1;
  399.         return(datacopy);
  400. }
  401. /***************************************************************************
  402.  * Function: ctree_getcount
  403.  *
  404.  * Purpose:
  405.  *
  406.  * Return the reference count for this key 
  407.  */
  408. long APIENTRY
  409. ctree_getcount(TREE tree, TREEKEY key)
  410. {
  411.         long FAR * pcounter;
  412.         pcounter = tree_find(tree, key);
  413.         if (pcounter == NULL) {
  414.                 return(0);
  415.         }
  416.         return(*pcounter);
  417. }
  418. /***************************************************************************
  419.  * Function: ctree_find
  420.  *
  421.  * Purpose:
  422.  *
  423.  * Return a pointer to the user's data block for this key,
  424.  * or NULL if key not present
  425.  */
  426. LPVOID APIENTRY
  427. ctree_find(TREE tree, TREEKEY key)
  428. {
  429.         long FAR * pcounter;
  430.         pcounter = tree_find(tree, key);
  431.         if (pcounter == NULL) {
  432.                 return(0);
  433.         }
  434.         /* increment pointer by size of 1 long to point to
  435.          * user's datablock
  436.          */
  437.         return(pcounter+1);
  438. }