当前位置:   article > 正文

二叉查找树及其C语言实现详解_二叉树的查找c语言

二叉树的查找c语言

目录

一、树(Tree)

二、二叉树

1、概念

2、二叉树的存储方式

3、二叉树的遍历

三、二叉查找树

1、查找操作

2、插入操作

3、删除操作

4、修改操作

          5、节点清空和树销毁操作

四、支持重复数据的二叉查找树

1、每个节点存储多个对象数据

2、每个节点存储单个对象数据

五、二叉查找树C语言实现

1、数据结构

2、操作函数声明

3、具体实现

4、调试问题

、说明


一、树(Tree)

树是一种一种非线性表结构。如下图,A 节点就是 B 节点的父节点,B 节点是 A 节点的子节点。B、C、D 这三个节点的父节点是同一个节点,所以它们之间互称为兄弟节点。我们把没有父节点的节点叫作根节点,也就是图中的节点 E。我们把没有子节点的节点叫作叶子节点或者叶节点,比如图中的 G、H、I、J、K、L 都是叶子节点

 

  • 节点的高度(Height):节点到叶子节点的最长路径(边数),从下往上
  • 节点深度(Depth):根节点到这个节点的的最长路径(边数),从上往下
  • 节点的层(Level)数:节点的深度+1

数的高度:根节点的高度

二、二叉树

1、概念

每个节点最多只有2个子节点的树,这两个子节点分别为左子节点和右子节点。

满二叉树:叶子节点全部在最底层,除了叶子节点外,每个节点都有左右两个子节点

完全二叉树:叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大

2、二叉树的存储方式

基于链表的链式存储:每个节点需要额外的2个指针来存储左右节点地址

基于数组的顺序存储:每个节点不需要额外的子节点指针,左子节点存储在下标 2 * i 的位置,右子节点存储在 2 * i + 1的位置,i为节点的层数。但如果是非完全二叉树也会比较浪费空间。

3、二叉树的遍历

根据节点和他的左右节点遍历的先后顺序,可分为前序遍历、中序遍历、后续遍历

  • 前序遍历是指,对于树中的任意节点来说,先打印这个节点,然后再打印它的左子树,最后打印它的右子树。本身 ---> 左 ---> 右
  • 中序遍历是指,对于树中的任意节点来说,先打印它的左子树,然后再打印它本身,最后打印它的右子树。左 ---> 本身 ---> 右
  • 后序遍历是指,对于树中的任意节点来说,先打印它的左子树,然后再打印它的右子树,最后打印这个节点本身。 左 ---> 右 ---> 本身

三、二叉查找树

一种能够快速查找、插入、删除数据的特殊二叉树结构。二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值,非平衡的二叉树

1、查找操作

二叉查找树可以快速的查找最大节点和最小节点;按照中序遍历二叉查找树,可以输出有序的数据序列,时间复杂度为O(n),非常高效。

查找指定节点步骤:

第一步:先取根节点,如果根节点数据 = 要查找的数据,则直接返回,否则进入第二步

第二步:如果查找的数比根节点小,则在左子树中递归查找

第三部:如果查找的数比根节点大,则在右子数中递归查找

查找最小节点步骤:

遍历二叉树的左子树,直到左节点为NULL的节点即为最小节点

查找最大节点步骤:

遍历二叉树的右子树,直到右节点为NULL的节点即为最大节点

中序遍历步骤:

对于树中的任意节点来说,先拷贝它的左子树节点数据至双向链表中,然后再拷贝它本身节点数据双向链表中,最后拷贝它的右子树节点数据双向链表中。左 ---> 本身 ---> 右

 

2、插入操作

插入操作与查找过程类似,一般新插入的数据都是在叶子节点上;所以也是先取根节点

第一步:如果查找数据比节点数据大,且节点的右子节点为空,则将数据直接插入右子节点的位置;如果右子节点不为空,则再递归遍历右子数,查找插入位置。

第二步:如果查找数据比节点数据小,且节点的左子节点为空,则将数据直接插入左子节点的位置;如果左子节点不为空,则再递归遍历左子数,查找插入位置。

3、删除操作

先说明下:del为删除节点、f_del为删除节点的父节点、min为最小节点、f_min为最小节点的父节点

第一种情况:如果删除的节点没有子节点,只需要直接将删除节点父节点中,指向要删除的子节点(删除节点)置为空。如图中要删除的55

第二种情况:如果删除的节点只有一个子节点(只有左节点或只有右节点),则只需要更新删除节点的父节点中指向要删除节点的指针,让其指向要删除节点的子节点。如图中要删除的13,有4种细分情况:

1、del只有左节点,del为f_del的左节点,删除过程为:将f_del左节点指向del的左节点,再将del删除

2、del只有左节点,del为f_del的右节点,删除过程为:将f_del右节点指向del的左节点,再将del删除

