![]() |
| | #1 |
| Registered User Join Date: Mar 2006
Posts: 139
| Help with insert/delete binary search tree I have already coded the insert and delete functions but the delete function is incomplete. There's a couple of things I need help in... 1) Is my insert function good or can it be improved somehow? 2) My delete function lacks the deletion of a node with both the left and right childs. I've searched a lot in the past few hours but couldn't find a proper way to do it. 2.a) How should I delete a node with 2 child nodes? 2.b) As in the first question, is the delete function good or can it be improved? This one I know it can because I'm repeating lots of code in those ifs but I don't see how can I improve it, I need help on that too. You'll probably notice but let me just make 2 remarks:
Now, my code: Code: 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
}
}
}
Last edited by Nazgulled; 03-23-2009 at 06:49 AM. |
| Nazgulled is offline | |
| | #2 |
| Registered User Join Date: Mar 2006
Posts: 139
| Little bump... |
| Nazgulled is offline | |
| | #3 |
| Algorithm Dissector Join Date: Dec 2005 Location: New Zealand
Posts: 2,476
| Actually you are using recursion. In fact you are exclusively using recursion and never using iteration - there are no loops at all in the posted code. Perhaps you meant to say that you are not using iteration? Deletion of a node with two children is done by finding the maximum node of the left-subtree, removing that form the tree, and re-inserting it in place of the node you wish to delete. (Or the minimum node of the right subtree)
__________________ My homepage Advice: Take only as directed - If symptoms persist, please see your debugger |
| iMalc is offline | |
| | #4 |
| Registered User Join Date: Mar 2006
Posts: 139
| You're right... Actually, what I mean was that I wasn't using recursion in the sense of returning a value, instead, I pass the address of structure as an argument. I misunderstood what I wanted to say... Someone else suggested me to use iteration over recursion because of possible stack problems. But I have no clue on how could I do a delete function of a binary search tree, or even just a "print-all-nodes-and-childs" functions without using recursion. I can do that with a linked-list, I just need to use "while" one time, but for a binary search tree with 2 childs? How do I do that? Also, the same person said something about freeing a pointer and then deferencing it: Code: free(cliPtr); cliPtr->clientProfile = NULL; Last edited by Nazgulled; 03-24-2009 at 07:30 AM. |
| Nazgulled is offline | |
| | #5 | |
| Algorithm Dissector Join Date: Dec 2005 Location: New Zealand
Posts: 2,476
| Quote:
In this case you can just delete this line: Code: cliPtr->clientProfile = NULL; Converting tail-recursion into iteration is not particularly hard. However if the function makes two recursive calls then only one of them can be turned into iteration. I'll illustrate how one can make a tree node counting function semi-iterative. Double Recursion: Code: // Returns the number of items in the tree
int TreeCount(const TItem *head) {
int count = 0;
if (head != NULL) {
//recursively count left nodes (add one for this node)
count += TreeCount(head->left) + 1;
//recursively count right nodes
count += TreeCount(head->right);
}
return count;
}
Code: // Returns the number of items in the tree
int TreeCount(const TItem *head) {
int count = 0;
while (head != NULL) {
//recursively count left nodes (add one for this node)
count += TreeCount(head->left) + 1;
//iteratively count right nodes
head = head->right;
}
return count;
}
__________________ My homepage Advice: Take only as directed - If symptoms persist, please see your debugger | |
| iMalc is offline | |
| | #6 | |
| Registered User Join Date: Mar 2006
Posts: 139
| Quote:
I guess free cleans that memory block and the data will still be there until something else overwrites it and it's the day it's supposed to work, right? Hum... After searching a bit for iteration on binary trees I found an algorithm for iterative insert, here's what I did: Code: void addClientToTree(ClientTree *cTree, ClientProfile cProfile) {
if(!*cTree) {
*cTree = newClientTreeNode(cProfile);
return;
}
ClientTree currPtr = *cTree;
int nCompare;
do {
nCompare = strcmp(currPtr->clientName, cProfile->clientName);
if(nCompare > 0) {
if(!currPtr->leftTree) {
currPtr->leftTree = newClientTreeNode(cProfile);
return;
} else {
currPtr = currPtr->leftTree;
}
} else if(nCompare < 0) {
if(!currPtr->rightTree) {
currPtr->rightTree = newClientTreeNode(cProfile);
return;
} else {
currPtr = currPtr->rightTree;
}
}
} while(currPtr && nCompare != 0);
return;
}
Code: ClientTree newClientTreeNode(ClientProfile cProfile) {
ClientTree newClient = malloc(sizeof(nClientTree));
if(!newClient) perror("malloc");
newClient->clientName = strdup(cProfile->clientName);
if(!newClient->clientName) perror("strdup");
newClient->clientProfile = cProfile;
newClient->leftTree = NULL;
newClient->rightTree = NULL;
return newClient;
}
I'll try to convert my delete function into iteration and see if I can also delete a nod with 2 child's... | |
| Nazgulled is offline | |
| | #7 | |
| CSharpener Join Date: Oct 2006
Posts: 5,242
| Quote:
memory does not belongs to your program - it is returned to the memory pool... if this free just returned the last chunk of the memory in some page - the whole page could be already returned to the OS making any address inside this page not available to the program at all. So even read operation from this address could cause a GPF
__________________ If I have eight hours for cutting wood, I spend six sharpening my axe. | |
| vart is offline | |
| | #8 |
| Registered User Join Date: Mar 2006
Posts: 139
| I don't, what I was trying to say is that if I use printf() right after free(), normally, I still see the stuff I freed... |
| Nazgulled is offline | |
| | #9 |
| CSharpener Join Date: Oct 2006
Posts: 5,242
| pure luck
__________________ If I have eight hours for cutting wood, I spend six sharpening my axe. |
| vart is offline | |
| | #10 | |
| C++ Witch Join Date: Oct 2003 Location: Singapore
Posts: 10,359
| Quote:
__________________ C + C++ Compiler: MinGW port of GCC Build + Version Control System: SCons + Bazaar Look up a C/C++ Reference and learn How To Ask Questions The Smart Way | |
| laserlight is online now | |
| | #11 | |
| Registered User Join Date: Mar 2006
Posts: 139
| Quote:
Normally, no, the code that follows the free() is not going to reuse that pointer because when I free() something, it's normally in linked lists or binary trees delete functions (like in the delete function in my first post). So, should or should I not set the pointers to NULL? | |
| Nazgulled is offline | |
| | #12 | |
| Registered User Join Date: Nov 2005
Posts: 146
| Quote:
| |
| Maz is offline | |
| | #13 | |
| C++ Witch Join Date: Oct 2003 Location: Singapore
Posts: 10,359
| Quote:
__________________ C + C++ Compiler: MinGW port of GCC Build + Version Control System: SCons + Bazaar Look up a C/C++ Reference and learn How To Ask Questions The Smart Way | |
| laserlight is online now | |
| | #14 |
| Kernel hacker Join Date: Jul 2007 Location: Farncombe, Surrey, England
Posts: 15,686
| It is indeed fine to set a pointer to NULL immediately after it was freed. However, if you do this: Code: cliPtr->clientProfile = NULL; cliPtr = NULL; -- Mats
__________________ Compilers can produce warnings - make the compiler programmers happy: Use them! Please don't PM me for help - and no, I don't do help over instant messengers. |
| matsp is offline | |
| | #15 |
| Registered User Join Date: Mar 2006
Posts: 139
| I think I get the picture now, thank you... Still, nobody commented on my attempt to do the insert function as iterative instead of recursive, I suppose there's nothing really wrong about it? |
| Nazgulled is offline | |
![]() |
| Tags |
| binary, delete, insert, search, tree |
| Thread Tools | |
| Display Modes | |
|
Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| BST (Binary search tree) | praethorian | C++ Programming | 3 | 11-13-2005 09:11 AM |
| Binary Tree Search | nickname_changed | C++ Programming | 7 | 01-13-2004 12:40 AM |
| Request for comments | Prelude | A Brief History of Cprogramming.com | 15 | 01-02-2004 10:33 AM |
| Binary Search Tree, Inserting node | cheryl_li | C Programming | 1 | 09-13-2003 03:53 AM |
| BST/Red and Black Tree | ghettoman | C++ Programming | 0 | 10-24-2001 10:45 PM |