之前写过一个二叉查找树,其中最麻烦的是删除元素的方法,一共分了8种情况,主要是要区分是否是根节点和非根节点,
写的太烦了,详细请参见:http://blog.csdn.net/todd911/article/details/8471566
今天要来简化一下这个方法,之前我还写过一篇《简洁的单项链表插入操作》,利用双指针,简化了根节点和非根节点的区别,
详细请参见:http://blog.csdn.net/todd911/article/details/8941593,其实在二叉查找树中也可以使用这种方法。
改进后的代码如下:
void deleteNode(treeNode** node, int value){
treeNode* current;
while( (current = *node) != NULL && current->value != value ){
if(current->value > value){
node = ¤t->left;
}else if(current->value < value){
node = ¤t->right;
}
}
//如果current为NULL,则没有找到
if(current == NULL){
printf("this node want to delete is not exit!\n");
}else{
//如果找到节点,则判断节点的状态
//没有孩子节点,则直接删除
if(current->left == NULL && current->right == NULL){
free(current);
*node = NULL;
current = NULL;
}else
//左右孩子都有,则先将右孩子插入到左孩子树上,再将原先指向current的指针指向current的左孩子,删除current
if(current->left != NULL && current->right != NULL){
insertNode(current->left, current->right);
*node = current->left;
free(current);
current = NULL;
}else
//没有左孩子,有右孩子,则将原先指向current的指针指向current的右孩子,删除current
if(current->left == NULL && current->right != NULL){
*node = current->right;
free(current);
current = NULL;
}else
//没有右孩子,有左孩子,则将原先指向current的指针指向current的左孩子,删除current
if(current->left != NULL && current->right == NULL){
*node = current->left;
free(current);
current = NULL;
}
}
}
这种方法有一个问题,就是被删除的节点都有左右孩子,就会先将右孩子插入到左孩子树上,再将原先指向current的指针指向current的左孩子,
导致二叉树的树干长度不平衡了。
详细步骤如下,节点12是要被删除的:
可见,最后树的结构破坏比较大, 可能会导致查找的效率降低。
下面我们来改进一下,如果要被删除的节点有左右孩子,则从左孩子获得值最大的那个,来替换要被删除的节点,详细步骤如下,节点12是要被删除的:
怎么样,树的结构没有怎么被破坏吧,推荐还是使用这种方法比较好。
下面附上完整的sample代码:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
typedef struct tagNode{
int value;
struct tagNode* left;
struct tagNode* right;
}treeNode;
void displayArray(int array[],int size){
printf("the array is:");
int i;
for(i=0;i<size;i++){
printf("%d ",array[i]);
}
printf("\n");
}
void displayTree(treeNode* node){
if(node == NULL) return;
if(node->left != NULL){
displayTree(node->left);
}
printf("%d ",node->value);
if(node->right != NULL){
displayTree(node->right);
}
}
void insertNode(treeNode* node, treeNode* iNode){
if(iNode->value >= node->value && node->right != NULL){
insertNode(node->right, iNode);
return;
}
if(iNode->value < node->value && node->left != NULL){
insertNode(node->left, iNode);
return;
}
if(iNode->value >= node->value && node->right == NULL){
node->right = iNode;
}
if(iNode->value < node->value && node->left == NULL){
node->left = iNode;
}
}
void deleteNode(treeNode** node, int value){
treeNode* current;
while( (current = *node) != NULL && current->value != value ){
if(current->value > value){
node = ¤t->left;
}else if(current->value < value){
node = ¤t->right;
}
}
if(current == NULL){
printf("this node want to delete is not exit!\n");
}else{
if(current->left == NULL && current->right == NULL){
free(current);
*node = NULL;
current = NULL;
}else if(current->left != NULL && current->right != NULL){
insertNode(current->left, current->right);
*node = current->left;
free(current);
current = NULL;
}else if(current->left == NULL && current->right != NULL){
*node = current->right;
free(current);
current = NULL;
}else if(current->left != NULL && current->right == NULL){
*node = current->left;
free(current);
current = NULL;
}
}
}
void getMaxValueNode(treeNode **link){
while( *link != NULL && (*link)->right != NULL){
*link = (*link)->right;
};
}
void deleteNode2(treeNode** node, int value){
treeNode* current;
while( (current = *node) != NULL && current->value != value ){
if(current->value > value){
node = ¤t->left;
}else if(current->value < value){
node = ¤t->right;
}
}
if(current == NULL){
printf("this node want to delete is not exit!\n");
}else{
if(current->left == NULL && current->right == NULL){
free(current);
*node = NULL;
current = NULL;
}else if(current->left != NULL && current->right != NULL){
treeNode** link = ¤t->left;
getMaxValueNode(link);
if(*link != NULL){
treeNode *maxValueNode = *link;
*link = (*link)->left;
maxValueNode->left = current->left;
maxValueNode->right = current->right;
*node = maxValueNode;
free(current);
current = NULL;
}
}else if(current->left == NULL && current->right != NULL){
*node = current->right;
free(current);
current = NULL;
}else if(current->left != NULL && current->right == NULL){
*node = current->left;
free(current);
current = NULL;
}
}
}
void createTree(treeNode** root, int array[], int size){
int i;
*root = (treeNode*)malloc(sizeof(treeNode));
(*root)->value = array[0];
(*root)->left = NULL;
(*root)->right = NULL;
for(i=1;i<size;i++){
treeNode* child = (treeNode*)malloc(sizeof(treeNode));
child->value = array[i];
child->left = NULL;
child->right = NULL;
insertNode(*root, child);
}
}
void deleteTree(treeNode* node){
if(node == NULL) return;
if(node->left != NULL){
deleteTree(node->left);
}
if(node->right != NULL){
deleteTree(node->right);
}
if(node->left == NULL && node->right == NULL){
free(node);
node = NULL;
}
}
int main(int argc, char* argv[]){
int array[SIZE] = {60,4,45,78,345,23,12,3,6,21};
displayArray(array,SIZE);
treeNode *root = NULL;
createTree(&root, array, SIZE);
printf("the tree is(left->middle->right):");
displayTree(root);
printf("\n");
int value = 12;
printf("delete value:%d\n",value);
deleteNode(&root,value);
printf("the tree is(left->middle->right):");
displayTree(root);
printf("\n");
value = 78;
printf("delete value:%d\n",value);
deleteNode2(&root,value);
printf("the tree is(left->middle->right):");
displayTree(root);
printf("\n");
deleteTree(root);
return 0;
}