3、del只有右节点,del为f_del的左节点,删除过程为:将f_del左节点指向del的右节点,再将del删除

4、del只有右节点,del为f_del的右节点,删除过程为:将f_del右节点指向del的右节点,再将del删除

第三种情况:如果删除的节点有两个子节点,则需要找到该节点的右子树中最小的节点,把他替换到要删除的节点上,然后删除这个最小节点。如图要删除的18,有有4种细分情况:

1、f_min就为del,min为叶子节点,删除过程为:先将min的数据替换到del,再将f_min的右节点指向min的右节点(NULL),最后删除min

2、f_min就为del,min还有右子树(不会再有左子树),删除过程为:先将min的数据替换到del,再将f_min的右节点指向min的右节点(!NULL),最后删除min

3、f_min不为del,min为叶子节点,删除过程为:先将min的数据替换到del,再将f_min的左节点指向min的右节点(NULL),最后删除min

4、f_min不为del,min还有右子树(不会再有左子树),删除过程为:先将min的数据替换到del,再将f_min的左节点指向min的右节点(!NULL),最后删除min

4、修改操作

修改操作与查找操作类似,在查找到相同key值的节点后,先释放节点指向的数据空间,然后修改节点数据。在修改过程中需要注意:

1、会先释放节点指向的就数据空间(这里如果是realloc更大的数据空间,容易造成指针泄露,且是不知道整个数据结构的大小的) 

2、修改的节点必须为新动态分配的空间

3、如果修改的节点有多个key值相同的节点,只会修改最新查找的一个

 

5、节点清空和树销毁操作

有的时候需要清空二叉树的所有节点保留树的句柄,再插入新的节点时不用再重新创建一颗新的树。或是不需要使用到树时时候需要释放所有内存,就需要将整颗树销毁,下次使用的时候再重新申请新的树。

