删除有两个节点的二叉树节点的删除策略
找到右子树中值最小的节点,或者找到左子树中最大的节点,称之为最优值节点,这个节点的值是最适合提替换要删除节点的,替换值之后,删除最优值节点,因为最优值节点一定是不会是有两个子节点的节点,所以删除就方便许多;
写了点代码记录下:
主要技巧是递归的使用,是最重要的操作二叉树的技巧:
//定义的二叉树的节点
/*
* 传入数字时候,柚子树比作字数达
*/
typedef struct Tree{
int val;
struct Tree* left;
struct Tree* right;
}tree;
然后是插入操作:
/*
* 添加程序
* 连接父节点要做到
* 使用
*/
int add(tree * root, tree * father, int value) {
tree *current = root;
if (current != NULL) {
if (value <= current->val) {
return add(current->left, current, value);
} else {
return add(current->right, current, value);
}
}
current = malloc(sizeof(tree));
current->val = value;
current->left = NULL;
current->right = NULL;
if (value <= father->val) {
father->left = current;
} else {
father->right = current;
}
// printf("value is %d location is %d\n",value,current);
return 1;
}
//打印所有的节点数据
//先序遍历
void printTree(tree* root) {
tree*current = root;
if (current != NULL) {
printf("value is %d\n", current->val);
printTree(current->left);
printTree(current->right);
} else {
return;
}
}
最后是删除的程序:因为定义节点时候选择没有定义父节点,所以需要找到删除节点之前的一个节点
//获取到需要删除节点的父节点地址,然后通过比较
//得到需要删除的节点是哪个
//首先直接传入pro 也就是父节点,不考虑根节点情况 也就是pro 和value 值不相等
int findPro(tree* pro, int value) {
if (value > pro->val) {
if (pro->right == NULL) {
//如果没有这个节点
printf("暂时没有这个值");
return -1;
} else {
//和这个值是相等的情况
if (pro->right->val == value) {
return pro;
} else {
return findPro(pro->right, value);
}
}
} else {
if (pro->left == NULL) {
printf("暂时没有这个值");
return -1;
} else {
if (pro->left->val == value) {
return pro;
} else {
return findPro(pro->left, value);
}
}
}
}
然后就是根据三种情况对节点进行删除,我没写root节点的删除,都是一个逻辑而已:
/**
* 根据值删除一个节点
* 三种情况,
* 一是删除没有子节点的
* 二是删除有一个子节点的
* 三是删除有两个子节点的
* 首先根据值找到节点,值是可能会重复的,那就先删除一个值
*
*/
void deleteItem(tree * root, int value) {
tree * pro = NULL;
tree * current = NULL;
if (root->val == value) {
printf("删除根节点");
//同样根节点删除也有三种情况,就一个节点,有两个节点,一个子节点都咩有
} else {
pro = findPro(root, value);
if (value > pro->val) {
current = pro->right;
if (current->left != NULL && current->right != NULL) {
//删除左子树和右子树都有的情况
deleDoubleChild(current);
} else if (current->left != NULL && current->right == NULL) {
pro->right = current->left;
free(current);
} else if (current->right != NULL && current->left == NULL) {
pro->right = current->right;
free(current);
} else if (current->left == NULL && current->right == NULL) {
pro->right = NULL;
free(current);
}
} else {
current = pro->left;
if (current->left != NULL && current->right != NULL) {
deleDoubleChild(current);
} else if (current->left != NULL && current->right == NULL) {
pro->left = current->left;
free(current);
} else if (current->right != NULL && current->left == NULL) {
pro->left = current->right;
free(current);
} else if (current->left == NULL && current->right == NULL) {
pro->left = NULL;
free(current);
}
}
}
}
其中,删除既有左子树又有右子树的程序我是通过右子树里面找最小的去实现的:
/*
* 删除同时有两个叶子节点的二叉树
* 不需要节点之前的节点,使用替换的方式进行
* 只不过需要找到替换值之前的那个节点进行删除
*/
void deleDoubleChild(tree*root) {
tree * current = root->right;
if (current->left == NULL) {
//也就是说 current 是需要删除的节点 值因该是current的值
root->right=current->right;
root->val=current->val;
free(current);
} else {
//删除current 的左子树
while (current->left->left != NULL) {
current = current->left;
}
//最后一个没有左子树
root->val = current->left->val;
current->left = NULL;
free(current->left);
}
}
程序结构应该还有改动的可能,还需要测试测试