c++(排序二叉树删除)
相比较节点的添加,平衡二叉树的删除要复杂一些。因为在删除的过程中,你要考虑到不同的情况,针对每一种不同的情况,你要有针对性的反应和调整。所以在代码编写的过程中,我们可以一边写代码,一边写测试用例。编写测试用例不光可以验证我们编写的代码是否正确,还能不断提高我们开发代码的自信心。这样,即使我们在开发过程对代码进行修改或者优化也不会担心害怕。然而看起来编写测试用例是一个繁杂的过程,但是从长期的收益来看,编写测试用例的成本是非常低廉的。
在排序二叉树的删除过程当中,我们应该怎么做呢?大家不用担心,只要按照我们下面的介绍一步一步往下做就可以了,大体上分为下面三个步骤:
1)判断参数的合法性,判断参数是否在当前的二叉树当中
2)删除的节点是根节点,此时应该怎么调整
3)删除的节点是普通节点,此时又应该怎么调整
闲话不多说,下面看看我们的代码是怎么设计的?
1、判断参数的合法性,同时判断当前的二叉树是否含有相关数据
1.1 判断输入参数是否合法
STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{
if(NULL == ppTreeNode || NULL == *ppTreeNode)
return FALSE;
return TRUE;
}
那么此时测试用例怎么写呢?
static void test1()
{
TREE_NODE* pTreeNode = NULL;
assert(FALSE == delete_node_from_tree(NULL, 10));
assert(FALSE == delete_node_from_tree(&pTreeNode, 10));
}
注: 上面的测试用例说明当指针为空或者指针的指针为空,函数返回FALSE。
1.2 判断输入数据是否存在
STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{
TREE_NODE* pTreeNode; if(NULL == ppTreeNode || NULL == *ppTreeNode)
return FALSE; pTreeNode = find_data_in_tree_node(*ppTreeNode, data);
if(NULL == pTreeNode)
return FALSE; return TRUE;
}
此时,我们设计一种当前指针合法,但是删除数据不存在的测试用例。
static void test2()
{
TREE_NODE* pTreeNode = NULL;
pTreeNode = create_tree_node(10);
assert(FALSE == delete_node_from_tree(&pTreeNode, 11));
free(pTreeNode);
}
注: 上面的测试用例根节点为10,但是删除的数据为11,单步跟踪,验证我们编写的代码是否正确。
2、删除的数据是根节点数据
2.1 删除根数据时,根节点没有左子树,没有右子树情形
/*
*
* 10 ======> NULL
* / \
* NULL NULL
*/
那么此时代码应该怎么写呢?我们可以试一试。
STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{
TREE_NODE* pTreeNode; if(NULL == ppTreeNode || NULL == *ppTreeNode)
return FALSE; pTreeNode = find_data_in_tree_node(*ppTreeNode, data);
if(NULL == pTreeNode)
return FALSE; if(*ppTreeNode == pTreeNode){
if(NULL == pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = NULL;
} free(pTreeNode);
return TRUE;
} return TRUE;
}
我们的代码明显越来越长,我们要保持耐心。此时,该是我们添加新测试用例的时候了。
static void test3()
{
TREE_NODE* pTreeNode = NULL;
pTreeNode = create_tree_node(10);
assert(TRUE == delete_node_from_tree(&pTreeNode, 10));
assert(NULL == pTreeNode);
}
2.2 删除根数据时,只有左子树节点,没有右子树节点
/*
*
* 10 ======> 5
* / \ / \
* 5 NULL 3 NULL
* /
* 3
*/
很明显,我们只需要把用左子树节点代替原来的根节点即可。
STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{
TREE_NODE* pTreeNode; if(NULL == ppTreeNode || NULL == *ppTreeNode)
return FALSE; pTreeNode = find_data_in_tree_node(*ppTreeNode, data);
if(NULL == pTreeNode)
return FALSE; if(*ppTreeNode == pTreeNode){
if(NULL == pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = NULL;
}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = pTreeNode->left_child;
pTreeNode->left_child->parent = NULL;
} free(pTreeNode);
return TRUE;
} return TRUE;
}
这个时候,我们可以添加新的测试用例,分别添加10、5、3,然后删除10。
static void test4()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 5));
assert(TRUE == insert_node_into_tree(&pTreeNode, 3));
assert(TRUE == delete_node_from_tree(&pTreeNode, 10));
assert(5 == pTreeNode->data);
assert(NULL == pTreeNode->parent);
free(pTreeNode->left_child);
free(pTreeNode);
}
2.3 删除根数据时,没有左子树节点,只有右子树节点
/*
*
* 10 ======> 15
* / \ / \
* NULL 15 NULL 20
* \
* 20
*/
上面的代码表示了节点的删除过程。我们可以按照这个流程编写代码。
STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{
TREE_NODE* pTreeNode; if(NULL == ppTreeNode || NULL == *ppTreeNode)
return FALSE; pTreeNode = find_data_in_tree_node(*ppTreeNode, data);
if(NULL == pTreeNode)
return FALSE; if(*ppTreeNode == pTreeNode){
if(NULL == pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = NULL;
}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = pTreeNode->left_child;
pTreeNode->left_child->parent = NULL;
}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){
*ppTreeNode = pTreeNode->right_child;
pTreeNode->right_child->parent = NULL;
} free(pTreeNode);
return TRUE;
} return TRUE;
}
添加测试用例,依次添加10、15、20,然后删除数据10。
static void test5()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 15));
assert(TRUE == insert_node_into_tree(&pTreeNode, 20));
assert(TRUE == delete_node_from_tree(&pTreeNode, 10));
assert(15 == pTreeNode->data);
assert(NULL == pTreeNode->parent);
free(pTreeNode->right_child);
free(pTreeNode);
}
2.4删除数据的左右节点都存在
2.4 删除节点的左右子树都存在,此时又会分成两种情形
1)左节点是当前左子树的最大节点,此时只需要用左节点代替根节点即可
/*
*
* 10 ======> 6
* / \ / \
* 6 15 5 15
* /
* 5
*/
代码该怎么编写呢?
STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{
TREE_NODE* pTreeNode;
TREE_NODE* pLeftMax; if(NULL == ppTreeNode || NULL == *ppTreeNode)
return FALSE; pTreeNode = find_data_in_tree_node(*ppTreeNode, data);
if(NULL == pTreeNode)
return FALSE; if(*ppTreeNode == pTreeNode){ if(NULL == pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = NULL;
}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = pTreeNode->left_child;
pTreeNode->left_child->parent = NULL;
}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){
*ppTreeNode = pTreeNode->right_child;
pTreeNode->right_child->parent = NULL;
}else{
pLeftMax = find_max_node(pTreeNode->left_child);
if(pLeftMax == pTreeNode->left_child){
*ppTreeNode = pTreeNode->left_child;
(*ppTreeNode)->right_child = pTreeNode->right_child;
(*ppTreeNode)->right_child->parent = *ppTreeNode;
(*ppTreeNode)->parent = NULL;
}
} free(pTreeNode);
return TRUE;
} return TRUE;
}
上面的代码中添加的内容表示了我们介绍的这一情形。为此,我们可以设计一种测试用例。依次插入10、6、5、15,然后删除10即可。
static void test6()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 6));
assert(TRUE == insert_node_into_tree(&pTreeNode, 5));
assert(TRUE == insert_node_into_tree(&pTreeNode, 15));
assert(TRUE == delete_node_from_tree(&pTreeNode, 10));
assert(6 == pTreeNode->data);
assert(NULL == pTreeNode->parent);
assert(15 == pTreeNode->right_child->data);
assert(pTreeNode = pTreeNode->right_child->parent);
assert(NULL == pTreeNode->parent);
free(pTreeNode->left_child);
free(pTreeNode->right_child);
free(pTreeNode);
}
如果上面的测试用例通过,表示我们添加的代码没有问题。
2)左节点不是当前左子树的最大节点,情形如下所示
/*
*
* 10 ======> 8
* / \ / \
* 6 15 5 15
* \
* 8
*/
此时,我们应该用10左侧的最大节点8代替删除的节点10即可。
STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{
TREE_NODE* pTreeNode;
TREE_NODE* pLeftMax; if(NULL == ppTreeNode || NULL == *ppTreeNode)
return FALSE; pTreeNode = find_data_in_tree_node(*ppTreeNode, data);
if(NULL == pTreeNode)
return FALSE; if(*ppTreeNode == pTreeNode){ if(NULL == pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = NULL;
}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = pTreeNode->left_child;
pTreeNode->left_child->parent = NULL;
}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){
*ppTreeNode = pTreeNode->right_child;
pTreeNode->right_child->parent = NULL;
}else{
pLeftMax = find_max_node(pTreeNode->left_child);
if(pLeftMax == pTreeNode->left_child){
*ppTreeNode = pTreeNode->left_child;
(*ppTreeNode)->right_child = pTreeNode->right_child;
(*ppTreeNode)->right_child->parent = *ppTreeNode;
(*ppTreeNode)->parent = NULL;
}else{
pTreeNode->data = pLeftMax->data;
pLeftMax->parent->right_child = NULL;
pTreeNode = pLeftMax;
}
} free(pTreeNode);
return TRUE;
} return TRUE;
}
那么,这个场景下面测试用例又该怎么设计呢?其实只需要按照上面给出的示意图进行即可。依次插入数据10、6、8、15,然后删除数据10。
static void test7()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 6));
assert(TRUE == insert_node_into_tree(&pTreeNode, 8));
assert(TRUE == insert_node_into_tree(&pTreeNode, 15));
assert(TRUE == delete_node_from_tree(&pTreeNode, 10));
assert(8 == pTreeNode->data);
assert(NULL == pTreeNode->parent);
assert(NULL == pTreeNode->left_child->right_child);
assert(NULL == pTreeNode->parent);
free(pTreeNode->left_child);
free(pTreeNode->right_child);
free(pTreeNode);
}
至此,删除节点为根节点的情形全部讨论完毕,那么如果删除的节点是普通节点呢,那应该怎么解决呢?
STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{
TREE_NODE* pTreeNode;
TREE_NODE* pLeftMax; if(NULL == ppTreeNode || NULL == *ppTreeNode)
return FALSE; pTreeNode = find_data_in_tree_node(*ppTreeNode, data);
if(NULL == pTreeNode)
return FALSE; if(*ppTreeNode == pTreeNode){ if(NULL == pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = NULL;
}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = pTreeNode->left_child;
pTreeNode->left_child->parent = NULL;
}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){
*ppTreeNode = pTreeNode->right_child;
pTreeNode->right_child->parent = NULL;
}else{
pLeftMax = find_max_node(pTreeNode->left_child);
if(pLeftMax == pTreeNode->left_child){
*ppTreeNode = pTreeNode->left_child;
(*ppTreeNode)->right_child = pTreeNode->right_child;
(*ppTreeNode)->right_child->parent = *ppTreeNode;
(*ppTreeNode)->parent = NULL;
}else{
pTreeNode->data = pLeftMax->data;
pLeftMax->parent->right_child = pLeftMax->left_child;
pLeftMax->left_child->parent = pLeftMax->parent;
pTreeNode = pLeftMax;
}
} free(pTreeNode);
return TRUE;
} return _delete_node_from_tree(pTreeNode);
}
我们在当前函数的最后一行添加_delete_node_from_tree,这个函数用来处理普通节点的删除情况,我们会在下面一篇博客中继续介绍。
3、 普通节点的删除
3 普通节点的删除
3.1 删除的节点没有左子树,也没有右子树
测试用例1: 删除节点6
/*
*
* 10 ======> 10
* / \ \
* 6 15 15
*
*/ static void test8()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 6));
assert(6 == pTreeNode->left_child->data);
assert(TRUE == insert_node_into_tree(&pTreeNode, 15));
assert(TRUE == delete_node_from_tree(&pTreeNode, 6));
assert(NULL == pTreeNode->left_child);
free(pTreeNode->right_child);
free(pTreeNode);
}
测试用例2: 删除节点15
/*
*
* 10 ======> 10
* / \ /
* 6 15 6
*
*/ static void test9()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 6));
assert(TRUE == insert_node_into_tree(&pTreeNode, 15));
assert(15 == pTreeNode->right_child->data);
assert(TRUE == delete_node_from_tree(&pTreeNode, 15));
assert(NULL == pTreeNode->right_child);
free(pTreeNode->right_child);
free(pTreeNode);
}
那么代码应该怎么编写呢?
STATUS _delete_node_from_tree(TREE_NODE* pTreeNode)
{
TREE_NODE* pLeftMax; if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child){
if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = NULL;
else
pTreeNode->parent->right_child = NULL;
} free(pTreeNode);
return TRUE;
}
3.2 删除的节点有左子树,没有右子树
测试用例1: 测试节点6
/*
*
* 10 ======> 10
* / /
* 6 3
* /
* 3
*/ static void test10()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 6));
assert(TRUE == insert_node_into_tree(&pTreeNode, 3));
assert(TRUE == delete_node_from_tree(&pTreeNode, 6));
assert(3 == pTreeNode->left_child->data);
assert(pTreeNode = pTreeNode->left_child->parent);
free(pTreeNode->left_child);
free(pTreeNode);
}
测试用例2: 删除节点15
/*
*
* 10 ======> 10
* \ \
* 15 12
* /
* 12
*/ static void test11()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 15));
assert(TRUE == insert_node_into_tree(&pTreeNode, 12));
assert(TRUE == delete_node_from_tree(&pTreeNode, 15));
assert(12 == pTreeNode->right_child->data);
assert(pTreeNode = pTreeNode->right_child->parent);
free(pTreeNode->right_child);
free(pTreeNode);
}
添加左子树不为空,右子树为空的处理代码,如下所示:
STATUS _delete_node_from_tree(TREE_NODE* pTreeNode)
{
TREE_NODE* pLeftMax; if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child){
if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = NULL;
else
pTreeNode->parent->right_child = NULL;
}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){
pTreeNode->left_child->parent = pTreeNode->parent; if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = pTreeNode->left_child;
else
pTreeNode->parent->right_child = pTreeNode->left_child;
} free(pTreeNode);
return TRUE;
}
3.3 删除的节点左子树为空,右子树节点不为空
测试用例1: 删除数据6
/*
*
* 10 ======> 10
* / /
* 6 8
* \
* 8
*/ static void test12()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 6));
assert(TRUE == insert_node_into_tree(&pTreeNode, 8));
assert(TRUE == delete_node_from_tree(&pTreeNode, 6));
assert(8 == pTreeNode->left_child->data);
assert(pTreeNode = pTreeNode->left_child->parent);
free(pTreeNode->left_child);
free(pTreeNode);
}
测试用例2: 删除数据15
/*
*
* 10 ======> 10
* \ \
* 15 20
* \
* 20
*/ static void test13()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 15));
assert(TRUE == insert_node_into_tree(&pTreeNode, 20));
assert(TRUE == delete_node_from_tree(&pTreeNode, 15));
assert(20 == pTreeNode->right_child->data);
assert(pTreeNode = pTreeNode->right_child->parent);
free(pTreeNode->right_child);
free(pTreeNode);
}
添加左子树为空,右子树不为空的处理情形。代码如下:
STATUS _delete_node_from_tree(TREE_NODE* pTreeNode)
{
TREE_NODE* pLeftMax; if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child){
if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = NULL;
else
pTreeNode->parent->right_child = NULL;
}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){
pTreeNode->left_child->parent = pTreeNode->parent; if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = pTreeNode->left_child;
else
pTreeNode->parent->right_child = pTreeNode->left_child;
}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){
pTreeNode->right_child->parent = pTreeNode->parent; if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = pTreeNode->right_child;
else
pTreeNode->parent->right_child = pTreeNode->right_child;
} free(pTreeNode);
return TRUE;
}
3.4 删除的节点左右子树均不为空,不过又要分为两种情形:
1) 左节点是删除节点左侧的最大节点 (删除节点6)
/*
*
* 10 ======> 10
* / /
* 6 5
* / \ \
* 5 8 8
*/ static void test14()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 6));
assert(TRUE == insert_node_into_tree(&pTreeNode, 5));
assert(TRUE == insert_node_into_tree(&pTreeNode, 8));
assert(TRUE == delete_node_from_tree(&pTreeNode, 6));
assert(5 == pTreeNode->left_child->data);
assert(pTreeNode = pTreeNode->left_child->parent);
assert( 8 == pTreeNode->left_child->right_child->data);
assert(pTreeNode->left_child = pTreeNode->left_child->right_child->parent);
free(pTreeNode->left_child->right_child);
free(pTreeNode->left_child);
free(pTreeNode);
}
2) 左节点不是删除节点左侧的最大节点(删除节点5)
/*
*
* 10 ======> 10
* / /
* 5 4
* / \ / \
* 2 6 2 6
* \
* 4
*/ static void test15()
{
TREE_NODE* pTreeNode = NULL;
assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
assert(TRUE == insert_node_into_tree(&pTreeNode, 5));
assert(TRUE == insert_node_into_tree(&pTreeNode, 2));
assert(TRUE == insert_node_into_tree(&pTreeNode, 4));
assert(TRUE == insert_node_into_tree(&pTreeNode, 6));
assert(TRUE == delete_node_from_tree(&pTreeNode, 5));
assert(4 == pTreeNode->left_child->data);
assert(NULL == pTreeNode->left_child->left_child->right_child);
free(pTreeNode->left_child->left_child);
free(pTreeNode->left_child->right_child);
free(pTreeNode->left_child);
free(pTreeNode);
}
那么针对这两种类型,我们的代码究竟应该怎么处理呢?
STATUS _delete_node_from_tree(TREE_NODE* pTreeNode)
{
TREE_NODE* pLeftMax; if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child){
if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = NULL;
else
pTreeNode->parent->right_child = NULL;
}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){
pTreeNode->left_child->parent = pTreeNode->parent; if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = pTreeNode->left_child;
else
pTreeNode->parent->right_child = pTreeNode->left_child;
}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){
pTreeNode->right_child->parent = pTreeNode->parent; if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = pTreeNode->right_child;
else
pTreeNode->parent->right_child = pTreeNode->right_child;
}else{
pLeftMax = find_max_node(pTreeNode->left_child);
if(pLeftMax == pTreeNode->left_child){ if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = pTreeNode->left_child;
else
pTreeNode->parent->right_child = pTreeNode->left_child; pTreeNode->left_child->parent = pTreeNode->parent;
pTreeNode->left_child->right_child = pTreeNode->right_child;
pTreeNode->right_child->parent = pTreeNode-> left_child; }else{
pTreeNode->data = pLeftMax->data;
pLeftMax->parent->right_child = pLeftMax->left_child;
pLeftMax->left_child->parent = pLeftMax->parent;
pTreeNode = pLeftMax;
}
} free(pTreeNode);
return TRUE;
}
结束总结:
上面的过程记录了我们的代码是怎么一步一步走过来的。最后我们给出一份完整的节点删除代码:
STATUS _delete_node_from_tree(TREE_NODE* pTreeNode)
{
TREE_NODE* pLeftMax; if(NULL == pTreeNode-> left_child && NULL == pTreeNode->right_child){
if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = NULL;
else
pTreeNode->parent->right_child = NULL;
}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){
pTreeNode->left_child->parent = pTreeNode->parent; if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = pTreeNode->left_child;
else
pTreeNode->parent->right_child = pTreeNode->left_child;
}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){
pTreeNode->right_child->parent = pTreeNode->parent; if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = pTreeNode->right_child;
else
pTreeNode->parent->right_child = pTreeNode->right_child;
}else{
pLeftMax = find_max_node(pTreeNode->left_child);
if(pLeftMax == pTreeNode->left_child){ if(pTreeNode == pTreeNode->parent->left_child)
pTreeNode->parent->left_child = pTreeNode->left_child;
else
pTreeNode->parent->right_child = pTreeNode->left_child; pTreeNode->left_child->parent = pTreeNode->parent;
pTreeNode->left_child->right_child = pTreeNode->right_child;
pTreeNode->right_child->parent = pTreeNode-> left_child; }else{
pTreeNode->data = pLeftMax->data;
pLeftMax->parent->right_child = pLeftMax->left_child;
pLeftMax->left_child->parent = pLeftMax->parent;
pTreeNode = pLeftMax;
}
} free(pTreeNode);
return TRUE;
} STATUS delete_node_from_tree(TREE_NODE** ppTreeNode, int data)
{
TREE_NODE* pTreeNode;
TREE_NODE* pLeftMax; if(NULL == ppTreeNode || NULL == *ppTreeNode)
return FALSE; pTreeNode = find_data_in_tree_node(*ppTreeNode, data);
if(NULL == pTreeNode)
return FALSE; if(*ppTreeNode == pTreeNode){ if(NULL == pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = NULL;
}else if(NULL != pTreeNode->left_child && NULL == pTreeNode->right_child){
*ppTreeNode = pTreeNode->left_child;
pTreeNode->left_child->parent = NULL;
}else if(NULL == pTreeNode->left_child && NULL != pTreeNode->right_child){
*ppTreeNode = pTreeNode->right_child;
pTreeNode->right_child->parent = NULL;
}else{
pLeftMax = find_max_node(pTreeNode->left_child);
if(pLeftMax == pTreeNode->left_child){
*ppTreeNode = pTreeNode->left_child;
(*ppTreeNode)->right_child = pTreeNode->right_child;
(*ppTreeNode)->right_child->parent = *ppTreeNode;
(*ppTreeNode)->parent = NULL;
}else{
pTreeNode->data = pLeftMax->data;
pLeftMax->parent->right_child = pLeftMax->left_child;
pLeftMax->left_child->parent = pLeftMax->parent;
pTreeNode = pLeftMax;
}
} free(pTreeNode);
return TRUE;
} return _delete_node_from_tree(pTreeNode);
}
c++(排序二叉树删除)的更多相关文章
- c++排序二叉树的出现的私有函数讨论,以及二叉树的删除操作详解
c++排序二叉树的出现的私有函数讨论, 以及二叉树的删除操作详解 标签(空格分隔): c++ 前言 我在c++学习的过程中, 最近打了一个排序二叉树的题目,题目中出现了私有函数成员,当时没有理解清楚这 ...
- 数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL
树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构. a.树是n ...
- c++(排序二叉树线索化)
前面我们谈到了排序二叉树,还没有熟悉的同学可以看一下这个,二叉树基本操作.二叉树插入.二叉树删除1.删除2.删除3.但是排序二叉树也不是没有缺点,比如说,如果我们想在排序二叉树中删除一段数据的节点怎么 ...
- JavaScript实现排序二叉树的相关算法
1.创建排序二叉树的构造函数 /** * 创建排序二叉树的构造函数 * @param valArr 排序二叉树中节点的值 * @constructor */ function BinaryTree(v ...
- Java编程的逻辑 (42) - 排序二叉树
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- (原创)像极了爱情的详解排序二叉树,一秒get
排序二叉树(建立.查找.删除) 二叉树我们已经非常熟悉了,但是除了寻常的储存数据.遍历结构,我们还能用二叉树做什么呢? 我们都知道不同的遍历方式会对相同的树中产生不同的序列结果,排序二叉树就是利用二叉 ...
- 并查集&线段树&树状数组&排序二叉树
超级无敌巨牛逼并查集(带权并查集)https://vjudge.net/problem/UVALive-4487 带删点的加权并查集 https://vjudge.net/problem/UVA-11 ...
- 二叉树 排序二叉树-可以通过中序遍历得到排序的数据 二叉排序树时间复杂度O(logn),
二叉树是一种非常重要的数据结构,它同时具有数组和链表各自的特点:它可以像数组一样快速查找,也可以像链表一样快速添加.但是他也有自己的缺点:删除操作复杂. 虽然二叉排序树的最坏效率是O(n),但它支持动 ...
- javascript/js实现 排序二叉树数据结构 学习随笔
二叉树是一种数据结构.其特点是: 1.由一系列节点组成,具有层级结构.每个节点的特性包含有节点值.关系指针.节点之间存在对应关系. 2.树中存在一个没有父节点的节点,叫做根节点.树的末尾存在一系列没有 ...
随机推荐
- PipeHttp 测试工具使用
以下简单介绍下参数工具的使用 GitHub地址: https://github.com/lulianqi/PipeHttp/ (工程地址) https://github.com/lulia ...
- ArcGIS 网络分析[2] 在ArcMap中使用网络数据集进行五大网络分析[最短路径/服务区/最近设施点/OD成本矩阵/车辆分配]
上一章花了大篇幅介绍网络数据集的创建,也简单说了下点线的连通性问题. 那么可以试试刀锋不锋利啦! 网络分析呢,ArcGIS提供了5个基本分析类型: 最短路径求解 服务区(服务覆盖范围) 事故突发地的最 ...
- windows net 命令(转载)
CMD-NET命令详解 net命令大全,net命令用法,net网络命令,net命令使用,net命令集,net命令介绍,net常用命令,net命令的使用技巧,net命令如何使用 大家在操作Windows ...
- 自定义tab吸顶效果一(原理)
PS:问题:什么是吸顶,吸顶有什么作用,吸顶怎么使用? 在很多app商城中,介绍软件的时候就会使用吸顶效果, 吸顶有很多作用,一个最简单粗暴的作用就是,让用户知道此刻在浏览哪个模块,并可以选择另外的模 ...
- Material Theme 文件名的标签(tab)被大写了
我们平时使用的都是小写的,今天第一次使用Material Theme 这个发现标签被大写了,百度后没找到然后自己找了找设置,解决了 原来是这样的, 设置如下 设置后: 希望能帮到有同样问题的同学
- dJango前言之 socketserver源码
socketserver源码分析: ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer) ftpserver. ...
- 启用composer镜像服务
使用composer下载东西,需要FQ时,可使用其镜像服务 安装composer后,命令行执行全局配置 composer config -g repo.packagist composer https ...
- MySQL字符串相关函数学习一
这里总结一下常用的或者有可能用到的一些字符串内建函数 ① ASCII() :返回字符的ASCII码 如果输入的不是一个字符而是一个字符串呢?ascii()会只取第一个字符作为计算的参数,如: ② CH ...
- 80 行代码爬取豆瓣 Top250 电影信息并导出到 CSV 及数据库
一.下载页面并处理 二.提取数据 观察该网站 html 结构 可知该页面下所有电影包含在 ol 标签下.每个 li 标签包含单个电影的内容. 使用 XPath 语句获取该 ol 标签 在 ol 标签中 ...
- js 对象的值传递
一.变量赋值的不同 1.原始值 在将一个保存着原始值的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的. 2.引用值: 在将一个保存着对象内存地址的变量复制给另一个变量 ...