So i need to define a destructive function BST insertbst(int i, BST t) that inserts i into BST t. That is, it modifies t to include i and returns the resulting tree. The running time must be O(height t).
I have come up with this version ... but gives me the following error's ideone.com/xhxb6
BST insertbst(int i, BST t) {
if (t == NULL) {
return BSTmake(i, NULL, NULL);
} else if (i < BSTkey(t)) {
return BSTmake(BSTkey(t), insertbst(i ,BSTleft(t)), BSTright(t));
} else {
return BSTmake(BSTkey(t), BSTleft(t), insertbst(i ,BSTright(t)));
}
}
The other functions used in my code can be found in: http://pastebin.com/TVYRE4Nd
Any suggestions to make it destructive, or to change it to avoid my heap error?
.h file: http://ideone.com/QeSTl
Test file: http://pastebin.com/9ca5i4My
You cannot use BSTmake() like you are doing now as you are creating a new BST node everytime it is called, where as you can definitely be sure that the new node should only be created only once for each insert.
Now for the following two statements in main
BST x = BSTmake(2, (BSTmake( 1, NULL, NULL)), (BSTmake(3, NULL,NULL)));
BST y = insertbst(4, x);
I don't know your assumption about where y should be pointing to. In general, implementations of a BST would just call insert on their own, passing in the node to be inserted and the root node. You will see that using this approach makes code much simpler to comprehend. You'll have to change your second line as insertbst( 4, &x) to use this pattern.
You would then have to change the implementation of your insertbst as below:
Pass the second argument as a pointer to the node pointer which represents the parent of the newnode.
if BST *t is null, create a new node and assign the pointer to the node to point to it.
if i < BSTkey(t) or i > BSTKey(t), you need to call insertbst() recursively by passing the pointer to either the left subtree or the right subtree as the second argument.
This is what it may look like:
BST insertbst(int i, BST *t) {
if (*t == NULL) {
*t = BSTMake( i, NULL, NULL);
}
else if (BSTkey(newnode) < BSTkey(*t)) {
insertbst( i, &t->left);
}
else {
insertbst( i, &t->right);
}
}
Also malloc() returns a void * which point to the allocated memory chunk. I am assuming BST is has been typedefed something like typedef struct bst_node * BST. Hence you should change the newnode declaration as BST newnode = (BST)malloc(sizeof(struct bst_node));.
Related
I have a function that creates a binary tree, and for each node in the tree, I need to add a node to a separate linked list that points to the node in the binary tree.
My function to create the binary tree:
typedef struct myTree _node;
void INSERT(_node *(*tree), _node *item) {
if (!(*tree)) {
*tree = item;
return;
}
if (item->val < (*tree)->val) {
INSERT(&(*tree)->left, item);
}
else if (item->val > (*tree)->val) {
INSERT(&(*tree)->right);
}
}
My main function:
int main(void) {
int i;
int *balanced;
_node *current, *root;
root = NULL;
for (i = 0; i < size; i++) {
current = (_node *)malloc(sizeof(_node));
current->left = current->right = NULL;
current->val = balanced[i];
INSERT(&root, current);
}
return 0;
}
I've left out parts of my main function for simplicity.
The idea is that I want to print out the contents of the tree in pre, in, and post order, as well as traverse the linked list and print the value of the node in the tree that each linked list node points to.
I'm only a few months into learning C, so I am not terribly advanced.
Much like your insert function is recursive on the tree, walking the tree is recursive as well. There are two ways to do this: the specific way and the generic way. Let's see both.
The specific way just prints values as it encounters them. It solves this specific problem: printing the values. If you have to do tree walks to do more than one thing, you'd have to copy the code, which is generally a bad thing.
On the other hand, the code is much simpler and easier to follow. Let's look at the in-order case (you can do the other two by yourself; they are very similar):
void print_in_order (const struct myTree * tree) {
// if we're in a null node, do nothing
if (!tree) return;
// otherwise, do the left subtree, then the current node, then the right subtree
// non-existent subtrees will be handled by the above check, so don't check twice
print_in_order(tree -> left);
printf("%d\n", tree -> val);
print_in_order(tree -> right);
}
The generic way, on the other hand, is a better approach if your program is doing tree walks for all sorts of purposes. The idea is that you encapsulate the actual task to be done at each node (in this case, printing it) in a separate function:
void print_node (const struct myTree * node) {
printf("%d\n", node -> val);
}
And then you write a function that takes this function as an argument and calls it on each node, in the corresponding order. Let's do it for in-order:
void apply_in_order (const struct myTree * tree,
void (* callback)(const struct myTree *)) {
// this is the same as before...
if (!tree) return;
apply_in_order(tree -> left, callback);
// ...except that, instead of doing a specific thing, we call the callback on each node
callback(tree);
apply_in_order(tree -> right, callback);
}
Now, you just call this function as apply_in_order(tree, print_node); and you get the same behavior as above. But the next time you need to write a function that walks a tree, you only need the per-node thing; the rest is already done.
I'm trying to create a method for inserting nodes into a BST with the following structs:
// node structure
struct Node {
int val;
struct Node* left;
struct Node* right;
};
// binary tree structure
struct BinaryTree {
struct Node* root;
};
Originally I created this method for adding nodes to the tree:
// add value to binary tree
void _AddNode(struct Node* node, int val) {
if (node == NULL)
*(&node) = CreateNode(val);
else if (val <= node->val)
_AddNode(node->left, val);
else
_AddNode(node->right, val);
}
void AddNode(struct BinaryTree* tree, int val) {
_AddNode(tree->root, val);
}
Using this function to construct the tree, I get a Segmentation fault: 11 error when I try to traverse, print, access data from the tree.
However, when I modified the function to pass in a double pointer and effectively do the same thing it worked:
// add value to binary tree
void _AddNode(struct Node** node, int val) {
if (*node == NULL)
*node = CreateNode(val);
else if (val <= (*node)->val)
_AddNode(&(*node)->left, val);
else
_AddNode(&(*node)->right, val);
}
void AddNode(struct BinaryTree* tree, int val) {
_AddNode(&tree->root, val);
}
Why does the latter work, but the former doesn't.
However, when I modified the function to pass in a double pointer and effectively do the same thing it worked
Substantially the same thing, on fundamentally different data. The (&node) in your original attempt gives you a pointer to a local variable. When you dereference that and assign to the result, you are therefore modifying the local variable. Such a modification is not visible in any way to the caller.
On the other hand if you pass (say) a suitable double pointer to your function, say _AddNode(&(*node)->left, 42), then the value of the function parameter points to the same thing: the (*node)->left of the caller. If you dereference that pointer and assign to the result then naturally that is visible to the caller.
It seems that both the original and modified function are identical
Clearly, they are not lexically identical. You seem to mean that they appear to you to be equivalent, but since the difference in behavior disproves such an equivalence, it stands to reason that the manifest differences in the two functions in fact produce different semantics. The key thing that seems to have confused you is that in C, function arguments are always passed by value, so each function parameter starts with the value passed by the caller, but is not an alias for the caller's corresponding argument. Parameters of pointer type are no exception.
I wrote this binary search tree data structure but I can't seem to figure out why or how the first node being printed is ZERO (0).
My code is publicly accessible here on ideone
void insert_tree(tree **l, int x, tree *parent)
{
tree *p; /* temp pointer */
if (*l == NULL) {
p = malloc(sizeof(tree));
p->item = x;
p->left = p->right = NULL;
p->parent = parent;
*l = p; /* link into parent's record */
return;
}
if (x < (*l)->item)
insert_tree(&((*l)->left), x, *l);
else
insert_tree(&((*l)->right), x, *l);
}
I think my confusion lies in the indirection and use of pointers (and pointer to pointer). I understand there are other ways to go about it but I am trying to stick with this particular use of pointers for good reason.
The problem in your code is that you are adding an empty node in the main, without initializing its item, left, or right: when you do this
tree *root = malloc(sizeof(tree));
the root gets assigned an uninitialized chunk of memory. You could place the first element into the first element directly, but this is not necessary: your insertion code already handles the situation when the root is NULL.
When you change your code to assign root a NULL, like this,
tree *root = NULL;
your program works correctly (demo).
I have a homework assignment to implement a binary search tree (create, delete, search). I used the example provided by the teacher but I can't make it work.
Here's my code so far:
void insert_node(int k){
struct node *nodnou,*flow,*parent;
nodnou = (struct node*)malloc(sizeof(node));
nodnou->st = NULL;
nodnou->dr = NULL;
nodnou->nr = k;
if (root==NULL)
{
root = (struct node*)malloc(sizeof(node));
root = nodnou;
}
else
{
flow = (struct node*)malloc(sizeof(node));
parent = (struct node*)malloc(sizeof(node));
flow = root;
parent = root;
while (((flow->st!=NULL) || (flow->dr!=NULL)) && flow!=NULL)
{
if (k<flow->nr)
{
parent = flow;
flow = flow->st;
}
else
{
parent = flow;
flow = flow->dr;
}
}
if (k<flow->nr)
{
parent->st = nodnou;
}
else
{
parent->dr = nodnou;
}
}
}
The way of thinking: This function gets the value of the node we want to insert as the k parameter. The function will only insert the root of the tree (root is global variable).
I think my biggest problem is the while loop that sweeps through the tree to find the spot for the new node.
If I use while (flow!=NULL) it won't work because the flow pointer gets an assignment to something that does not exist. Please help me understand where I am wrong (homework).
Your code has several important flaws, not the least of which is a misunderstanding of how dynamic memory allocation works in C. Never follow a pattern like this:
Type *pointer = malloc(sizeof(Type));
pointer = <<something else>>
It literally leaks memory and gains you nothing in two short lines. This isn't an object-reference based language like Java or C#. Pointers are variables that hold memory addresses. Just like an int can hold an integer, a pointer holds an address. And just like the following example:
int n = 6;
n = 5; //Hmm. Where did the 6 go? Oh yeah, We overwrote it with 5.
You will lose your allocation link doing the same thing with pointers:
struct node *root = malloc(sizeof(*root));
root = nodnou; // memory allocated above is gone. forever leaked.
Pointers are variables. Just like any other variable, they hold values. In the case of a pointer, however, its value is an address. You can have pointers to almost anything in C, including pointers to pointers; variables that hold the address of pointer variables. And I bring them up because they proffer a particularly elegant solution to your insertion requirements.
The following is a general implementation for a binary tree insertion that supports no duplicates in the tree (the code gets even shorter if you allow duplicates). Furthermore, it does this using exactly zero local variables beyond the provided function parameters, and I challenge you to dissect this and determine how it works. It even works on an initially NULL tree root pointer, eliminating the need to special casing if (root) {} else {} logic:
void insert_node(struct node **pp, int k)
{
while (*pp)
{
if (k < (*pp)->nr) // move down left side?
pp = &(*pp)->st;
else if ((*pp)->nr < k) // move down right side?
pp = &(*pp)->dr;
else return; // found the key, no dupes. leave
}
// pp contains the address of the pointer we need to set.
*pp = malloc(sizeof(**pp));
(*pp)->st = (*pp)->dr = NULL;
(*pp)->nr = k;
}
If your tree should support duplicates you need to be consistent about which side they are inserted on, but it shortens the above algorithm considerably:
void insert_node(struct node **pp, int k)
{
while (*pp)
pp = (k < (*pp)->nr) ? &(*pp)->st : &(*pp)->dr;
// pp contains the address of the pointer we need to set.
*pp = malloc(sizeof(**pp));
(*pp)->st = (*pp)->dr = NULL;
(*pp)->nr = k;
}
In either case, invoked on the caller side like this:
struct node *root = NULL;
insert(&root, 5);
insert(&root, 10);
insert(&root, 7);
...etc...
I think you should use while(flow != NULL) and insert your element as flow after that. The way it is right now it will stop in cases when it shouldn't and do weird things whenever it stops. Try working through some examples with pen and paper.
You almost got it. Keep Up!
First you need to understand a bit better memory allocation. In reality, you only need the very first malloc() call in your function. That is the memory you allocate for the node you are appending to the tree during each insert_node() call. All remainingr mallocs you are performing are unnecesary. It seems that you intuitively feel you need to allocate memory for the other pointers you are using, but all of them are temporary and don't require any allocation, just assignment to a valid node before attempting to de-reference them. In fact, those unnecesary allocations will create what is known as a memory leak (memory you request and fail to release) in code like this:
root = (struct node*)malloc(sizeof(node));
root = nodnou;
The second assignmet (root = nodnou) overwrites the result of the previous malloc() call and since you didn't save the overwritten pointer value in any other place, you will no longer be able to release that memory, it will be marked as used for the lifetime of your application!
Next, you can simplify the code that is walking the tree looking for the insertion point.
You seem to worry that flow becomes NULL, but it doesn't matter. The important node is parent. After the while loop ends, it will be pointing to the actual node where the inserted node needs to be linked. Here is a modified version of your code.
void insert_node(int k) {
struct node *nodnou, *flow, *parent;
// this is the only memory allocation that should be done
nodnou = (struct node*)malloc(sizeof(node));
nodnou->st = NULL;
nodnou->dr = NULL;
nodnou->nr = k;
parent = NULL;
if( root == NULL ) {
root = nodnou;
} else {
flow = root;
// We will walk the tree in order until we reach the bottom of the
// tree (flow becomes null). What we are trying to do is to find out
// the node that will become the parent of the new node we are inserting
// It doesn't matter if flow becomes NULL, the important value after the
// while loop ends is parent
while( flow != NULL ) {
// update the current potential parent node
parent = flow;
if( k < flow->nr ) {
// the number we are inserting is lower than the flow node, walk to the left
flow = flow->st;
} else {
// the number we are inserting is greater or equal than the flow node,
// walk to the right
flow = flow->dr;
}
}
// We have reached the bottom, now compare number again with the node that
// will become parent, to find out if we need to link this node to the left
// or to the right of the parent node
if( k < parent->nr ) {
parent->st = nodnou;
} else {
parent->dr = nodnou;
}
}
}
That's it. Try to code the rest of the tree operations and don't hesitate to ask if you become confused. =)
I wrote the following function which returns the middle element of a linked list, which uses the double pointer method
struct node
{
int data;
struct node *next;
}*start;
void middleelement()
{
struct node *x=start,*y=start;
int n=0;
if(start==NULL)
{
printf("\nThere are no elments in the list");
}
else
{
while((x->next)!=NULL)
{
x=x->next->next;
y=y->next;
n++;
}
printf("\nMiddle element is %d",y->data);
}
}
However, whenever I run the functions, the Windows explorer stops working
What is the flaw in the code?
Is there any better algorithm than this to find the middle element?
If the number of entries is odd, your x will end up being NULL, so when the next loop iteration dreferences it, your program is going to crash. You should modify your condition to account for that:
while(x && x->next) {
...
}
Comparing with NULL is optional in C, so you can skip the != NULL to shorten the condition.
Of course passing the start parameter through a global variable is unorthodox, to say the least. It would be much better to pass it as a regular function parameter.