使用递归的方法,可以将树的所有节点删除,递归的终止条件就是节点为空,递归公式为,递归查找到左子树和右子树均为空的树节点,先将该节点指向的数据删除(如果指向的数据为动态分配的需要在这里释放),再释放节点空间,最后将节点指向空(这里需要注意指针变量传参,如果要修改该指针变量的值即指针本身需要传入指针变量的地址,即使用双重指针才能!!!

 

 

四、支持重复数据的二叉查找树

在工程中使用二叉查找树时,用来存储单个数据的情况很少,多用来存储包含多个字段的对象,利用对象的某个字段作为key值来构建key-value的数据存储结构。在key-value的数据存储结构中,就不可避免的会有相同key值的情况,在插入新的节点时,如何存储相同key值的对象?大致有以下两种方法

1、每个节点存储多个对象数据

在二叉查找树的每一个节点使用链表来存储key值相同的对象,相对容易理解,但是这样的弊端就是二叉树的每个节点中至少需要多3个地址空间用来存储 链表的节点数据,比较浪费空间。

2、每个节点存储单个对象数据

在插入数据时,如果key值与二叉树的某个节点key值相同,则将数据插入到这个相同key值节点的右子树。与不支持重复数据二叉树插入操作相比,只需要将 > key值得节点插入到这个节点的右子数改为 >= 即可实现

 

在查找数据时,查找key值相同的节点后,并不停止查找,而是继续在右子树中查找,直到遇到叶子节点为止,然后将节点数据放入链表中,这样可以把key值相同的所有数据都找出来。

 

在删除数据时,删除节点只有左子树时则直接退出,因为没有右子树就不会有相同的key节点。删除节点右子树不为空 或 右子树节点为空但是key值相同 则继续查找相同key值的节点

 

 

五、二叉查找树C语言实现

1、数据结构

  1. #define BS_TREE_MALLOC(size) pvPortMalloc(size);
  2. #define BS_TREE_REALLOC(p,size) rt_realloc(p,size);
  3. #define BS_TREE_CALLOC(n,size) calloc(n,size);
  4. #define BS_TREE_FREE(p) vPortFree(p);
  5. struct bs_tree_node;
  6. struct bs_tree;
  7. /*
  8. * 二叉查找树key比较, key_cmp:传入的要比较的key, key_becmp:被比较的key
  9. * 任意一个节点,其左子树中任意一个节点的值,都要小于这个节点的值
  10. * 任意一个几点,其右子数中任意一个节点的值,都要大于这个节点的值
  11. * 返回值 > 0 : key_cmp > key_becmp
  12. * 返回值 = 0 : key_cmp = key_becmp
  13. * 返回值 < 0 : key_cmp < key_becmp
  14. */
  15. typedef int (*bstree_keycmp)(struct bs_tree *bstree, const void *key_cmp, const void *key_becmp);
  16. /* 二叉树中的节点数据删除函数,如果插入节点为动态分配,则需要在该函数中释放节点空间 */
  17. typedef int (*bstree_value_free)(struct bs_tree_node *node);
  18. struct bs_tree_node
  19. {
  20. void *key;
  21. void *value;
  22. struct bs_tree_node *left_child; /*左子树*/
  23. struct bs_tree_node *right_child; /*右子树*/
  24. };
  25. struct bs_tree
  26. {
  27. int num; /*二叉树中节点个数的总和*/
  28. struct bs_tree_node *root; /*二叉树的根节点*/
  29. bstree_keycmp keycmp; /*二叉树key比较*/
  30. bstree_value_free valuefree; /*二叉树节点数据删除*/
  31. };
  32. #define BSTREE_IS_EMPTY(tree) (tree->num == 0)
  33. /*根据当前结构体元素的地址,获取到结构体首地址*/
  34. //#define OFFSETOF(TYPE,MEMBER) ((unsigned int)&((TYPE *)0)->MEMBER)
  35. //#define container(ptr,type,member) ({\
  36. // const typeof( ((type *)0)->member) *__mptr = (ptr);\
  37. // (type *) ((char *)__mptr - OFFSETOF(type,member));})
  38. #define OFFSETOF(TYPE,MEMBER) ((unsigned int)&((TYPE *)0)->MEMBER)
  39. #define container(ptr,type,member) ((type *) ((char *)ptr - OFFSETOF(type,member)))

2、操作函数声明

  1. extern struct bs_tree *bs_tree_creat(bstree_keycmp keycmp, bstree_value_free valuefree);
  2. extern struct bs_tree *bs_tree_creat_default(bstree_value_free valuefree);
  3. extern int bs_tree_insert(struct bs_tree *bstree, void *key, void *value);
  4. extern int bs_tree_delete(struct bs_tree *bstree, void *key);
  5. extern int bs_tree_modify(struct bs_tree *bstree, void *key, void *value);
  6. extern int bs_tree_search(struct bs_tree *bstree, void *key, struct double_list *dlist);
  7. extern void * bs_tree_search_min(struct bs_tree *bstree);
  8. extern void * bs_tree_search_max(struct bs_tree *bstree);
  9. extern void bs_tree_node_empty(struct bs_tree **bstree, struct bs_tree_node **node);
  10. extern void bs_tree_destroy (struct bs_tree **bstree);
  11. /*中序遍历二叉树,并将节点数据放入双向链表中,链表在使用完释放空间的时候,不能将节点数据空间删除*/
  12. extern int bs_tree_inorder(struct bs_tree *bstree, struct bs_tree_node *node, struct double_list *dlist);
  13. extern void bs_tree_sample(void);

3、具体实现

  1. #include "algo_bs_tree.h"
  2. /**
  3. * 二叉树key比较, key_cmp:传入的要比较的key, key_becmp:被比较的key
  4. *
  5. * @return > 0 : key_cmp > key_becmp
  6. * @return = 0 : key_cmp = key_becmp
  7. * @return < 0 : key_cmp < key_becmp
  8. *
  9. */
  10. static int bstree_keycmp_default(struct bs_tree *bstree, const void *key_cmp, const void *key_becmp)
  11. {
  12. return strcmp(key_cmp, key_becmp);
  13. }
  14. /**
  15. * 动态创建一个二叉查找树.
  16. *
  17. * @return NULL:创建失败
  18. * !NULL:创建成功
  19. */
  20. struct bs_tree *bs_tree_creat(bstree_keycmp keycmp, bstree_value_free valuefree)
  21. {
  22. struct bs_tree *bstree = NULL;
  23. if (keycmp == NULL)
  24. return NULL;
  25. /*申请二叉查找树结构空间*/
  26. bstree = BS_TREE_MALLOC(sizeof(*bstree));
  27. if (bstree == NULL)
  28. return NULL;
  29. bstree->num = 0;
  30. bstree->keycmp = keycmp;
  31. bstree->valuefree = valuefree;
  32. bstree->root = NULL;
  33. return bstree;
  34. }
  35. /**
  36. * 使用默认 key比较函数 动态创建一个二叉查找树.
  37. *
  38. * @return NULL:创建失败
  39. * !NULL:创建成功
  40. */
  41. struct bs_tree *bs_tree_creat_default(bstree_value_free valuefree)
  42. {
  43. return bs_tree_creat(bstree_keycmp_default, valuefree);
  44. }
  45. /**
  46. * 向一个二叉查找树插入一个节点.支持相同key值的节点插入
  47. *
  48. * @param bstree: 二叉查找树
  49. * @param key: 关键值
  50. * @param value: 节点数据
  51. *
  52. * @return 0:插入成功
  53. * -1:二叉查找树不存在 或 key为空 或 value为空
  54. * -2:节点空间申请失败
  55. * -3:插入失败
  56. */
  57. int bs_tree_insert(struct bs_tree *bstree, void *key, void *value)
  58. {
  59. struct bs_tree_node *new_node = NULL;
  60. struct bs_tree_node *f_node = NULL;
  61. int res = 0;
  62. if (bstree == NULL || key == NULL || value == NULL)
  63. return -1;
  64. /*申请二叉查找树节点空间*/
  65. new_node = (struct bs_tree_node*)BS_TREE_MALLOC(sizeof(*new_node));
  66. if (new_node == NULL)
  67. return -2;
  68. new_node->key = key;
  69. new_node->value = value;
  70. new_node->left_child = NULL;
  71. new_node->right_child = NULL;
  72. /*数为空,插入到根节点*/
  73. if (BSTREE_IS_EMPTY(bstree))
  74. {
  75. bstree->root = new_node;
  76. bstree->num ++;
  77. return 0;
  78. }
  79. else
  80. {
  81. f_node = bstree->root;
  82. while (f_node != NULL)
  83. {
  84. res = bstree->keycmp(bstree, key, f_node->key);
  85. if (res >= 0) /*去右子树中查找,支持相同key值的节点插入*/
  86. {
  87. if (f_node->right_child == NULL)
  88. {
  89. f_node->right_child = new_node;
  90. bstree->num ++;
  91. return 0;
  92. }
  93. f_node = f_node->right_child;
  94. }
  95. else if (res < 0)/*去左子树中查找*/
  96. {
  97. if (f_node->left_child == NULL)
  98. {
  99. f_node->left_child = new_node;
  100. bstree->num ++;
  101. return 0;
  102. }
  103. f_node = f_node->left_child;
  104. }
  105. }
  106. }
  107. return -3;
  108. }
  109. /**
  110. * 删除一个节点.
  111. *
  112. * @param bstree: 二叉查找树
  113. * @param key: 删除节点关键值
  114. *
  115. * @return 0:删除成功
  116. * -1:二叉查找树不存在 或 key为空
  117. * -2:节点不存在
  118. */
  119. int bs_tree_delete(struct bs_tree *bstree, void *key)
  120. {
  121. struct bs_tree_node *del_node = NULL;//要删除节点
  122. struct bs_tree_node *f_delnode = NULL;//要删除节点的父节点
  123. struct bs_tree_node *minnode = NULL;//最小节点
  124. struct bs_tree_node *f_minnode = NULL;//最小节点的父节点
  125. struct bs_tree_node *temp = NULL;
  126. int finsh_flg = 0, res = 0;
  127. if (bstree == NULL || key == NULL)
  128. return -1;
  129. /*查找要删除的节点*/
  130. del_node = bstree->root;
  131. while ((del_node != NULL) && ((res = bstree->keycmp(bstree, key, del_node->key)) != 0))
  132. {
  133. f_delnode = del_node;
  134. if (res > 0)
  135. {
  136. del_node = del_node->right_child;
  137. }
  138. else
  139. {
  140. del_node = del_node->left_child;
  141. }
  142. }
  143. /*要删除的节点不存在*/
  144. if (del_node == NULL)
  145. return -2;
  146. do
  147. {
  148. if (bstree->keycmp(bstree, key, del_node->key) == 0)
  149. {
  150. /*如果删除的节点有两个子节点,则需要找到该节点的右子树中最小的节点,把他替换到要删除的节点上,然后删除这个最小节点
  151. *
  152. *1、f_min就为del,min为叶子节点,删除过程为:先将min的数据替换到del,再将f_min的右节点指向min的右节点(NULL),最后删除min
  153. *2、f_min就为del,min还有右子树(不会再有左子树),删除过程为:先将min的数据替换到del,再将f_min的右节点指向min的右节点(!NULL),最后删除min
  154. *3、f_min不为del,min为叶子节点,删除过程为:先将min的数据替换到del,再将f_min的左节点指向min的右节点(NULL),最后删除min
  155. *4、f_min不为del,min还有右子树(不会再有左子树),删除过程为:先将min的数据替换到del,再将f_min的左节点指向min的右节点(!NULL),最后删除min
  156. */
  157. if ((del_node->left_child != NULL) && (del_node->right_child != NULL))
  158. {
  159. f_minnode = del_node;
  160. minnode = del_node->right_child;
  161. while (minnode->left_child != NULL)//查找最小节点
  162. {
  163. f_minnode = minnode;
  164. minnode = minnode->left_child;
  165. }
  166. /*先删除要删除节点上的数据,数据空间为动态申请的需要在这里先释放*/
  167. bstree->valuefree(del_node);
  168. del_node->key = minnode->key;
  169. del_node->value = minnode->value;
  170. if (f_minnode == del_node)
  171. {
  172. f_minnode->right_child = minnode->right_child;
  173. }
  174. else
  175. {
  176. f_minnode->left_child = minnode->right_child;
  177. }
  178. /*交换最小节点和删除节点,因为真正删除的是最小节点,
  179. 删除节点的父节点的子节点还是删除节点*/
  180. temp = minnode;
  181. minnode = del_node;
  182. del_node = temp;
  183. }
  184. /*要删除的节点只有左子树*/
  185. else if (del_node->left_child != NULL)
  186. {
  187. /*先删除要删除节点上的数据,数据空间为动态申请的需要在这里先释放*/
  188. bstree->valuefree(del_node);
  189. minnode = del_node->left_child;
  190. finsh_flg = 1;
  191. }
  192. /*要删除的节点只有右子树*/
  193. else if (del_node->right_child != NULL)
  194. {
  195. /*先删除要删除节点上的数据,数据空间为动态申请的需要在这里先释放*/
  196. bstree->valuefree(del_node);
  197. minnode = del_node->right_child;
  198. }
  199. /*要删除节点没有子节点*/
  200. else
  201. {
  202. /*先删除要删除节点上的数据,数据空间为动态申请的需要在这里先释放*/
  203. bstree->valuefree(del_node);
  204. minnode->left_child = NULL;
  205. minnode->right_child = NULL;
  206. minnode = NULL;
  207. }
  208. if (del_node == bstree->root)//删除的是头结点
  209. {
  210. bstree->root = minnode;
  211. }
  212. else
  213. {
  214. if (del_node == f_delnode->left_child)//删除节点在删除节点父节点的左子树上
  215. {
  216. f_delnode->left_child = minnode;
  217. }
  218. else if (del_node == f_delnode->right_child)//删除节点在删除节点父节点的右子树上
  219. {
  220. f_delnode->right_child = minnode;
  221. }
  222. }
  223. BS_TREE_FREE(del_node);
  224. del_node = minnode;/*将删除节点指向填补的节点,继续判断删除节点的右子树是否还有相同key值的节点*/
  225. bstree->num --;
  226. }
  227. else
  228. {
  229. del_node = del_node->right_child;/*右子树不为空但key不相同*/
  230. }
  231. /*1、删除节点只有左子树时则直接退出,因为没有右子树就不会有相同的key节点
  232. 2、删除节点右子树不为空 或 右子树节点为空但是key值相同 则继续查找相同key值的节点
  233. */
  234. } while ( ((del_node->right_child != NULL) || ((del_node->right_child == NULL) && (bstree->keycmp(bstree, key, del_node->key) == 0))) && !finsh_flg);
  235. return 0;
  236. }
  237. /**
  238. * 修改一个节点.注意事项:
  239. * 1、会先释放节点指向的就数据空间(这里如果是realloc更大的数据空间,容易造成指针泄露,且是不知道整个数据结构的大小的)
  240. * 2、修改的节点必须为新动态分配的空间
  241. * 3、如果修改的节点有多个key值相同的节点,只会修改最新查找的一个
  242. *
  243. * @param bstree: 二叉查找树
  244. * @param key: 修改节点关键值
  245. * @param value: 修改节点数据
  246. *
  247. * @return 0:修改成功
  248. * -1:二叉查找树不存在 或 key为空 或value为空
  249. * -2:节点不存在
  250. */
  251. int bs_tree_modify(struct bs_tree *bstree, void *key, void *value)
  252. {
  253. struct bs_tree_node *mody_node = NULL;
  254. int res = -2;
  255. if (bstree == NULL || key == NULL || value == NULL)
  256. return -1;
  257. /*查找要修改的节点*/
  258. mody_node = bstree->root;
  259. while (mody_node != NULL)
  260. {
  261. res = bstree->keycmp(bstree, key, mody_node->key);
  262. if (res > 0)
  263. {
  264. mody_node = mody_node->right_child;
  265. }
  266. else if (res < 0)
  267. {
  268. mody_node = mody_node->left_child;
  269. }
  270. else
  271. {
  272. bstree->valuefree(mody_node);
  273. mody_node->key = key;
  274. mody_node->value = value;
  275. res = 0;
  276. break;
  277. }
  278. }
  279. return res;
  280. }
  281. /**
  282. * 根据key查找节点数据.
  283. *
  284. * @param bstree: 二叉查找树
  285. * @param key: 查找节点关键值
  286. *
  287. * @return 0:查找成功
  288. * -1:二叉查找树不存在 或 key为空 或value为空
  289. * -2:节点不存在
  290. */
  291. int bs_tree_search(struct bs_tree *bstree, void *key, struct double_list *dlist)
  292. {
  293. struct bs_tree_node *ser_node = NULL;
  294. int res = -2;
  295. if (bstree == NULL || key == NULL || BSTREE_IS_EMPTY(bstree))
  296. return -1;
  297. /*查找要查找的节点*/
  298. ser_node = bstree->root;
  299. while (ser_node != NULL)
  300. {
  301. res = bstree->keycmp(bstree, key, ser_node->key);
  302. if (res > 0)
  303. {
  304. ser_node = ser_node->right_child;
  305. }
  306. else if (res < 0)
  307. {
  308. ser_node = ser_node->left_child;
  309. }
  310. else
  311. {
  312. double_list_add_node_tail(dlist, ser_node->value);
  313. ser_node = ser_node->right_child;
  314. res = 0;
  315. }
  316. }
  317. return res;
  318. }
  319. /**
  320. * 查找二叉树中的最小节点数据.
  321. *
  322. * @param bstree: 二叉查找树
  323. *
  324. * @return 0:查找成功
  325. * -1:二叉查找树不存在 或 key为空 或value为空
  326. * -2:节点不存在
  327. */
  328. void * bs_tree_search_min(struct bs_tree *bstree)
  329. {
  330. struct bs_tree_node *ser_node = NULL;
  331. if (bstree == NULL || BSTREE_IS_EMPTY(bstree))
  332. return NULL;
  333. /*查找要查找的节点*/
  334. ser_node = bstree->root;
  335. while ((ser_node != NULL) && (ser_node->left_child != NULL))
  336. {
  337. ser_node = ser_node->left_child;
  338. }
  339. if (ser_node != NULL)
  340. {
  341. return ser_node->value;
  342. }
  343. return NULL;
  344. }
  345. /**
  346. * 查找二叉树中的最大节点数据.
  347. *
  348. * @param bstree: 二叉查找树
  349. *
  350. * @return 0:查找成功
  351. * -1:二叉查找树不存在 或 key为空 或value为空
  352. * -2:节点不存在
  353. */
  354. void * bs_tree_search_max(struct bs_tree *bstree)
  355. {
  356. struct bs_tree_node *ser_node = NULL;
  357. if (bstree == NULL || BSTREE_IS_EMPTY(bstree))
  358. return NULL;
  359. /*查找要查找的节点*/
  360. ser_node = bstree->root;
  361. while ((ser_node != NULL) && (ser_node->right_child != NULL))
  362. {
  363. ser_node = ser_node->right_child;
  364. }
  365. if (ser_node != NULL)
  366. {
  367. return ser_node->value;
  368. }
  369. return NULL;
  370. }
  371. /**
  372. * 中序遍历二叉树,并将节点数据放入双向链表中
  373. *
  374. * @param bstree: 二叉查找树
  375. *
  376. * @return NULL:查找失败
  377. * !NULL:查找成功.返回节点数据
  378. */
  379. int bs_tree_inorder(struct bs_tree *bstree, struct bs_tree_node *node, struct double_list *dlist)
  380. {
  381. if (bstree == NULL || BSTREE_IS_EMPTY(bstree))
  382. return NULL;
  383. if (node == NULL)
  384. {
  385. return NULL;
  386. }
  387. bs_tree_inorder(bstree, node->left_child, dlist);
  388. double_list_add_node_tail(dlist, node->value);
  389. bs_tree_inorder(bstree, node->right_child, dlist);
  390. return dlist->len;
  391. }
  392. ///**
  393. // * 清空二叉树节点数据
  394. // *
  395. // * @param bstree: 二叉查找树
  396. // *
  397. // * @return
  398. // */
  399. //void bs_tree_node_empty(struct bs_tree *bstree, struct bs_tree_node *node)
  400. //{
  401. // if (bstree == NULL || BSTREE_IS_EMPTY(bstree))
  402. // return;
  403. // if (node == NULL)
  404. // {
  405. // return;
  406. // }
  407. // bs_tree_node_empty(bstree, node->left_child);
  408. // bs_tree_node_empty(bstree, node->right_child);
  409. // bstree->valuefree(node);
  410. // BS_TREE_FREE(node);
  411. // node = NULL;
  412. bstree->num--;
  413. //}
  414. ///**
  415. // * 销毁一颗二叉查找树
  416. // *
  417. // * @param bstree: 二叉查找树
  418. // *
  419. // * @return
  420. // */
  421. //void bs_tree_destroy(struct bs_tree *bstree)
  422. //{
  423. // bs_tree_node_empty(bstree, bstree->root);
  424. // BS_TREE_FREE(bstree);
  425. //}
  426. /**
  427. * 清空二叉树节点数据
  428. *
  429. * @param bstree: 二叉查找树
  430. *
  431. * @return
  432. */
  433. void bs_tree_node_empty(struct bs_tree **bstree, struct bs_tree_node **node)
  434. {
  435. if (*bstree == NULL || BSTREE_IS_EMPTY((*bstree)))
  436. return;
  437. if (*node == NULL)
  438. {
  439. return;
  440. }
  441. bs_tree_node_empty(bstree, &(*node)->left_child);
  442. bs_tree_node_empty(bstree, &(*node)->right_child);
  443. (*bstree)->valuefree(*node);
  444. (*bstree)->num--;
  445. BS_TREE_FREE(*node);
  446. *node = NULL;
  447. }
  448. /**
  449. * 销毁一颗二叉查找树
  450. *
  451. * @param bstree: 二叉查找树
  452. *
  453. * @return
  454. */
  455. void bs_tree_destroy(struct bs_tree **bstree)
  456. {
  457. bs_tree_node_empty(bstree, &(*bstree)->root);
  458. BS_TREE_FREE(*bstree);
  459. *bstree = NULL;
  460. }
  461. /*******************************************************************************************
  462. * 使用示例
  463. *******************************************************************************************/
  464. struct test_node
  465. {
  466. char key[10];
  467. char value[10];
  468. };
  469. static int node_value_free_sample(struct bs_tree_node *node)
  470. {
  471. struct test_node *node_temp = NULL;
  472. /*根据key在test_node结构体中的偏移地址,找到二叉查找树节点实际指向的结构体首地址*/
  473. node_temp = container(node->key, struct test_node, key);
  474. /*如果节点所指向数据空间为动态申请的则需要释放*/
  475. BS_TREE_FREE(node_temp);
  476. /*将二叉树中指向这块内存的节点key 和 value 赋为空*/
  477. node->key = NULL;
  478. node->value = NULL;
  479. return 0;
  480. }
  481. struct bs_tree *bs_tree_test = NULL;
  482. char tree_node_read[10][10];
  483. struct double_list *dlist_test = NULL;
  484. void bs_tree_sample(void)
  485. {
  486. int i = 0, j = 0, key[10] = {0};
  487. struct test_node *node_temp = NULL;
  488. char rd_key[10] = {10}, del_key[10] = {0};
  489. struct double_list_node *dlist_node = NULL;
  490. bs_tree_test = bs_tree_creat_default(node_value_free_sample);
  491. dlist_test = double_list_creat();
  492. for (i=0; i<10; i++)
  493. {
  494. key[i] = rand() % 10;
  495. }
  496. /*插入 -- 查询*/
  497. for (i=0; i<10; i++)
  498. {
  499. node_temp = BS_TREE_MALLOC(sizeof(*node_temp));
  500. memset(node_temp, 0, sizeof(*node_temp));
  501. sprintf(node_temp->key, "AAA%d", key[i]);
  502. sprintf(node_temp->value, "%d", key[i]);
  503. bs_tree_insert(bs_tree_test, node_temp->key, node_temp->value);//支持多个节点插入
  504. }
  505. for (i=0; i<10; i++)
  506. {
  507. memset(tree_node_read[i], 0, 10);
  508. memset(rd_key, 0, sizeof(rd_key));
  509. sprintf(rd_key, "AAA%d", key[i]);
  510. bs_tree_search(bs_tree_test, rd_key, dlist_test);//相同key值的数据会被放入双向链表中
  511. dlist_node = dlist_test->head;
  512. for (j=0; j<dlist_test->len; j++)//相同key值的节点数据
  513. {
  514. memcpy(tree_node_read[j], dlist_node->value, 10);
  515. dlist_node = dlist_node->next;
  516. }
  517. double_list_node_empty(dlist_test, 0);//清空双向链表节点
  518. }
  519. /*中序遍历*/
  520. bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);
  521. dlist_node = dlist_test->head;
  522. for (i=0; i<dlist_test->len; i++)
  523. {
  524. memcpy(tree_node_read[i], dlist_node->value, 10);
  525. dlist_node = dlist_node->next;
  526. }
  527. double_list_node_empty(dlist_test, 0);
  528. /*清空 -- 插入 -- 查询*/
  529. bs_tree_node_empty(&bs_tree_test, &(bs_tree_test)->root);
  530. for (i=0; i<10; i++)
  531. {
  532. node_temp = BS_TREE_MALLOC(sizeof(*node_temp));
  533. memset(node_temp, 0, sizeof(*node_temp));
  534. sprintf(node_temp->key, "AAA%d", key[i]);
  535. sprintf(node_temp->value, "%d", key[i] + 10);
  536. bs_tree_insert(bs_tree_test, node_temp->key, node_temp->value);
  537. }
  538. for (i=0; i<10; i++)
  539. {
  540. memset(tree_node_read[i], 0, 10);
  541. memset(rd_key, 0, sizeof(rd_key));
  542. sprintf(rd_key, "AAA%d", key[i]);
  543. bs_tree_search(bs_tree_test, rd_key, dlist_test);//相同key值的数据会被放入双向链表中
  544. dlist_node = dlist_test->head;
  545. for (j=0; j<dlist_test->len; j++)//相同key值的节点数据
  546. {
  547. memcpy(tree_node_read[j], dlist_node->value, 10);
  548. dlist_node = dlist_node->next;
  549. }
  550. double_list_node_empty(dlist_test, 0);//清空双向链表节点
  551. }
  552. /*中序遍历*/
  553. bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);
  554. dlist_node = dlist_test->head;
  555. for (i=0; i<dlist_test->len; i++)
  556. {
  557. memcpy(tree_node_read[i], dlist_node->value, 10);
  558. dlist_node = dlist_node->next;
  559. }
  560. double_list_node_empty(dlist_test, 0);
  561. /*修改 -- 查询*/
  562. for (i=0; i<10; i++)
  563. {
  564. node_temp = BS_TREE_MALLOC(sizeof(*node_temp));
  565. memset(node_temp, 0, sizeof(*node_temp));
  566. sprintf(node_temp->key, "AAA%d", key[i]);
  567. sprintf(node_temp->value, "%d", key[i] + 20);
  568. bs_tree_modify(bs_tree_test, node_temp->key, node_temp->value);
  569. }
  570. for (i=0; i<10; i++)
  571. {
  572. memset(tree_node_read[i], 0, 10);
  573. memset(rd_key, 0, sizeof(rd_key));
  574. sprintf(rd_key, "AAA%d", key[i]);
  575. bs_tree_search(bs_tree_test, rd_key, dlist_test);//相同key值的数据会被放入双向链表中
  576. dlist_node = dlist_test->head;
  577. for (j=0; j<dlist_test->len; j++)//相同key值的节点数据
  578. {
  579. memcpy(tree_node_read[j], dlist_node->value, 10);
  580. dlist_node = dlist_node->next;
  581. }
  582. double_list_node_empty(dlist_test, 0);//清空双向链表节点
  583. }
  584. /*中序遍历*/
  585. bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);
  586. dlist_node = dlist_test->head;
  587. for (i=0; i<dlist_test->len; i++)
  588. {
  589. memcpy(tree_node_read[i], dlist_node->value, 10);
  590. dlist_node = dlist_node->next;
  591. }
  592. double_list_node_empty(dlist_test, 0);
  593. /*删除 -- 查询*/
  594. sprintf(del_key, "AAA%d", key[0]);
  595. bs_tree_delete(bs_tree_test, del_key);
  596. for (i=0; i<10; i++)
  597. {
  598. memset(tree_node_read[i], 0, 10);
  599. }
  600. bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);/*中序遍历*/
  601. dlist_node = dlist_test->head;
  602. for (i=0; i<dlist_test->len; i++)
  603. {
  604. memcpy(tree_node_read[i], dlist_node->value, 10);
  605. dlist_node = dlist_node->next;
  606. }
  607. double_list_node_empty(dlist_test, 0);
  608. /*删除 -- 查询*/
  609. sprintf(del_key, "AAA%d", key[1]);
  610. bs_tree_delete(bs_tree_test, del_key);
  611. for (i=0; i<10; i++)
  612. {
  613. memset(tree_node_read[i], 0, 10);
  614. }
  615. bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);/*中序遍历*/
  616. dlist_node = dlist_test->head;
  617. for (i=0; i<dlist_test->len; i++)
  618. {
  619. memcpy(tree_node_read[i], dlist_node->value, 10);
  620. dlist_node = dlist_node->next;
  621. }
  622. double_list_node_empty(dlist_test, 0);
  623. /*删除 -- 查询*/
  624. sprintf(del_key, "AAA%d", key[2]);
  625. bs_tree_delete(bs_tree_test, del_key);
  626. for (i=0; i<10; i++)
  627. {
  628. memset(tree_node_read[i], 0, 10);
  629. }
  630. bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);/*中序遍历*/
  631. dlist_node = dlist_test->head;
  632. for (i=0; i<dlist_test->len; i++)
  633. {
  634. memcpy(tree_node_read[i], dlist_node->value, 10);
  635. dlist_node = dlist_node->next;
  636. }
  637. double_list_node_empty(dlist_test, 0);
  638. /*释放二叉树 和 双向链表结构*/
  639. double_list_destroy(dlist_test, 0);
  640. bs_tree_destroy(&bs_tree_test);
  641. }

4、调试问题

1、逻辑判断的运算符优先级要比赋值运算符优先级高

正确写法:while((del_node != NULL)&&((res = bstree->keycmp(bstree, key, del_node->key)) != 0))

错误写法:while ((del_node != NULL) && (res = bstree->keycmp(bstree, key, del_node->key) != 0))

2、指针变量传参时,如果要修改该指针变量的值即指针本身需要传入指针变量的地址,即使用双重指针才能。如本文中的 二叉树节点清空和二叉树销毁

 

六、说明

本文部分内容(图片与部分文字)为学习王争老师在极客时间专栏——《数据结构与算法之美》的学习总结。仅仅是个人学习备忘,如有侵犯权益,请联系我,立即修改。

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号