static void btree_push(struct btree_info *info, struct bnode_info *node) { assert(info != NULL); assert(node != NULL); bnode_init(node); // 1. 是否为空树 if (info->root == NULL) { info->root = node; return ; } // 2.非空树 struct bnode_info **pparent = &info->root; struct bnode_info *cur = NULL; while (*pparent != NULL) { cur = *pparent; if (info->cmp(node, cur) >= 0) { pparent = &cur->rchild; } else { pparent = &cur->lchild; } } *pparent = node; node->parent = cur; }
bnode* bnode_create(void* k,void* v,int kS,int vS,bnode* p,bnode* l,bnode* r){ bnode* node = malloc(sizeof(bnode)); if(!node){return NULL;} node->key = malloc(kS); node->value = malloc(vS); if(!node->key || !node->value){ free(node->key); free(node->value); return NULL; } if(k){memcpy(node->key,k,kS);} else{node->key = 0;} if(v){memcpy(node->value,v,vS);} else{node->value = NULL;} bnode_init(node,node->key,node->value,kS,vS,p,l,r); return node; }
//第2个参数是要删除的节点的小结构体的地址 static inline void del_node(struct btree *btree, struct bnode *bnode) { //树上的节点的身份 enum e_id { ROOT, LCHILD, RCHILD, } id; if (!bnode->parent) { //是否树根节点 id = ROOT; } else if (bnode->parent->lchild == bnode) { //是否是其父亲节点的左孩子 id = LCHILD; } else if (bnode->parent->rchild == bnode) { //是否是其父亲节点的右孩子 id = RCHILD; } if (!bnode->lchild && !bnode->rchild) { //如果要删除的节点是叶子节点 printf("ok\n"); switch (id) { case ROOT: btree->root = NULL; break; case LCHILD: printf("ok1\n"); bnode->parent->lchild = NULL; bnode->parent = NULL; break; case RCHILD: printf("ok2\n"); bnode->parent->rchild = NULL; bnode->parent = NULL; break; } } else if (bnode->lchild && !bnode->rchild) { //如果要删除的节点有左孩子,没有右孩子 switch (id) { case ROOT: bnode->lchild->parent = NULL; btree->root = bnode->lchild; //bnode->parent->lchild = bnode->lchild; break; case LCHILD: bnode->lchild->parent = bnode->parent; bnode->parent->lchild = bnode->lchild; bnode_init(bnode); break; case RCHILD: bnode->lchild->parent = bnode->parent; bnode->parent->rchild = bnode->lchild; bnode_init(bnode); break; } } else if (!bnode->lchild && bnode->rchild) { //如果要删除的节点有右孩子,没有左孩子 switch (id) { case ROOT: bnode->rchild->parent = NULL; btree->root = bnode->rchild; break; case LCHILD: bnode->rchild->parent = bnode->parent; bnode->parent->lchild = bnode->rchild; bnode_init(bnode); break; case RCHILD: bnode->rchild->parent = bnode->parent; bnode->parent->rchild = bnode->rchild; bnode_init(bnode); break; } } else { //如果要删除的节点两个孩子都存在 //找到一个能顶替删除节点的节点来取代要删除的节点,可以找这样的两个节点之一: //1、要删除节点的左孩子的最右边的孩子(其实就是找要删除节点的左子树中值最大的节点) //2、要删除节点的右孩子的最左边的孩子(其实就是找要删除节点的右子树中值最小的节点) //下面的代码以1来做: //定位到要删除节点的顶替节点 struct bnode *cur = bnode->lchild; while (cur->rchild) { cur = cur->rchild; } //判断能顶替要删除的节点是其父亲节点的左孩子还是右孩子 if (cur == cur->parent->lchild) { //是左孩子 cur->parent->lchild = cur->lchild; } else { //是右孩子 cur->parent->rchild = cur->lchild; } if (cur->lchild) { //cur的左孩子是否存在 cur->lchild->parent = cur->parent; } switch (id) { case ROOT: btree->root = cur; break; case LCHILD: bnode->parent->lchild = cur; break; case RCHILD: bnode->parent->rchild = cur; break; } //cur接收所有要删除节点bnode的所有关系 cur->parent = bnode->parent; cur->lchild = bnode->lchild; cur->rchild = bnode->rchild; if (cur->lchild) { cur->lchild->parent = cur; } if (cur->rchild) { //其实这个判断条件可以不要,因为既然要删除的节点必定是有两个孩子的,我们选择的能顶替它(要删除的节点)的节点是它左(要删除节点)孩子的最右边的孩子,假如它的左孩子没有右孩子,那么它的左孩子就是能顶替它的节点,如果该节点没有左孩子,那么上面的第230行如果不判断,231行就会出现段错误。但右孩子之所以不用判断,是因为它现在接收的右孩子就是要删除节点的右孩子(该右孩子必定存在,否则我们要删除的节点就不是有两个孩子的节点)。 cur->rchild->parent = cur; } } bnode_init(bnode); //初始化要删除的节点,使其不再指向之前所指向的节点 }