赞
踩
目录
六、说明
树是一种一种非线性表结构。如下图,A 节点就是 B 节点的父节点,B 节点是 A 节点的子节点。B、C、D 这三个节点的父节点是同一个节点,所以它们之间互称为兄弟节点。我们把没有父节点的节点叫作根节点,也就是图中的节点 E。我们把没有子节点的节点叫作叶子节点或者叶节点,比如图中的 G、H、I、J、K、L 都是叶子节点
数的高度:根节点的高度
每个节点最多只有2个子节点的树,这两个子节点分别为左子节点和右子节点。
满二叉树:叶子节点全部在最底层,除了叶子节点外,每个节点都有左右两个子节点
完全二叉树:叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大
基于链表的链式存储:每个节点需要额外的2个指针来存储左右节点地址
基于数组的顺序存储:每个节点不需要额外的子节点指针,左子节点存储在下标 2 * i 的位置,右子节点存储在 2 * i + 1的位置,i为节点的层数。但如果是非完全二叉树也会比较浪费空间。
根据节点和他的左右节点遍历的先后顺序,可分为前序遍历、中序遍历、后续遍历
一种能够快速查找、插入、删除数据的特殊二叉树结构。二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值,非平衡的二叉树
二叉查找树可以快速的查找最大节点和最小节点;按照中序遍历二叉查找树,可以输出有序的数据序列,时间复杂度为O(n),非常高效。
查找指定节点步骤:
第一步:先取根节点,如果根节点数据 = 要查找的数据,则直接返回,否则进入第二步
第二步:如果查找的数比根节点小,则在左子树中递归查找
第三部:如果查找的数比根节点大,则在右子数中递归查找
查找最小节点步骤:
遍历二叉树的左子树,直到左节点为NULL的节点即为最小节点
查找最大节点步骤:
遍历二叉树的右子树,直到右节点为NULL的节点即为最大节点
中序遍历步骤:
对于树中的任意节点来说,先拷贝它的左子树节点数据至双向链表中,然后再拷贝它本身节点数据双向链表中,最后拷贝它的右子树节点数据双向链表中。左 ---> 本身 ---> 右
插入操作与查找过程类似,一般新插入的数据都是在叶子节点上;所以也是先取根节点
第一步:如果查找数据比节点数据大,且节点的右子节点为空,则将数据直接插入右子节点的位置;如果右子节点不为空,则再递归遍历右子数,查找插入位置。
第二步:如果查找数据比节点数据小,且节点的左子节点为空,则将数据直接插入左子节点的位置;如果左子节点不为空,则再递归遍历左子数,查找插入位置。
先说明下: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
修改操作与查找操作类似,在查找到相同key值的节点后,先释放节点指向的数据空间,然后修改节点数据。在修改过程中需要注意:
1、会先释放节点指向的就数据空间(这里如果是realloc更大的数据空间,容易造成指针泄露,且是不知道整个数据结构的大小的)
2、修改的节点必须为新动态分配的空间
3、如果修改的节点有多个key值相同的节点,只会修改最新查找的一个
有的时候需要清空二叉树的所有节点保留树的句柄,再插入新的节点时不用再重新创建一颗新的树。或是不需要使用到树时时候需要释放所有内存,就需要将整颗树销毁,下次使用的时候再重新申请新的树。
使用递归的方法,可以将树的所有节点删除,递归的终止条件就是节点为空,递归公式为,递归查找到左子树和右子树均为空的树节点,先将该节点指向的数据删除(如果指向的数据为动态分配的需要在这里释放),再释放节点空间,最后将节点指向空(这里需要注意指针变量传参,如果要修改该指针变量的值即指针本身需要传入指针变量的地址,即使用双重指针才能!!!)
在工程中使用二叉查找树时,用来存储单个数据的情况很少,多用来存储包含多个字段的对象,利用对象的某个字段作为key值来构建key-value的数据存储结构。在key-value的数据存储结构中,就不可避免的会有相同key值的情况,在插入新的节点时,如何存储相同key值的对象?大致有以下两种方法
在二叉查找树的每一个节点使用链表来存储key值相同的对象,相对容易理解,但是这样的弊端就是二叉树的每个节点中至少需要多3个地址空间用来存储 链表的节点数据,比较浪费空间。
在插入数据时,如果key值与二叉树的某个节点key值相同,则将数据插入到这个相同key值节点的右子树。与不支持重复数据二叉树插入操作相比,只需要将 > key值得节点插入到这个节点的右子数改为 >= 即可实现
在查找数据时,查找key值相同的节点后,并不停止查找,而是继续在右子树中查找,直到遇到叶子节点为止,然后将节点数据放入链表中,这样可以把key值相同的所有数据都找出来。
在删除数据时,删除节点只有左子树时则直接退出,因为没有右子树就不会有相同的key节点。删除节点右子树不为空 或 右子树节点为空但是key值相同 则继续查找相同key值的节点
- #define BS_TREE_MALLOC(size) pvPortMalloc(size);
- #define BS_TREE_REALLOC(p,size) rt_realloc(p,size);
- #define BS_TREE_CALLOC(n,size) calloc(n,size);
- #define BS_TREE_FREE(p) vPortFree(p);
-
- struct bs_tree_node;
- struct bs_tree;
-
- /*
- * 二叉查找树key比较, key_cmp:传入的要比较的key, key_becmp:被比较的key
- * 任意一个节点,其左子树中任意一个节点的值,都要小于这个节点的值
- * 任意一个几点,其右子数中任意一个节点的值,都要大于这个节点的值
- * 返回值 > 0 : key_cmp > key_becmp
- * 返回值 = 0 : key_cmp = key_becmp
- * 返回值 < 0 : key_cmp < key_becmp
- */
- typedef int (*bstree_keycmp)(struct bs_tree *bstree, const void *key_cmp, const void *key_becmp);
- /* 二叉树中的节点数据删除函数,如果插入节点为动态分配,则需要在该函数中释放节点空间 */
- typedef int (*bstree_value_free)(struct bs_tree_node *node);
-
- struct bs_tree_node
- {
- void *key;
- void *value;
- struct bs_tree_node *left_child; /*左子树*/
- struct bs_tree_node *right_child; /*右子树*/
- };
-
- struct bs_tree
- {
- int num; /*二叉树中节点个数的总和*/
- struct bs_tree_node *root; /*二叉树的根节点*/
- bstree_keycmp keycmp; /*二叉树key比较*/
- bstree_value_free valuefree; /*二叉树节点数据删除*/
- };
-
- #define BSTREE_IS_EMPTY(tree) (tree->num == 0)
-
- /*根据当前结构体元素的地址,获取到结构体首地址*/
- //#define OFFSETOF(TYPE,MEMBER) ((unsigned int)&((TYPE *)0)->MEMBER)
- //#define container(ptr,type,member) ({\
- // const typeof( ((type *)0)->member) *__mptr = (ptr);\
- // (type *) ((char *)__mptr - OFFSETOF(type,member));})
-
- #define OFFSETOF(TYPE,MEMBER) ((unsigned int)&((TYPE *)0)->MEMBER)
- #define container(ptr,type,member) ((type *) ((char *)ptr - OFFSETOF(type,member)))

