どのように正しく挿入-削除にバイナリ検索ツリー。
-
21-08-2019 - |
質問
私はちょっといけたCの質問にこのはり重要になっていま---
ってコードされ、挿入、削除の機能を自分のバイナリ検索ツリーの削除機能は不完全なものです。ある夫婦の物ださ---
1) 私の挿入機能の良しでも改善されなんだか?
2) 私の削除機能を欠いたの削除ノードの左右の子供.い検索をする機会が多いので、ここ数時間もかを調べの適正について教えてください。
2.a) いつ、どのように削除するノード2の子ノード?
2.b) 第の質問は削除機能の良しできます。ここかできない繰り返し多くのコードにifもしっかり身につけるた見たいのですが向上することでお困ります。
typedef struct sClientProfile *ClientProfile;
typedef struct sClientTree *ClientTree;
typedef struct sClientProfile {
char *clientName;
int clientAge;
int clientNIF;
} nClientProfile;
typedef struct sClientTree {
ClientProfile clientProfile;
char *clientName;
ClientTree leftTree;
ClientTree rightTree;
} nClientTree;
void addClientToTree(ClientTree *cTree, ClientProfile cProfile) {
if(!*cTree) {
ClientTree new = (ClientTree)malloc(sizeof(nClientTree));
if(!new) {
perror("malloc");
}
new->clientName = strdup(cProfile->clientName);
new->clientProfile = cProfile;
new->leftTree = NULL;
new->rightTree = NULL;
*cTree = new;
} else {
if(strcmp((*cTree)->clientName, cProfile->clientName) > 0) {
addClientToTree(&(*cTree)->leftTree, cProfile);
} else {
addClientToTree(&(*cTree)->rightTree, cProfile);
}
}
}
void deleteClientFromTree(ClientTree *cTree, char *cName) {
if(!cTree) return;
int nCompare = strcmp((*cTree)->clientName, cName);
if(nCompare > 0) {
deleteClientFromTree(&(*cTree)->leftTree, cName);
} else if(nCompare < 0) {
deleteClientFromTree(&(*cTree)->rightTree, cName);
} else {
if(!(*cTree)->leftTree && !(*cTree)->rightTree) {
ClientTree cliPtr = *cTree;
free(cliPtr->clientProfile);
free(cliPtr);
cliPtr->clientProfile = NULL;
cliPtr = NULL;
*cTree = NULL;
} else if(!(*cTree)->leftTree) {
ClientTree cliPtr = *cTree;
free(cliPtr->clientProfile);
free(cliPtr);
cliPtr->clientProfile = NULL;
*cTree = (*cTree)->rightTree;
} else if(!(*cTree)->rightTree) {
ClientTree cliPtr = *cTree;
free(cliPtr->clientProfile);
free(cliPtr);
cliPtr->clientProfile = NULL;
*cTree = (*cTree)->leftTree;
} else {
// MISSING DELETE CASE
}
}
}
く通知がついてお話ししましょう2備考:
- このツリー用の文字列ではなくint表現。だからこそ思いのまま使用strcmp()すべてにしようとして使用できます。
- 私は使用しない繰り返しなのポインタの構造体のポインタの場合)で作業しました。見た目よりクリーンなんだか、そして将来いの成功またはノードを削除しました。
更新。
しかし、私たか反復の削除機能がないようにもなって改善することができないかも見えないことに気づいた。このコードの場合で、削除するノードの2つの領で作業ではないでくださ---
また、全体にコードが思いのコードを改善することができ、この問題です。私と呼ばれることがありますこれらの課題A,B(あ億も、C、Dを参照しています。
bool deleteClientFromTree(ClientTree *cTree, char *cName) {
if(!cTree) return FALSE;
ClientTree currPtr = *cTree;
ClientTree prevPtr = NULL;
int nCompare;
while(currPtr) {
nCompare = strcmp(currPtr->clientName, cName);
if(nCompare > 0) {
prevPtr = currPtr;
currPtr = currPtr->leftTree;
} else if(nCompare < 0) {
prevPtr = currPtr;
currPtr = currPtr->rightTree;
} else {
/*
* A)
*
* The following cases have 3 lines in common, the free()
* calls and return statement. Is there anyway to improve
* this code and make it more compact?
*
* Of course, the printf's are to be removed...
*/
if(!prevPtr && !currPtr->leftTree && !currPtr->rightTree) {
printf("CASE #1\n");
*cTree = NULL;
free(currPtr->clientProfile);
free(currPtr);
return TRUE;
} else if(!currPtr->leftTree || !currPtr->rightTree) {
printf("CASE #2\n");
if(prevPtr->leftTree == currPtr) {
prevPtr->leftTree = currPtr->rightTree;
} else {
prevPtr->rightTree = currPtr->leftTree;
}
free(currPtr->clientProfile);
free(currPtr);
return TRUE;
} else {
printf("CASE #3\n");
ClientTree tempPtr = currPtr->rightTree;
while(tempPtr->leftTree) {
tempPtr = tempPtr->leftTree;
}
/*
* C)
*
* This has a big problem...
*
* If you take a look at the ClientProfile structure,
* in the first post, you'll see two ints
* (clientNIF/clientAge) and one char* (clientName).
*
* The problem is that the following code line is only
* copying the integer data, not the string. For some
* reason, the string remains the old one.
*
* I tried to use strdup() directly on clientName like:
* currPtr->clientProfile->clientName = strdup(tempPtr->clientProfile->clientName);
* but it still doesn't work.
*
* Why everything is being copied but the strings?
*/
currPtr->clientProfile = tempPtr->clientProfile;
/*
* D)
*
* Is there anyway to not call the function itself
* and make the while loop once again and delete the
* corresponding leaf?
*/
return deleteClientFromTree(&currPtr->rightTree, tempPtr->clientProfile->clientName);
}
}
}
return FALSE;
}
解決
、あなたはその子について何かを行う必要があります。
は子がない場合 - 何の問題。あなただけのノードを削除します。
もしそこに左の子、また、全く問題ありません。ノードを削除し、その場所にその左の子を移動します。
右の子のために同じ。単に削除されたノードの代わりに子を移動します。
あなたは左と右の両方の子を持つノードを削除したい場合は、問題が来ます。あなたは、削除されたノードの代わりに左または右の子を移動させることができていますが、その後、他の子とそのサブツリーについて何をしますか?
ソリューションはこれです。あなたは、削除されたノードに論理的な後継者を探します。論理的な後継者によって、私はこれを意味します。 が次の最大数のある論理的な後継者、あなたは整数で作られたツリーを持っていて、値35を持つノードを削除しますと言います。 Y A?あなたはインオーダー散歩をしていた場合、それはあなたが削除している要素の後に来る要素になります。
さて、論理的な後継者を見つけるための簡単なルールがあります。あなたは正しいものを行く(これはあなたが2人の子供を持っている場合であるので、あなたは常に、権利を持っている)、その後、あなたはできる限り左に行きます。
あなたがで終わるその要素は、論理的な後継者です。これは、削除された要素より大きいです(あなたが右の開始時に行ってきました、覚えている?)それは、の最小の次に大きな要素です。の
さて、その要素は常に一つだけ、あるいはまったく子供を持っている - あなたは限りあなたは、覚えることができるのままに行ってきましたので?そう、あなたはそれ以上を残して行くことができない - 何の左側がないので - そのための要素は、子またはちょうど右の子を持っていないし、それはそれは簡単にはunlink catagories(子供がいないか、ただ一人の子供)のいずれかに該当する意味します。だから、リンク解除のこの要素は簡単です。
;これを考える -今クールビットが来ます各要素の左にあるすべてのものが小さいため、すべてに - その次の最大の要素は、削除したい要素として、ツリー内の同じ場所にあった場合は、は、ツリーはまだの有効で正しいだろう右の方が大きいます。
それでは、あなたがやっていることはこれです。あなたは、削除されたノードに次の最大のノードにユーザーデータをコピーして、あなたはを削除するには、その次に大きいノードの(それは解除して削除するのは簡単ですので、それは、子またはちょうど右の子を持っていません)。
そして、それはそれだ!
だから、基本的には - 、あなたの論理的な後継者を見つけるツリーから彼を解除し、あなたが実際にもともともちろん、あなたはその後、削除しない(削除している要素の中に自分のユーザデータを入れて、それが物理的にまだの一部だからツリー)。
他のヒント
まず最初に、あなたは再帰を使用していない言及したが、各機能は、自分自身を呼び出す論理パスを持っています。
質問にオンます:
1) 再帰を削除します。あなたの木があなたのスタックを吹き飛ばすのに十分な大きさである場合、これは多くの問題にあなたを得ることができます。 GCCは末尾再帰のための限定的なサポートがありますが、私はそれにカウントされないでしょう。
2) 通常は、次の2つのノードとの子を削除すると、削除したノードをしていた位置に、左または右のノードを推進します。
(これは非常に単純なケースですが、私はあなたのツリーはバランスがとれていないと仮定しています)2.B) あなたの削除のコードは、いくつかの問題があります。私はいくつかの仮定の状況でそれを歩いてお勧めします。私にはすぐに明らかにポインタをfree'ingし、それをdeferencingた。
free(cliPtr);
cliPtr->clientProfile = NULL;
あなたが正当なものが離れて乗得ればもちろん、あなたはいつものスタイルを心配することができます。
理想的BST内のノードの削除のための3つの場合があります
ケース1:
X has no children: remove X
事例2:
X has one children : Splice out X
事例3:
X has two children : swap X with its successor and follow case #1 or #2
だから、行方不明、削除する場合についてます:
Xは、(ノード削除する)二人の子供を持っている場合、Xの後継とXを交換し、ケース#1又はケース#2に従います。あなたはまた、良い代替かもしれないが、その前身で置き換えることができます。
if ( X->left && X->right)
{
NODE *Successor = FindSuccessor(X);
X->data = Successor->data;
free(Successor);
}
このバイナリコードは、検索、削除、挿入され、終了します。 例:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Binary Tree {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
LinkedList ll = new LinkedList();
ll.add("\n"+"mai 0020");
ll.add("\n"+"king 0019");
ll.add("\n"+"maan 0002");
ll.add("\n"+"dimple 0024");
ll.add("\n"+"eman 0004");
ll.add("\n"+"lara 0005");
ll.add("\n"+"cute 0008");
ll.add("\n"+"irene 0011");
ll.add("\n"+"sheena 0030");
ll.add("\n"+"aisy 0003");
System.out.println("display: " + ll);
System.out.println("\n\n");
for(int c=0; c<=10; c++) {
System.out.println("select from: 1-insert, 2-delete," +
" 3-display, 4-search, 5-quit");
String x = br.readLine();
int y = Integer.parseInt(x);
switch (y) {
case 1: //inserting
System.out.println("input name");
String n= br.readLine();
System.out.println("input a list number");
String o = br.readLine();
int z = Integer.parseInt(o);
ll.add("\n"+n+" "+z);
break;
case 2: // delete
ll.removeFirst();
break;
case 3: //Display
System.out.println("\n\n"+"List of employee: " + ll);
System.out.println("\n\n");
break;
case 4: //search
System.out.println("\n");
System.out.println("Search");
System.out.println("first element of the Linkedlist is: "
+ ll.getFirst());
System.out.println("\n\n");
System.out.println("last element of linkedlist:"
+ ll.getLast());
break;
case 5: //quit
System.out.println("\n\n\n\n\n"
+ " Thank You Very Much!!!!!!!\n\n\n");
System.exit(0);
break;
}
}
}
}
int delete_value(Tree*&root,Tree*&find,Tree*&ptr,int numb){
if(find->value==number){
//the number exist in the root,so we should find the highest value inside the right brache and replace it with the root.
Tree*ptr2=NULL;
Tree*ptr3=NULL;//pointer pointing to the parent of the last element of ptr2.
ptr2=root->right;
while(ptr2!=NULL){
ptr3=ptr2;
ptr2=ptr2->left;
}
if(ptr2->right!=NULL){
ptr3->left=ptr2->right;
}
swap(ptr2->value,root->value);
delete ptr2;
ptr2=ptr3=NULL;
}
else{
while(find->value!=numb){
if(find->value!=numb){
ptr=find;
}
if(find->value < numb){
find=find->right;
return delete_value(root,find,ptr,numb);
}
else{
find=find->left;
return delete_value(root,find,ptr,numb);
}
}//end of while
}//end of else
//the pointer find is pointing at the element we want to delete.
//the pointer ptr is pointing at the element before the one's we want to delete.
//case 1:the element to delete don't have any children
if(find->right==NULL && find->left==NULL){
if(ptr->left=find){
ptr->left=NULl;
delete find;
}
else{
ptr->right=NULL;
delete find;
}
}//end of the first case.
//case 2:the element has one child it could be to the left or to the right.
//a-child to the right.
if( find->right!=NULL && find->left==NULL ){
Tree*ptr2=find->right;
while(ptr2!=NULL){
ptr2=ptr2->left;//find the highest value in the right branche and replace it with the delete element
}
swap(find->value,ptr2->value);
delete ptr2;
ptr2=NULL;
}
//b-child to the left.
if(find->right==NULL && find->left!=NULL){
Tree*ptr2=find->left;
//check wether the find element is to the right or to the left of ptr.
if(ptr->left==find){
ptr->left=ptr2;
delete find;
}
else{
ptr->right=ptr2;
delete find;
}
}//end of the second case.
//case3: the element has to children.
if(find->right!=NULL&&find->left!=NULL){
Tree*ptr2=find->left;
while(ptr2->right!=NULL){
ptr2=ptr2->right;
}
swap(ptr2->value,find->value);
delete ptr2;
ptr2=NULL;
}//end of case 3.
}//end of the function.