相比较节点的添加,平衡二叉树的删除要复杂一些。因为在删除的过程中,你要考虑到不同的情况,针对每一种不同的情况,你要有针对性的反应和调整。所以在代码编写的过程中,我们可以一边写代码,一边写测试用例。编写测试用例不光可以验证我们编写的代码是否正确,还能不断提高我们开发代码的自信心。这样,即使我们在开发过程对代码进行修改或者优化也不会担心害怕。然而看起来编写测试用例是一个繁杂的过程,但是从长期的收益来看,编写测试用例的成本是非常低廉的。

在排序二叉树的删除过程当中,我们应该怎么做呢?大家不用担心,只要按照我们下面的介绍一步一步往下做就可以了,大体上分为下面三个步骤:

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++(排序二叉树删除)的更多相关文章

  1. c++排序二叉树的出现的私有函数讨论,以及二叉树的删除操作详解

    c++排序二叉树的出现的私有函数讨论, 以及二叉树的删除操作详解 标签(空格分隔): c++ 前言 我在c++学习的过程中, 最近打了一个排序二叉树的题目,题目中出现了私有函数成员,当时没有理解清楚这 ...

  2. 数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

    树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构.    a.树是n ...

  3. c++(排序二叉树线索化)

    前面我们谈到了排序二叉树,还没有熟悉的同学可以看一下这个,二叉树基本操作.二叉树插入.二叉树删除1.删除2.删除3.但是排序二叉树也不是没有缺点,比如说,如果我们想在排序二叉树中删除一段数据的节点怎么 ...

  4. JavaScript实现排序二叉树的相关算法

    1.创建排序二叉树的构造函数 /** * 创建排序二叉树的构造函数 * @param valArr 排序二叉树中节点的值 * @constructor */ function BinaryTree(v ...

  5. Java编程的逻辑 (42) - 排序二叉树

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  6. (原创)像极了爱情的详解排序二叉树,一秒get

    排序二叉树(建立.查找.删除) 二叉树我们已经非常熟悉了,但是除了寻常的储存数据.遍历结构,我们还能用二叉树做什么呢? 我们都知道不同的遍历方式会对相同的树中产生不同的序列结果,排序二叉树就是利用二叉 ...

  7. 并查集&线段树&树状数组&排序二叉树

    超级无敌巨牛逼并查集(带权并查集)https://vjudge.net/problem/UVALive-4487 带删点的加权并查集 https://vjudge.net/problem/UVA-11 ...

  8. 二叉树 排序二叉树-可以通过中序遍历得到排序的数据 二叉排序树时间复杂度O(logn),

    二叉树是一种非常重要的数据结构,它同时具有数组和链表各自的特点:它可以像数组一样快速查找,也可以像链表一样快速添加.但是他也有自己的缺点:删除操作复杂. 虽然二叉排序树的最坏效率是O(n),但它支持动 ...

  9. javascript/js实现 排序二叉树数据结构 学习随笔

    二叉树是一种数据结构.其特点是: 1.由一系列节点组成,具有层级结构.每个节点的特性包含有节点值.关系指针.节点之间存在对应关系. 2.树中存在一个没有父节点的节点,叫做根节点.树的末尾存在一系列没有 ...

随机推荐

  1. S7-200以太网通信

    一.西门子网络系统 二.s7-200通过以太网模块接入以太网 三.S7-200可以接入的以太网系统 四.S7-200以太网通讯实验 五.实验硬件系统组成 六.S7-200作为服务器的配置 1.进入以太 ...

  2. lesson - 11 正则表达式

    正则就是有一定规律的字符串,有几个特殊符号很关键(. * + ? | ),我们平时不仅可以用命令行工具grep/sed/awk去引用正则,而且还可以把正则嵌入在nginx.apache.甚至php.p ...

  3. unity图片后期处理

    处理算法如下,在Start方法中分别调用想要的效果就行了.其中,将你需要处理的 图片 拖拽到 image参数上.注意,如果想要图片保持原来的尺寸不被压缩,需要更改图片的导入设置如下图,主要的Textu ...

  4. Disruptor并发框架 (二)核心概念场景分析

    核心术语 RingBuffer(容器): 被看作Disruptor最主要的组件,然而从3.0开始RingBuffer仅仅负责存储和更新在Disruptor中流通的数据.对一些特殊的使用场景能够被用户( ...

  5. Python之禅及释义

    在python shell中敲 import this会触发一个彩蛋,神奇的打印下面一段话: The Zen of Python, 即python之禅, 1999年Tim Peters大牛总结的&qu ...

  6. Micropython实战之TPYBoardv102 DIY金属检测仪

    转载请以链接形式注明文章来源(MicroPythonQQ技术交流群:157816561,公众号:MicroPython玩家汇) 1.实验目的 1.学习在PC机系统中扩展简单I/O接口的方法. 2.进一 ...

  7. Python核心编程笔记--动态属性

    一.动态语言与静态语言 1.1 静态语言特点: a. 在定义变量时需要指定变量的类型,根据指定的类型来确定变量所占的内存空间 b. 需要经过编译才能运行 c. 在代码编译后,运行过程不能对代码进行操作 ...

  8. css实现网格背景

    只使用一个渐变时,我们能创建的图案并不多,当我们把多个渐变图案组合起来,让他们透过彼此的透明区域显现时,神奇的事情就发生了!我们首先想到的是把水平和水质条纹叠加起来,就可以得到各种各样的网格. 1. ...

  9. python之dictionary

    1.python3字典 字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中 d ...

  10. PE解析器的编写(三)——区块表的解析

    PE文件中所有节的属性都被定义在节表中,节表由一系列的IMAGE_SECTION_HEADER结构排列而成,每个结构用来描述一个节,结构的排列顺序和它们描述的节在文件中的排列顺序是一致的. 具有相同属 ...