- extern struct bs_tree *bs_tree_creat(bstree_keycmp keycmp, bstree_value_free valuefree);
- extern struct bs_tree *bs_tree_creat_default(bstree_value_free valuefree);
- extern int bs_tree_insert(struct bs_tree *bstree, void *key, void *value);
- extern int bs_tree_delete(struct bs_tree *bstree, void *key);
- extern int bs_tree_modify(struct bs_tree *bstree, void *key, void *value);
- extern int bs_tree_search(struct bs_tree *bstree, void *key, struct double_list *dlist);
- extern void * bs_tree_search_min(struct bs_tree *bstree);
- extern void * bs_tree_search_max(struct bs_tree *bstree);
- extern void bs_tree_node_empty(struct bs_tree **bstree, struct bs_tree_node **node);
- extern void bs_tree_destroy (struct bs_tree **bstree);
-
- /*中序遍历二叉树,并将节点数据放入双向链表中,链表在使用完释放空间的时候,不能将节点数据空间删除*/
- extern int bs_tree_inorder(struct bs_tree *bstree, struct bs_tree_node *node, struct double_list *dlist);
-
- extern void bs_tree_sample(void);
- #include "algo_bs_tree.h"
-
-
- /**
- * 二叉树key比较, key_cmp:传入的要比较的key, key_becmp:被比较的key
- *
- * @return > 0 : key_cmp > key_becmp
- * @return = 0 : key_cmp = key_becmp
- * @return < 0 : key_cmp < key_becmp
- *
- */
- static int bstree_keycmp_default(struct bs_tree *bstree, const void *key_cmp, const void *key_becmp)
- {
- return strcmp(key_cmp, key_becmp);
- }
-
- /**
- * 动态创建一个二叉查找树.
- *
- * @return NULL:创建失败
- * !NULL:创建成功
- */
- struct bs_tree *bs_tree_creat(bstree_keycmp keycmp, bstree_value_free valuefree)
- {
- struct bs_tree *bstree = NULL;
-
- if (keycmp == NULL)
- return NULL;
-
- /*申请二叉查找树结构空间*/
- bstree = BS_TREE_MALLOC(sizeof(*bstree));
- if (bstree == NULL)
- return NULL;
-
- bstree->num = 0;
- bstree->keycmp = keycmp;
- bstree->valuefree = valuefree;
- bstree->root = NULL;
-
- return bstree;
- }
-
- /**
- * 使用默认 key比较函数 动态创建一个二叉查找树.
- *
- * @return NULL:创建失败
- * !NULL:创建成功
- */
- struct bs_tree *bs_tree_creat_default(bstree_value_free valuefree)
- {
- return bs_tree_creat(bstree_keycmp_default, valuefree);
- }
-
-
- /**
- * 向一个二叉查找树插入一个节点.支持相同key值的节点插入
- *
- * @param bstree: 二叉查找树
- * @param key: 关键值
- * @param value: 节点数据
- *
- * @return 0:插入成功
- * -1:二叉查找树不存在 或 key为空 或 value为空
- * -2:节点空间申请失败
- * -3:插入失败
- */
- int bs_tree_insert(struct bs_tree *bstree, void *key, void *value)
- {
- struct bs_tree_node *new_node = NULL;
- struct bs_tree_node *f_node = NULL;
- int res = 0;
-
- if (bstree == NULL || key == NULL || value == NULL)
- return -1;
-
- /*申请二叉查找树节点空间*/
- new_node = (struct bs_tree_node*)BS_TREE_MALLOC(sizeof(*new_node));
- if (new_node == NULL)
- return -2;
-
- new_node->key = key;
- new_node->value = value;
- new_node->left_child = NULL;
- new_node->right_child = NULL;
-
- /*数为空,插入到根节点*/
- if (BSTREE_IS_EMPTY(bstree))
- {
- bstree->root = new_node;
- bstree->num ++;
- return 0;
- }
- else
- {
- f_node = bstree->root;
- while (f_node != NULL)
- {
- res = bstree->keycmp(bstree, key, f_node->key);
- if (res >= 0) /*去右子树中查找,支持相同key值的节点插入*/
- {
- if (f_node->right_child == NULL)
- {
- f_node->right_child = new_node;
- bstree->num ++;
- return 0;
- }
- f_node = f_node->right_child;
- }
- else if (res < 0)/*去左子树中查找*/
- {
- if (f_node->left_child == NULL)
- {
- f_node->left_child = new_node;
- bstree->num ++;
- return 0;
- }
- f_node = f_node->left_child;
- }
- }
- }
-
- return -3;
- }
-
-
- /**
- * 删除一个节点.
- *
- * @param bstree: 二叉查找树
- * @param key: 删除节点关键值
- *
- * @return 0:删除成功
- * -1:二叉查找树不存在 或 key为空
- * -2:节点不存在
- */
- int bs_tree_delete(struct bs_tree *bstree, void *key)
- {
- struct bs_tree_node *del_node = NULL;//要删除节点
- struct bs_tree_node *f_delnode = NULL;//要删除节点的父节点
- struct bs_tree_node *minnode = NULL;//最小节点
- struct bs_tree_node *f_minnode = NULL;//最小节点的父节点
- struct bs_tree_node *temp = NULL;
- int finsh_flg = 0, res = 0;
-
- if (bstree == NULL || key == NULL)
- return -1;
-
- /*查找要删除的节点*/
- del_node = bstree->root;
- while ((del_node != NULL) && ((res = bstree->keycmp(bstree, key, del_node->key)) != 0))
- {
- f_delnode = del_node;
- if (res > 0)
- {
- del_node = del_node->right_child;
- }
- else
- {
- del_node = del_node->left_child;
- }
- }
-
- /*要删除的节点不存在*/
- if (del_node == NULL)
- return -2;
-
- do
- {
- if (bstree->keycmp(bstree, key, del_node->key) == 0)
- {
- /*如果删除的节点有两个子节点,则需要找到该节点的右子树中最小的节点,把他替换到要删除的节点上,然后删除这个最小节点
- *
- *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
- */
- if ((del_node->left_child != NULL) && (del_node->right_child != NULL))
- {
- f_minnode = del_node;
- minnode = del_node->right_child;
- while (minnode->left_child != NULL)//查找最小节点
- {
- f_minnode = minnode;
- minnode = minnode->left_child;
- }
-
- /*先删除要删除节点上的数据,数据空间为动态申请的需要在这里先释放*/
- bstree->valuefree(del_node);
-
- del_node->key = minnode->key;
- del_node->value = minnode->value;
- if (f_minnode == del_node)
- {
- f_minnode->right_child = minnode->right_child;
- }
- else
- {
- f_minnode->left_child = minnode->right_child;
- }
-
- /*交换最小节点和删除节点,因为真正删除的是最小节点,
- 删除节点的父节点的子节点还是删除节点*/
- temp = minnode;
- minnode = del_node;
- del_node = temp;
- }
- /*要删除的节点只有左子树*/
- else if (del_node->left_child != NULL)
- {
- /*先删除要删除节点上的数据,数据空间为动态申请的需要在这里先释放*/
- bstree->valuefree(del_node);
-
- minnode = del_node->left_child;
-
- finsh_flg = 1;
- }
- /*要删除的节点只有右子树*/
- else if (del_node->right_child != NULL)
- {
- /*先删除要删除节点上的数据,数据空间为动态申请的需要在这里先释放*/
- bstree->valuefree(del_node);
-
- minnode = del_node->right_child;
- }
- /*要删除节点没有子节点*/
- else
- {
- /*先删除要删除节点上的数据,数据空间为动态申请的需要在这里先释放*/
- bstree->valuefree(del_node);
-
- minnode->left_child = NULL;
- minnode->right_child = NULL;
- minnode = NULL;
- }
-
- if (del_node == bstree->root)//删除的是头结点
- {
- bstree->root = minnode;
- }
- else
- {
- if (del_node == f_delnode->left_child)//删除节点在删除节点父节点的左子树上
- {
- f_delnode->left_child = minnode;
- }
- else if (del_node == f_delnode->right_child)//删除节点在删除节点父节点的右子树上
- {
- f_delnode->right_child = minnode;
- }
- }
-
- BS_TREE_FREE(del_node);
- del_node = minnode;/*将删除节点指向填补的节点,继续判断删除节点的右子树是否还有相同key值的节点*/
-
- bstree->num --;
- }
- else
- {
- del_node = del_node->right_child;/*右子树不为空但key不相同*/
- }
-
- /*1、删除节点只有左子树时则直接退出,因为没有右子树就不会有相同的key节点
- 2、删除节点右子树不为空 或 右子树节点为空但是key值相同 则继续查找相同key值的节点
- */
- } while ( ((del_node->right_child != NULL) || ((del_node->right_child == NULL) && (bstree->keycmp(bstree, key, del_node->key) == 0))) && !finsh_flg);
-
- return 0;
- }
-
- /**
- * 修改一个节点.注意事项:
- * 1、会先释放节点指向的就数据空间(这里如果是realloc更大的数据空间,容易造成指针泄露,且是不知道整个数据结构的大小的)
- * 2、修改的节点必须为新动态分配的空间
- * 3、如果修改的节点有多个key值相同的节点,只会修改最新查找的一个
- *
- * @param bstree: 二叉查找树
- * @param key: 修改节点关键值
- * @param value: 修改节点数据
- *
- * @return 0:修改成功
- * -1:二叉查找树不存在 或 key为空 或value为空
- * -2:节点不存在
- */
- int bs_tree_modify(struct bs_tree *bstree, void *key, void *value)
- {
- struct bs_tree_node *mody_node = NULL;
- int res = -2;
-
- if (bstree == NULL || key == NULL || value == NULL)
- return -1;
-
- /*查找要修改的节点*/
- mody_node = bstree->root;
- while (mody_node != NULL)
- {
- res = bstree->keycmp(bstree, key, mody_node->key);
- if (res > 0)
- {
- mody_node = mody_node->right_child;
- }
- else if (res < 0)
- {
- mody_node = mody_node->left_child;
- }
- else
- {
- bstree->valuefree(mody_node);
- mody_node->key = key;
- mody_node->value = value;
- res = 0;
- break;
- }
- }
-
- return res;
- }
-
- /**
- * 根据key查找节点数据.
- *
- * @param bstree: 二叉查找树
- * @param key: 查找节点关键值
- *
- * @return 0:查找成功
- * -1:二叉查找树不存在 或 key为空 或value为空
- * -2:节点不存在
- */
- int bs_tree_search(struct bs_tree *bstree, void *key, struct double_list *dlist)
- {
- struct bs_tree_node *ser_node = NULL;
- int res = -2;
-
- if (bstree == NULL || key == NULL || BSTREE_IS_EMPTY(bstree))
- return -1;
-
- /*查找要查找的节点*/
- ser_node = bstree->root;
- while (ser_node != NULL)
- {
- res = bstree->keycmp(bstree, key, ser_node->key);
- if (res > 0)
- {
- ser_node = ser_node->right_child;
- }
- else if (res < 0)
- {
- ser_node = ser_node->left_child;
- }
- else
- {
- double_list_add_node_tail(dlist, ser_node->value);
- ser_node = ser_node->right_child;
- res = 0;
- }
- }
-
- return res;
- }
-
- /**
- * 查找二叉树中的最小节点数据.
- *
- * @param bstree: 二叉查找树
- *
- * @return 0:查找成功
- * -1:二叉查找树不存在 或 key为空 或value为空
- * -2:节点不存在
- */
- void * bs_tree_search_min(struct bs_tree *bstree)
- {
- struct bs_tree_node *ser_node = NULL;
-
- if (bstree == NULL || BSTREE_IS_EMPTY(bstree))
- return NULL;
-
- /*查找要查找的节点*/
- ser_node = bstree->root;
- while ((ser_node != NULL) && (ser_node->left_child != NULL))
- {
- ser_node = ser_node->left_child;
- }
-
- if (ser_node != NULL)
- {
- return ser_node->value;
- }
-
- return NULL;
- }
-
- /**
- * 查找二叉树中的最大节点数据.
- *
- * @param bstree: 二叉查找树
- *
- * @return 0:查找成功
- * -1:二叉查找树不存在 或 key为空 或value为空
- * -2:节点不存在
- */
- void * bs_tree_search_max(struct bs_tree *bstree)
- {
- struct bs_tree_node *ser_node = NULL;
-
- if (bstree == NULL || BSTREE_IS_EMPTY(bstree))
- return NULL;
-
- /*查找要查找的节点*/
- ser_node = bstree->root;
- while ((ser_node != NULL) && (ser_node->right_child != NULL))
- {
- ser_node = ser_node->right_child;
- }
-
- if (ser_node != NULL)
- {
- return ser_node->value;
- }
-
- return NULL;
- }
-
- /**
- * 中序遍历二叉树,并将节点数据放入双向链表中
- *
- * @param bstree: 二叉查找树
- *
- * @return NULL:查找失败
- * !NULL:查找成功.返回节点数据
- */
- int bs_tree_inorder(struct bs_tree *bstree, struct bs_tree_node *node, struct double_list *dlist)
- {
- if (bstree == NULL || BSTREE_IS_EMPTY(bstree))
- return NULL;
-
- if (node == NULL)
- {
- return NULL;
- }
-
- bs_tree_inorder(bstree, node->left_child, dlist);
- double_list_add_node_tail(dlist, node->value);
- bs_tree_inorder(bstree, node->right_child, dlist);
-
- return dlist->len;
- }
-
- ///**
- // * 清空二叉树节点数据
- // *
- // * @param bstree: 二叉查找树
- // *
- // * @return
- // */
- //void bs_tree_node_empty(struct bs_tree *bstree, struct bs_tree_node *node)
- //{
- // if (bstree == NULL || BSTREE_IS_EMPTY(bstree))
- // return;
-
- // if (node == NULL)
- // {
- // return;
- // }
-
- // bs_tree_node_empty(bstree, node->left_child);
- // bs_tree_node_empty(bstree, node->right_child);
- // bstree->valuefree(node);
- // BS_TREE_FREE(node);
- // node = NULL;
- bstree->num--;
- //}
-
- ///**
- // * 销毁一颗二叉查找树
- // *
- // * @param bstree: 二叉查找树
- // *
- // * @return
- // */
- //void bs_tree_destroy(struct bs_tree *bstree)
- //{
- // bs_tree_node_empty(bstree, bstree->root);
- // BS_TREE_FREE(bstree);
- //}
-
- /**
- * 清空二叉树节点数据
- *
- * @param bstree: 二叉查找树
- *
- * @return
- */
- void bs_tree_node_empty(struct bs_tree **bstree, struct bs_tree_node **node)
- {
- if (*bstree == NULL || BSTREE_IS_EMPTY((*bstree)))
- return;
-
- if (*node == NULL)
- {
- return;
- }
-
- bs_tree_node_empty(bstree, &(*node)->left_child);
- bs_tree_node_empty(bstree, &(*node)->right_child);
- (*bstree)->valuefree(*node);
- (*bstree)->num--;
- BS_TREE_FREE(*node);
- *node = NULL;
- }
-
- /**
- * 销毁一颗二叉查找树
- *
- * @param bstree: 二叉查找树
- *
- * @return
- */
- void bs_tree_destroy(struct bs_tree **bstree)
- {
- bs_tree_node_empty(bstree, &(*bstree)->root);
- BS_TREE_FREE(*bstree);
- *bstree = NULL;
- }
-
- /*******************************************************************************************
- * 使用示例
- *******************************************************************************************/
- struct test_node
- {
- char key[10];
- char value[10];
- };
-
- static int node_value_free_sample(struct bs_tree_node *node)
- {
- struct test_node *node_temp = NULL;
-
- /*根据key在test_node结构体中的偏移地址,找到二叉查找树节点实际指向的结构体首地址*/
- node_temp = container(node->key, struct test_node, key);
- /*如果节点所指向数据空间为动态申请的则需要释放*/
- BS_TREE_FREE(node_temp);
- /*将二叉树中指向这块内存的节点key 和 value 赋为空*/
- node->key = NULL;
- node->value = NULL;
-
- return 0;
- }
-
-
- struct bs_tree *bs_tree_test = NULL;
- char tree_node_read[10][10];
- struct double_list *dlist_test = NULL;
-
- void bs_tree_sample(void)
- {
- int i = 0, j = 0, key[10] = {0};
- struct test_node *node_temp = NULL;
- char rd_key[10] = {10}, del_key[10] = {0};
- struct double_list_node *dlist_node = NULL;
-
- bs_tree_test = bs_tree_creat_default(node_value_free_sample);
- dlist_test = double_list_creat();
-
- for (i=0; i<10; i++)
- {
- key[i] = rand() % 10;
- }
-
- /*插入 -- 查询*/
- for (i=0; i<10; i++)
- {
- node_temp = BS_TREE_MALLOC(sizeof(*node_temp));
- memset(node_temp, 0, sizeof(*node_temp));
- sprintf(node_temp->key, "AAA%d", key[i]);
- sprintf(node_temp->value, "%d", key[i]);
- bs_tree_insert(bs_tree_test, node_temp->key, node_temp->value);//支持多个节点插入
- }
- for (i=0; i<10; i++)
- {
- memset(tree_node_read[i], 0, 10);
- memset(rd_key, 0, sizeof(rd_key));
- sprintf(rd_key, "AAA%d", key[i]);
-
- bs_tree_search(bs_tree_test, rd_key, dlist_test);//相同key值的数据会被放入双向链表中
- dlist_node = dlist_test->head;
- for (j=0; j<dlist_test->len; j++)//相同key值的节点数据
- {
- memcpy(tree_node_read[j], dlist_node->value, 10);
- dlist_node = dlist_node->next;
- }
- double_list_node_empty(dlist_test, 0);//清空双向链表节点
- }
-
- /*中序遍历*/
- bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);
- dlist_node = dlist_test->head;
- for (i=0; i<dlist_test->len; i++)
- {
- memcpy(tree_node_read[i], dlist_node->value, 10);
- dlist_node = dlist_node->next;
- }
- double_list_node_empty(dlist_test, 0);
-
-
-
- /*清空 -- 插入 -- 查询*/
- bs_tree_node_empty(&bs_tree_test, &(bs_tree_test)->root);
- for (i=0; i<10; i++)
- {
- node_temp = BS_TREE_MALLOC(sizeof(*node_temp));
- memset(node_temp, 0, sizeof(*node_temp));
- sprintf(node_temp->key, "AAA%d", key[i]);
- sprintf(node_temp->value, "%d", key[i] + 10);
- bs_tree_insert(bs_tree_test, node_temp->key, node_temp->value);
- }
- for (i=0; i<10; i++)
- {
- memset(tree_node_read[i], 0, 10);
- memset(rd_key, 0, sizeof(rd_key));
- sprintf(rd_key, "AAA%d", key[i]);
-
- bs_tree_search(bs_tree_test, rd_key, dlist_test);//相同key值的数据会被放入双向链表中
- dlist_node = dlist_test->head;
- for (j=0; j<dlist_test->len; j++)//相同key值的节点数据
- {
- memcpy(tree_node_read[j], dlist_node->value, 10);
- dlist_node = dlist_node->next;
- }
- double_list_node_empty(dlist_test, 0);//清空双向链表节点
- }
- /*中序遍历*/
- bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);
- dlist_node = dlist_test->head;
- for (i=0; i<dlist_test->len; i++)
- {
- memcpy(tree_node_read[i], dlist_node->value, 10);
- dlist_node = dlist_node->next;
- }
- double_list_node_empty(dlist_test, 0);
-
-
-
- /*修改 -- 查询*/
- for (i=0; i<10; i++)
- {
- node_temp = BS_TREE_MALLOC(sizeof(*node_temp));
- memset(node_temp, 0, sizeof(*node_temp));
- sprintf(node_temp->key, "AAA%d", key[i]);
- sprintf(node_temp->value, "%d", key[i] + 20);
- bs_tree_modify(bs_tree_test, node_temp->key, node_temp->value);
- }
- for (i=0; i<10; i++)
- {
- memset(tree_node_read[i], 0, 10);
- memset(rd_key, 0, sizeof(rd_key));
- sprintf(rd_key, "AAA%d", key[i]);
-
- bs_tree_search(bs_tree_test, rd_key, dlist_test);//相同key值的数据会被放入双向链表中
- dlist_node = dlist_test->head;
- for (j=0; j<dlist_test->len; j++)//相同key值的节点数据
- {
- memcpy(tree_node_read[j], dlist_node->value, 10);
- dlist_node = dlist_node->next;
- }
- double_list_node_empty(dlist_test, 0);//清空双向链表节点
- }
-
- /*中序遍历*/
- bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);
- dlist_node = dlist_test->head;
- for (i=0; i<dlist_test->len; i++)
- {
- memcpy(tree_node_read[i], dlist_node->value, 10);
- dlist_node = dlist_node->next;
- }
- double_list_node_empty(dlist_test, 0);
-
-
-
-
-
- /*删除 -- 查询*/
- sprintf(del_key, "AAA%d", key[0]);
- bs_tree_delete(bs_tree_test, del_key);
- for (i=0; i<10; i++)
- {
- memset(tree_node_read[i], 0, 10);
- }
- bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);/*中序遍历*/
- dlist_node = dlist_test->head;
- for (i=0; i<dlist_test->len; i++)
- {
- memcpy(tree_node_read[i], dlist_node->value, 10);
- dlist_node = dlist_node->next;
- }
- double_list_node_empty(dlist_test, 0);
- /*删除 -- 查询*/
- sprintf(del_key, "AAA%d", key[1]);
- bs_tree_delete(bs_tree_test, del_key);
- for (i=0; i<10; i++)
- {
- memset(tree_node_read[i], 0, 10);
- }
- bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);/*中序遍历*/
- dlist_node = dlist_test->head;
- for (i=0; i<dlist_test->len; i++)
- {
- memcpy(tree_node_read[i], dlist_node->value, 10);
- dlist_node = dlist_node->next;
- }
- double_list_node_empty(dlist_test, 0);
- /*删除 -- 查询*/
- sprintf(del_key, "AAA%d", key[2]);
- bs_tree_delete(bs_tree_test, del_key);
- for (i=0; i<10; i++)
- {
- memset(tree_node_read[i], 0, 10);
- }
- bs_tree_inorder(bs_tree_test, bs_tree_test->root, dlist_test);/*中序遍历*/
- dlist_node = dlist_test->head;
- for (i=0; i<dlist_test->len; i++)
- {
- memcpy(tree_node_read[i], dlist_node->value, 10);
- dlist_node = dlist_node->next;
- }
- double_list_node_empty(dlist_test, 0);
-
-
- /*释放二叉树 和 双向链表结构*/
- double_list_destroy(dlist_test, 0);
- bs_tree_destroy(&bs_tree_test);
- }

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、指针变量传参时,如果要修改该指针变量的值即指针本身需要传入指针变量的地址,即使用双重指针才能。如本文中的 二叉树节点清空和二叉树销毁
本文部分内容(图片与部分文字)为学习王争老师在极客时间专栏——《数据结构与算法之美》的学习总结。仅仅是个人学习备忘,如有侵犯权益,请联系我,立即修改。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。