我差不多完成了二进制搜索树程序。但是,我坚持删除:删除左右子树的节点。左子树中提升了最大的左值。它有时可行,但并不总是以它应有的方式工作。即,如果您将值23,14,31,7,9输入树中并删除23,则出现的值为14 14 7 9.请帮忙!
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int key;
struct node* left;
struct node* right;
}node;
struct node* root= NULL;
int count=0;
void preOrder(node* temp){
if (temp!=NULL){
printf("%d ",temp->key);
preOrder(temp->left);
preOrder(temp->right);
}
}
//for printing
void inOrder(node* temp){
if (temp!=NULL){
inOrder(temp->left);
printf("%d ",temp->key);
inOrder(temp->right);
}
}
void printPrompt(void){
int choice=-1;
do{
printf(" Enter <1> Inorder <2> Preorder <3> Return to Menu: ");
scanf("%d", &choice);
if(choice!=1 && choice!=2 && choice!=3) printf(" Error: invalid input! \n\n");
if(choice==1){
if(root==NULL) printf("\tError: is empty tree\n");
else {
printf("\tInorder:\t ");
inOrder(root);
printf("\n\n");
}
}
else if (choice==2){
struct node* temp=root;
if(root==NULL) printf("\tError: is empty tree\n");
else {
printf("\tPreorder:\t ");
preOrder(root);
printf("\n\n");
}
}
}while (choice!=3);
printf(" <Exit print method>\n\n");
}
//printing complete
//both are similar code- one searches and another finds the node
int contains(node* current, int value){
if(current==NULL) return 0;
if (value==current->key) {
return 1;
}
else if(value < current->key) return contains(current->left, value);
else return contains(current->right, value);
}
node* findParent(node* current, int value){
if (value == current->key) return NULL; //if only one node in BST, then no parent node
if (value < current->key) {
if (current->left == NULL) return NULL; //if value not found, return null
else if (current->left->key == value) return current;
else return findParent (current->left, value);
}
else {
if (current->right == NULL) return NULL;
else if (current->right->key== value) return current;
else return findParent (current->right, value);
}
}
node* findNode(node* current, int value){
if (current == NULL) return NULL;
if (current->key == value) {
return current;
}
else if (value < current->key) return findNode (current->left, value);
else return findNode (current->right, value);
}
//
void del(value){
struct node* nodeToRemove= findNode(root, value);
if (nodeToRemove == NULL) printf("\tError: node not found in tree\n");
else {
struct node* parent = findParent(root, value);
if (count == 1 ) {
root= NULL;
printf("\tRemoving the only node in BST\n");
}
else if (nodeToRemove->left == NULL && nodeToRemove->right == NULL){
printf("\tRemoving leaf node in BST\n");
if (nodeToRemove->key < parent->key) parent->left = NULL;
else parent->right = NULL;
}
else if (nodeToRemove->left== NULL && nodeToRemove->right != NULL){
printf("\tRemoving node with right subtree but no left subtree\n");
if (nodeToRemove->key < parent->key) {
parent->left = nodeToRemove->right;
}
else parent->right = nodeToRemove->right;
}
else if (nodeToRemove->left!= NULL && nodeToRemove->right == NULL){
printf("\tRemoving node with left subtree but no right subtree\n");
if (nodeToRemove->key < parent->key) {
parent->left = nodeToRemove->left;
}
else parent->right = nodeToRemove->left;
}
else{
printf("\tRemoving node with both left subtree and right subtree\n");
struct node* nodeLargestLeft = nodeToRemove -> left;
while (nodeLargestLeft -> right != NULL) nodeLargestLeft= nodeLargestLeft->right;
findParent(root, nodeLargestLeft->key)->right=NULL;
nodeToRemove->key=nodeLargestLeft->key;
}
}
printf("\tResult: ");
preOrder(root);
printf("\n");
count= count-1;
}
void deletePrompt(void){
int value=-1;
do{
printf(" Delete key or press -1 to return to menu: ");
scanf("%d", &value);
if(value>0){
if(root==NULL) printf("\tError: is empty tree\n");
else del(value);
}
else if (value<=0) printf("\tError: key not positive\n");
}while (value!=-1);
printf(" <Exit delete method>\n\n");
}
void searchPrompt(void){
int value=-1;
do{
printf(" Search key or press -1 to return to menu: ");
scanf("%d", &value);
if(value>0){
if (root==NULL) printf("\tError: tree is empty\n");
else {
if(contains(root, value)) printf("\tKey %d is found\n",value);
else printf("\tKey %d is not found\n",value);
}
}
else if (value<=0) printf("\tError: key not positive\n");
}while (value!=-1);
printf(" <Exit search method>\n\n");
}
//for search
//for insertion
void insertNode(node* current, int value){
if(value< current->key){
if (current->left == NULL) {
current->left=(node*) malloc(sizeof(node));
current->left->key = value;
current->left->left = NULL;
current->left->right = NULL;
printf("\tSuccess! Value inserted: %d\n", current->left->key);
}
else {
insertNode(current->left, value);
}
}
else {
if (current->right == NULL) {
current->right=(node*) malloc(sizeof(node));
current->right->key = value;
current->right->left = NULL;
current->right->right = NULL;
printf("\tSuccess! Value inserted: %d\n", current->right->key);
}
else {
insertNode(current->right, value);
}
}
}//end insert
void insert(int value){
if(root==NULL){ //empty tree
root =(node*) malloc(sizeof(node));
root->key= value;
printf("\tPrint root here: %d\n", value);
root->left= NULL;
root->right=NULL;
printf("\tSuccess! Value inserted: %d\n", root->key);
}
else {
insertNode(root, value);
}
printf("\tResult: ");
preOrder(root);
printf("\n");
}
void insertPrompt(void){
int value=-1;
do{
printf(" Insert value or press -1 to return to menu: ");
scanf("%d", &value);
if(value>0){
insert(value);
count= count+1;
printf("\tCount: %d\n", count);
}
else if (value<=0)printf("\tError: key not positive\n");
}while (value!=-1);
printf(" <Exit insert method>\n\n");
}
int menuPrompt(void){
int choice=-1;
do{
printf("Enter <1> Search <2> Insert <3> Delete <4> Print Tree <5> Quit: ");
scanf("%d", &choice);
if(choice>5 || choice<1) printf("Error: invalid input! \n\n");
} while(choice>5 || choice<1);
return choice;
}
int main(int argc, char *argv[]){
int choice=-1;
int value=-1;
while(choice!=5){
choice=menuPrompt();
switch(choice){
case 1:
searchPrompt();
break;
case 2:
insertPrompt();
break;
case 3:
deletePrompt();
break;
case 4:
printPrompt();
break;
case 5:
printf("<Exit program> \n");
break;
}//end switch
}
system("PAUSE");
return 0;
}
答案 0 :(得分:3)
具有两个子树的节点的删除算法略有错误。你正确的做法是:
找到左子树的最大值(或右子树的最小值):
struct node* nodeLargestLeft = nodeToRemove -> left;
while (nodeLargestLeft -> right != NULL)
nodeLargestLeft= nodeLargestLeft->right;
使用上面
中找到的节点的值替换要删除的节点的值nodeToRemove-&GT;键= nodeLargestLeft-&GT;密钥;
您尝试从示例树中删除23
23
/ \
14 31
/
7
\
9
在左子树中有14个最大值,现在看起来像这样:
14
/ \
14 31
/
7
\
9
但是现在,您不能只删除最大节点(您的根节点)的父节点的右子树。在你提到的示例中,这将是整个二叉树的正确子树!
findParent(root, nodeLargestLeft->key)->right=NULL; // wrong
相反,您必须为重复节点(第二级中的节点14)执行常规删除过程。由于它是左子树中具有最大值的节点,因此它不能具有正确的子树。所以只有两种情况:左边的子树也是空的,在这种情况下可以丢弃节点,或者填充它,在这种情况下,左子树的根节点替换这个节点。
在你的例子中,第二种情况发生了,你的树应该是这样的:
14
/ \
7 31
\
9
通过最少的侵入性更改,此过程应该有效:
printf("\tRemoving node with both left subtree and right subtree\n");
struct node* nodeLargestLeft = nodeToRemove->left;
parent = findParent(root, nodeLargestLeft->key);
while (nodeLargestLeft -> right != NULL) {
parent = nodeLargestLeft;
nodeLargestLeft= nodeLargestLeft->right;
}
nodeToRemove->key=nodeLargestLeft->key;
parent->left = nodeLargestLeft->left;
您的代码还有其他一些问题,例如
parent
是NULL
- 指针,导致parent->key
上的段错误findParent
的调用看起来很难看,在遍历树或为每个节点维护父指针时更好地跟踪父级。答案 1 :(得分:0)
好的,我解决了自己的问题。有一个特例。
else{
printf("\tRemoving node with both left subtree and right subtree\n");
//special case, if left of nodeToRemove has no right node
struct node* nodeLargestLeft = nodeToRemove -> left;
if (nodeToRemove->left->right == NULL) {
nodeToRemove->key = nodeToRemove->left ->key;
nodeToRemove->left = nodeToRemove->left->left;
}else{
while (nodeLargestLeft -> right != NULL) nodeLargestLeft= nodeLargestLeft->right;
findParent(root, nodeLargestLeft->key)->right=NULL;
nodeToRemove->key=nodeLargestLeft->key;
}
}
答案 2 :(得分:0)
DELETION是b-tree中最不正常的例程,这是我的, 这是维基文章,它恢复了我所做的https://en.wikipedia.org/wiki/Binary_search_tree#Deletion
void bt_rec_delete(pbbtree bt, size_t root)
{
ptbBtreeNode me, right, left, parent, replacer;
char side;
ll rec;
me = &bt->tb[root];
me->deleted = TRUE;
right = me->right == 0 ? NULL : &bt->tb[me->right];
left = me->left == 0 ? NULL : &bt->tb[me->left];
parent = me->parent == 0 ? NULL : &bt->tb[me->parent];
// if (parent)
// disp_dbt(bt,parent->index,0);
if (parent)
side = parent->right == root ? 'r' : 'l';
else
side = 0;
if (!right && !left)
{
if (side == 'r')
parent->right = 0;
else if (side == 'l')
parent->left = 0;
else
bt->current_root = 0;
propagate_depth(bt, root);
}
else if (!right)
{
left->parent = me->parent;
if (side == 'r')
parent->right = left->index;
else if (side == 'l')
parent->left = left->index;
else
bt->current_root = left->index;
propagate_depth(bt, left->index);
}
else if (!left)
{
right->parent = me->parent;
if (side == 'r')
parent->right = right->index;
else if (side == 'l')
parent->left = right->index;
else
bt->current_root = right->index;
propagate_depth(bt, right->index);
}
else
{
unsigned rec_par;
if (right->depth > left->depth)
{
rec = bt_get_maximum(bt, right->index);
assert(rec > 0);
rec_par = bt->tb[rec].parent;
if (rec_par != me->index)
{
bt->tb[rec_par].left = bt->tb[rec].right; // maximum assure me there is no left leaf
if (bt->tb[rec].right > 0)
bt->tb[bt->tb[rec].right].parent = rec_par;
bt->tb[rec].right = 0;
}
propagate_depth(bt, rec_par);
}
else
{
rec = bt_get_minimum(bt, left->index);
assert(rec > 0);
rec_par = bt->tb[rec].parent;
if (rec_par != me->index)
{
bt->tb[rec_par].right = bt->tb[rec].left;// minimum assure me there is no right leaf
if (bt->tb[rec].left > 0)
bt->tb[bt->tb[rec].left].parent = rec_par;
bt->tb[rec].left = 0;
}
propagate_depth(bt, rec_par);
}
replacer = &bt->tb[rec];
replacer->depth = me->depth;
if (side == 'r')
parent->right = replacer->index;
else if (side == 'l')
parent->left = replacer->index;
else
bt->current_root = replacer->index;
replacer->parent = me->parent;
if (replacer->index != left->index)
{
replacer->left = left->index;
left->parent = replacer->index;
}
if (replacer->index != right->index)
{
replacer->right = right->index;
right->parent = replacer->index;
}
}
}