I have an assignment to write a self balancing binary search tree. I decided to use an AVL tree as it is what we have discussed in class. Then with the given input of { 3, 5, 61, 9, 32, 7, 1, 45, 26, 6} I'm expecting an output of:
7
6-----|-----32
3----| 9----|----45
1---| |---26 |---61
That is, unless I have grossly misunderstood and thus miscalculated what an AVL tree is supposed to do when it balances itself. The output I'm getting is quite different:
5
3-----|-----61
1----| 9----|
7---|---32
6--| 26--|--45
Again, unless I am completely wrong, that tree is not balanced. The function I'm using to set up the tree is defined as such:
node* insertKeyAVL(node* n, int e)
{
int cmpVal;
if (n == NULL){
n = create_node();
n->data = e;
} else if (e < n->data) {
if (n->left == NULL){
n->left = create_node();
n->left->data = e;
n->left->parent = n;
} else {
n->left = insertKeyAVL(n->left, e);
}
cmpVal = height(n->left) - height(n->right);
} else {
if (n->right == NULL){
n->right = create_node();
n->right->data = e;
n->right->parent = n;
} else {
n->right = insertKeyAVL(n->right, e);
}
cmpVal = height(n->right) - height(n->left);
}
if (cmpVal > 2){
if (n->left){
if (e < n->left->data)
n = rotate_left(n);
else
n = rotate_right_left(n);
} else if (n->right){
if (e > n->right->data)
n = rotate_right(n);
else
n = rotate_left_right(n);
}
}
n->height = max(height(n->left), height(n->right)) + 1;
return n;
}
The structure I'm using to store all the data is defined as such:
typedef struct node
{
struct node *parent;
struct node* left;
struct node* right;
int data;
int height;
} node;
The functions rotate_left_right and rotate_right_left are basic functions that rotate the direction of the first post-fix then the second post-fix, and are both reliant on rotate_left and rotate_right for their respective direction. rotate left is defined as such:
node* rotate_left(node* n)
{
node* tmp = n->left;
n->left = tmp->right;
tmp->right = n;
tmp->parent = n->parent;
n->parent = tmp;
n->height = max(height(n->left), height(n->right)) + 1;
tmp->height = max(height(tmp->left), n->height) + 1;
return tmp;
}
rotate_right is similar but adjusted for a rotation right.
I'm wondering where this code messes up so that it doesn't produce the desired output.
when you add 26 in your expected result cmpval for 5 become 2 which is not valid that's why code re-execute and give result as yours.
I don't have a full answer and I'm not sure your code is salvageable, since it misses a lot of pieces. Main source of surprise is the missing initialization of cmpVal which is then compared to 2. But if n is NULL its UB.
cmpVal is the balance of AVL but with an absolute value. Unfortunately when rebalancing you check the existence of a left child or of a right child. But this tells you nothing. You need to know the sign of the balance in order to choose the rotation direction. You can have both children and still need to balance.
Your insertion looks strange because after checking that the node is not NULL you check the children for the same thing. But recursion here would have saved the two checks entirely by performing the check for you.
Related
So I need to do a depth first search traversal of a given graph, however if a node in the graph has multiple adjacent neighbours, I need to choose the node with the lowest value to go to. So I implemented the following recursive depth first search function:
void DFS(struct Graph *graph, int vertex) {
struct node *adjList = graph->adjLists[vertex];
struct node *temp = adjList;
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
int neighbouring_nodes[graph->numVertices];
while (temp != NULL) {
int count = 0;
struct node *temp_cpy = temp;
while (temp_cpy != NULL) {
neighbouring_nodes[count] = temp_cpy->vertex;
count++;
temp_cpy = temp_cpy->next;
}
int smallest_node = neighbouring_nodes[0];
for (int i = 0; i < count; i++) {
if (neighbouring_nodes[i] < smallest_node) {
smallest_node = neighbouring_nodes[i];
}
}
if (graph->visited[smallest_node] == 0) {
DFS(graph, smallest_node);
} else if (graph->visited[smallest_node] == 1 && count == 1) {
//if the node is visited but is it the only neighbour
DFS(graph, smallest_node);
}
temp = temp->next;
}
}
But when I run my program, it results in an infinite loop. I think I know why I am getting an infinite loop, it might be because there is never a return condition, so the recursive function just keeps running?
Is this type of depth first search possible with a recursive function? If yes, where am I going wrong? If no, how would I do it iteratively?
Help would be much appreciated.
Below is my full program without the DFS function:
// DFS algorithm in C
#include <stdio.h>
#include <stdlib.h>
struct node {
int vertex;
struct node *next;
};
struct node *createNode(int v);
struct Graph {
int numVertices;
int *visited;
struct node **adjLists;
};
// Create a node
struct node *createNode(int v) {
struct node *newNode = malloc(sizeof(struct node));
newNode->vertex = v;
newNode->next = NULL;
return newNode;
}
// Create graph
struct Graph *createGraph(int vertices) {
struct Graph *graph = malloc(sizeof(struct Graph));
graph->numVertices = vertices;
graph->adjLists = malloc(vertices * sizeof(struct node*));
graph->visited = malloc(vertices * sizeof(int));
int i;
for (i = 0; i < vertices; i++) {
graph->adjLists[i] = NULL;
graph->visited[i] = 0;
}
return graph;
}
// Add edge
void addEdge(struct Graph *graph, int src, int dest) {
// Add edge from src to dest
struct node *newNode = createNode(dest);
newNode->next = graph->adjLists[src];
graph->adjLists[src] = newNode;
// Add edge from dest to src
newNode = createNode(src);
newNode->next = graph->adjLists[dest];
graph->adjLists[dest] = newNode;
}
// Print the graph
void printGraph(struct Graph *graph) {
int v;
for (v = 0; v < graph->numVertices; v++) {
struct node *temp = graph->adjLists[v];
printf("\n Adjacency list of vertex %d\n ", v);
while (temp) {
printf("%d -> ", temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
int main() {
struct Graph *graph = createGraph(4);
addEdge(graph, 0, 1);
addEdge(graph, 0, 2);
addEdge(graph, 1, 2);
addEdge(graph, 2, 3);
printGraph(graph);
DFS(graph, 2);
return 0;
}
"if a node in the graph has multiple adjacent neighbours, I need to choose the node with the lowest value to go to."
I assume the 'value' of a node is an attribute of the node object?
Most implementations of DFS will first look at the node with the lowest index in the data structure containing the node objects. So, if you first sort the nodes in your data structure into ascending value order, then the DFS will do what you want without needing to change the DFS code.
Here is what I came up with:
void DFS(struct Graph* graph, int vertex) {
struct node* temp = graph->adjLists[vertex];
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
int neighbouring_nodes[graph->numVertices];
int count = 0;
while(temp != NULL) {
neighbouring_nodes[count] = temp->vertex;
count++;
temp = temp->next;
}
int smallest_node = neighbouring_nodes[0];
// Need to search (at most) in every neighbouring node
for (int i = 0; i < count; i++) {
// Go through all nodes in neighbouring_nodes array in order
// to find the smallest unvisited one, if it exists
for (int j = 0; j < count; j++){
// if current smallest_node has already been visited and
// neighbouring_nodes[j] is unvisited, assign it to smallest_node
if (graph->visited[smallest_node] == 1 && graph->visited[neighbouring_nodes[j]] == 0){
smallest_node = neighbouring_nodes[j];
}
// if neighbouring_nodes[j] is smaller than smallest_node,
// assign it to smallest_node
if (graph->visited[neighbouring_nodes[j]] == 0 && neighbouring_nodes[j] < smallest_node){
smallest_node = neighbouring_nodes[j];
}
}
if (graph->visited[smallest_node] == 0){
// calls DFS on the smallest unvisited neighboring node, if it exists
DFS(graph, smallest_node);
}else{
// otherwise (all neighboring nodes already visited)
// return control to the caller function
return;
}
}
}
I'm not 100% sure I understood what you wanted to do with the while (temp != NULL) and while (temp_cpy != NULL) loops but couldn't really figure out a way to use this approach especially in your particular case in which you want to visit the neighboring nodes in ascending order.
Let's assume a simple graph like 6->0->1, calling DFS(g, 0) will get temp to point to 6->1->NULL (could be also 1->6->NULL, depending on how you construct the graph), then smallest_node will be 1 and therefore the node 1 will be visited and the temp = temp->next will "assign" 1->NULL to temp. Back to the beginning of the loop, now temp_cpy will "be equal" to temp, hence 1->NULL. The node 6 is not on the list anymore even if it was not visited, on the other hand the already visited node 1 is still there. Also count is now equal to 1 therefore the condition (graph->visited[smallest_node] == 1 && count == 1) is met and DFS(g, 1) is called, which should not since node 1 was already visited. The infinite loop arises from this, since the previous condition is always met when temp has one (already visited) element left ([some value]->NULL). Once you reach that point you always call DFS(g, [some value]) and this will never give back control, since before reaching the temp = temp->next statement (which should assign NULL to temp , hence ending the while loop), DFS(g, [some other value]) is again called, which at some point will again call DFS(g, [some value]), and so forth.
As mentioned, one problem your original code has is that you call the DFS function also for an already visited vertex, and this should never be the case. When you encounter an already visited neighboring vertex, you want either to check the next or, if there are no unvisited neighboring vertices left, to give back control to the caller function. Therefore the last if else statement should not be there. The second problem is that smallest_node is selected in the wrong way. This is because temp_cpy, as explained above, is not constructed in such a way that it necessarily contains all unvisited neighboring nodes and also because you're actually looking for the smallest element in this list, regardless if it has already been visited or not (again because of the assumption that temp_cpy contains only all unvisited nodes). In fact you should be looking for the "smallest unvisited node" rather than the "smallest node".
In my code I go through all neighboring nodes with two for loops, find the smallest unvisited one and call DFS(g, [smallest unvisited node]) and once there are no unvisited neighbors left, return control back to the caller function.
I Hope this is somewhat understandable and I also hope I'm not missing something about what you had in mind with your implementation, in which case I would be very much interested in some explanations!
Here is a simpler version of the DFS in which neighboring nodes are checked and eventually visited in the order they're presented in the adjList. In this case I think the while (temp != NULL)/temp = temp->next approach makes sense:
void DFS(struct Graph *graph, int vertex) {
struct node *temp = graph->adjLists[vertex];
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
// for vertex search in every neighboring node
while (temp != NULL) {
// if neighboring vertex temp->vertex not visited, then search there
if (graph->visited[temp->vertex] == 0) {
DFS(graph, temp->vertex);
// if already visited, go to the next vertex on the neighbors list
}else{
temp = temp->next;
}
}
// when searched in all neighboring vertexes return control to caller
return;
}
I have recently implemented a normal B-tree (without any variant) in C, but I would like to check if my implementation is valid i.e. if it does not violate the following properties:
Every node has at most m children.
Every non-leaf node (except root) has at least ⌈m/2⌉ child nodes.
The root has at least two children if it is not a leaf node.
A non-leaf node with k children contains k − 1 keys.
All leaves appear in the same level and carry no information.
Could help me with the implementation of this procedure giving me an example with some code in C or with some suggestions?
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define EMPTY 0
#define NODE_ORDER 3 /*The degree of the tree.*/
#define NODE_POINTERS (NODE_ORDER*2)
#define NODE_KEYS NODE_POINTERS-1
typedef unsigned char bool;
typedef struct tree_node {
int key_array[NODE_KEYS];
struct tree_node *child_array[NODE_POINTERS];
unsigned int key_index;
bool leaf;
} node_t;
typedef struct {
node_t *node_pointer;
int key;
bool found;
unsigned int depth;
} result_t;
typedef struct {
node_t *root;
unsigned short order;
bool lock;
} btree_t;
static int BTreeGetLeftMax(node_t *T);
static int BTreeGetRightMin(node_t *T);
/* The AllocateNode operation allocate a b-tree node.And then set the node's
** properties to the defualt value :
** BTreeNode => K[i] = 0
** BTreeNode => child_array[i] = NULL
** BTreeNode => key_index = 0
** BTreeNode => isLeaf = 1;
*/
static node_t *create_node()
{
int i;
node_t *new_node = (node_t *)malloc(sizeof(node_t));
if(!new_node){
printf("Out of memory");
exit(0);
}
// Set Keys
for(i = 0;i < NODE_KEYS; i++){
new_node->key_array[i] = 0;
}
// Set ptr
for(i = 0;i < NODE_POINTERS; i++){
new_node->child_array[i] = NULL;
}
new_node->key_index = EMPTY;
new_node->leaf = TRUE;
return new_node;
}
/* The CreatBTree operation creates an empty b-tree by allocating a new root
** that has no keys and is a leaf node.Only the root node is permitted to
** have this properties.
*/
btree_t *create_btree()
{
btree_t *new_root = (btree_t *)malloc(sizeof(btree_t));
if(!new_root){
return NULL;
}
node_t *head = create_node();
if(!head){
return NULL;
}
new_root->order = NODE_ORDER;
new_root->root = head;
new_root->lock = FALSE;
return new_root;
}
static result_t *get_resultset()
{
result_t *ret = (result_t *)malloc(sizeof(result_t));
if(!ret){
printf("ERROR! Out of memory.");
exit(0);
}
ret->node_pointer = NULL;
ret->key = 0;
ret->found = FALSE;
ret->depth = 0;
return ret;
}
/* The BTreeSearch operation is to search X in T.Recursively traverse the tree
** from top to bottom.At each level, BTreeSearch choose the maximum key whose
** value is greater than or equal to the desired value X.If equal to the
** desired ,found.Otherwise continue to traverse.
*/
result_t *search(int key, node_t *node)
{
print_node(node);
int i = 0;
while((i < node->key_index) && (key > node->key_array[i])){
//printf("it %d is <= %d and key %d > than %d\n", i, node->key_index, key, node->key_array[i]);
i++;
}
//printf("end iterator: %d\n", i);
//printf("better: \n");
/*
int c = 0;
while((c < node->key_index) && (key > node->key_array[c])){
printf("it %d is <= %d and key %d > than %d\n", c, node->key_index, key, node->key_array[c]);
c++;
}
*/
// HACK /// may not be working
if(i == 6){
i--;
}
// Check if we found it
if((i <= node->key_index) && (key == node->key_array[i])){
result_t *result = get_resultset();
result->node_pointer = node;
result->key = i;
result->found = TRUE;
return result;
}
// Not found check leaf or child
if(node->leaf){
result_t *result = get_resultset();
result->node_pointer = node;
result->found = FALSE;
return result;
}else{
result_t *result = get_resultset();
return search(key, node->child_array[i]);
}
}
/* The split_child operation moves the median key of node child_array into
** its parent ptrParent where child_array is the ith child of ptrParent.
*/
static void split_child(node_t *parent_node, int i, node_t *child_array)
{
int j;
//Allocate a new node to store child_array's node.
node_t *new_node = create_node();
new_node->leaf = child_array->leaf;
new_node->key_index = NODE_ORDER-1;
//Move child_array's right half nodes to the new node.
for(j = 0;j < NODE_ORDER-1;j++){
new_node->key_array[j] = child_array->key_array[NODE_ORDER+j];
}
//If child_array is not leaf node,then move child_array's [child_array]s to the new
//node's [child_array]s.
if(child_array->leaf == 0){
for(j = 0;j < NODE_ORDER;j++){
new_node->child_array[j] = child_array->child_array[NODE_ORDER+j];
}
}
child_array->key_index = NODE_ORDER-1;
//Right shift ptrParent's [child_array] from index i
for(j = parent_node->key_index;j>=i;j--){
parent_node->child_array[j+1] = parent_node->child_array[j];
}
//Set ptrParent's ith child_array to the newNode.
parent_node->child_array[i] = new_node;
//Right shift ptrParent's Keys from index i-1
for(j = parent_node->key_index;j>=i;j--){
parent_node->key_array[j] = parent_node->key_array[j-1];
}
//Set ptrParent's [i-1]th Key to child_array's median [child_array]
parent_node->key_array[i-1] = child_array->key_array[NODE_ORDER-1];
//Increase ptrParent's Key number.
parent_node->key_index++;
}
/* The BTreeInsertNonFull operation insert X into a non-full node T.before
** execute this operation,guarantee T is not a full node.
*/
static void insert_nonfull(node_t *n, int key){
int i = n->key_index;
if(n->leaf){
// Shift until we fit
while(i>=1 && key<n->key_array[i-1]){
n->key_array[i] = n->key_array[i-1];
i--;
}
n->key_array[i] = key;
n->key_index++;
}else{
// Find the position i to insert.
while(i>=1 && key<n->key_array[i-1]){
i--;
}
//If T's ith child_array is full,split first.
if(n->child_array[i]->key_index == NODE_KEYS){
split_child(n, i+1, n->child_array[i]);
if(key > n->key_array[i]){
i++;
}
}
//Recursive insert.
insert_nonfull(n->child_array[i], key);
}
}
/* The BTreeInsert operation insert key into T.Before insert ,this operation
** check whether T's root node is full(root->key_index == 2*d -1) or not.If full,
** execute split_child to guarantee the parent never become full.And then
** execute BTreeInsertNonFull to insert X into a non-full node.
*/
node_t *insert(int key, btree_t *b)
{
if(!b->lock){
node_t *root = b->root;
if(root->key_index == NODE_KEYS){ //If node root is full,split it.
node_t *newNode = create_node();
b->root = newNode; //Set the new node to T's Root.
newNode->leaf = 0;
newNode->key_index = 0;
newNode->child_array[0] = root;
split_child(newNode, 1, root);//Root is 1th child of newNode.
insert_nonfull(newNode, key); //Insert X into non-full node.
}else{ //If not full,just insert X in T.
insert_nonfull(b->root, key);
}
}else{
printf("Tree is locked\n");
}
return b->root;
}
/* The merge_children operation merge the root->K[index] and its two child
** and then set chlid1 to the new root.
*/
static void merge_children(node_t *root, int index, node_t *child1, node_t *child2){
child1->key_index = NODE_KEYS;
int i;
//Move child2's key to child1's right half.
for(i=NODE_ORDER;i<NODE_KEYS;i++)
child1->key_array[i] = child2->key_array[i-NODE_ORDER];
child1->key_array[NODE_ORDER-1] = root->key_array[index]; //Shift root->K[index] down.
//If child2 is not a leaf node,must copy child2's [ptrchlid] to the new
//root(child1)'s [child_array].
if(0 == child2->leaf){
for(i=NODE_ORDER;i<NODE_POINTERS;i++)
child1->child_array[i] = child2->child_array[i-NODE_ORDER];
}
//Now update the root.
for(i=index+1;i<root->key_index;i++){
root->key_array[i-1] = root->key_array[i];
root->child_array[i] = root->child_array[i+1];
}
root->key_index--;
free(child2);
}
/* The BTreeBorrowFromLeft operation borrows a key from leftPtr.curPtr borrow
** a node from leftPtr.root->K[index] shift down to curPtr,shift leftPtr's
** right-max key up to root->K[index].
*/
static void BTreeBorrowFromLeft(node_t *root, int index, node_t *leftPtr, node_t *curPtr){
curPtr->key_index++;
int i;
for(i=curPtr->key_index-1;i>0;i--)
curPtr->key_array[i] = curPtr->key_array[i-1];
curPtr->key_array[0] = root->key_array[index];
root->key_array[index] = leftPtr->key_array[leftPtr->key_index-1];
if(0 == leftPtr->leaf)
for(i=curPtr->key_index;i>0;i--)
curPtr->child_array[i] = curPtr->child_array[i-1];
curPtr->child_array[0] = leftPtr->child_array[leftPtr->key_index];
leftPtr->key_index--;
}
/* The BTreeBorrowFromLeft operation borrows a key from rightPtr.curPtr borrow
** a node from rightPtr.root->K[index] shift down to curPtr,shift RightPtr's
** left-min key up to root->K[index].
*/
static void BTreeBorrowFromRight(node_t *root, int index, node_t *rightPtr, node_t *curPtr){
curPtr->key_index++;
curPtr->key_array[curPtr->key_index-1] = root->key_array[index];
root->key_array[index] = rightPtr->key_array[0];
int i;
for(i=0;i<rightPtr->key_index-1;i++)
rightPtr->key_array[i] = rightPtr->key_array[i+1];
if(0 == rightPtr->leaf){
curPtr->child_array[curPtr->key_index] = rightPtr->child_array[0];
for(i=0;i<rightPtr->key_index;i++)
rightPtr->child_array[i] = rightPtr->child_array[i+1];
}
rightPtr->key_index--;
}
/* The BTreeDeleteNoNone operation recursively delete X in root,handle both leaf
** and internal node:
** 1. If X in a leaf node,just delete it.
** 2. If X in a internal node P:
** a): If P's left neighbor -> prePtr has at least d keys,replace X with
** prePtr's right-max key and then recursively delete it.
** b): If P's right neighbor -> nexPtr has at least d keys,replace X with
** nexPtr's left-min key and then recursively delete it.
** c): If both of prePtr and nexPtr have d-1 keys,merge X and nexPtr into
** prePtr.Now prePtr have 2*d-1 keys,and then recursively delete X in
** prePtr.
** 3. If X not in a internal node P,X must in P->child_array[i] zone.If child_array[i]
** only has d-1 keys:
** a): If child_array[i]'s neighbor have at least d keys,borrow a key from
** child_array[i]'s neighbor.
** b): If both of child_array[i]'s left and right neighbor have d-1 keys,merge
** child_array[i] with one of its neighbor.
** finally,recursively delete X.
*/
static void BTreeDeleteNoNone(int X, node_t *root){
int i;
//Is root is a leaf node ,just delete it.
if(1 == root->leaf){
i=0;
while( (i<root->key_index) && (X>root->key_array[i])) //Find the index of X.
i++;
//If exists or not.
if(X == root->key_array[i]){
for(;i<root->key_index-1;i++)
root->key_array[i] = root->key_array[i+1];
root->key_index--;
}
else{
printf("Node not found.\n");
return ;
}
}
else{ //X is in a internal node.
i = 0;
node_t *prePtr = NULL, *nexPtr = NULL;
//Find the index;
while( (i<root->key_index) && (X>root->key_array[i]) )
i++;
if( (i<root->key_index) && (X == root->key_array[i]) ){ //Find it in this level.
prePtr = root->child_array[i];
nexPtr = root->child_array[i+1];
/*If prePtr at least have d keys,replace X by X's precursor in
*prePtr*/
if(prePtr->key_index > NODE_ORDER-1){
int aPrecursor = BTreeGetLeftMax(prePtr);
root->key_array[i] = aPrecursor;
//Recursively delete aPrecursor in prePtr.
BTreeDeleteNoNone(aPrecursor,prePtr);
}
else
if(nexPtr->key_index > NODE_ORDER-1){
/*If nexPtr at least have d keys,replace X by X's successor in
* nexPtr*/
int aSuccessor = BTreeGetRightMin(nexPtr);
root->key_array[i] = aSuccessor;
BTreeDeleteNoNone(aSuccessor,nexPtr);
}
else{
/*If both of root's two child have d-1 keys,then merge root->K[i]
* and prePtr nexPtr. Recursively delete X in the prePtr.*/
merge_children(root,i,prePtr,nexPtr);
BTreeDeleteNoNone(X,prePtr);
}
}
else{ //Not find in this level,delete it in the next level.
prePtr = root->child_array[i];
node_t *leftBro = NULL;
if(i<root->key_index)
nexPtr = root->child_array[i+1];
if(i>0)
leftBro = root->child_array[i-1];
/*root->child_array[i] need to borrow from or merge with his neighbor
* and then recursively delete. */
if(NODE_ORDER-1 == prePtr->key_index){
//If left-neighbor have at least d-1 keys,borrow.
if( (leftBro != NULL) && (leftBro->key_index > NODE_ORDER-1))
BTreeBorrowFromLeft(root,i-1,leftBro,prePtr);
else //Borrow from right-neighbor
if( (nexPtr != NULL) && (nexPtr->key_index > NODE_ORDER-1))
BTreeBorrowFromRight(root,i,nexPtr,prePtr);
//OR,merge with its neighbor.
else if(leftBro != NULL){
//Merge with left-neighbor
merge_children(root,i-1,leftBro,prePtr);
prePtr = leftBro;
}
else //Merge with right-neighbor
merge_children(root,i,prePtr,nexPtr);
}
/*Now prePtr at least have d keys,just recursively delete X in
* prePtr*/
BTreeDeleteNoNone(X,prePtr);
}
}
}
/*Get T's left-max key*/
static int BTreeGetLeftMax(node_t *T){
if(0 == T->leaf){
return BTreeGetLeftMax(T->child_array[T->key_index]);
}else{
return T->key_array[T->key_index-1];
}
}
/*Get T's right-min key*/
static int BTreeGetRightMin(node_t *T){
if(0 == T->leaf){
return BTreeGetRightMin(T->child_array[0]);
}else{
return T->key_array[0];
}
}
/* The BTreeDelete operation delete X from T up-to-down and no-backtrack.
** Before delete,check if it's necessary to merge the root and its children
** to reduce the tree's height.Execute BTreeDeleteNoNone to recursively delete
*/
node_t *delete(int key, btree_t *b)
{
if(!b->lock){
//if the root of T only have 1 key and both of T's two child have d-1
//key,then merge the children and the root. Guarantee not need to backtrack.
if(b->root->key_index == 1){
node_t *child1 = b->root->child_array[0];
node_t *child2 = b->root->child_array[1];
if((!child1) && (!child2)){
if((NODE_ORDER-1 == child1->key_index) && (NODE_ORDER-1 == child2->key_index)){
//Merge the children and set child1 to the new root.
merge_children(b->root, 0, child1, child2);
free(b->root);
BTreeDeleteNoNone(key, child1);
return child1;
}
}
}
BTreeDeleteNoNone(key, b->root);
}else{
printf("Tree is locked\n");
}
return b->root;
}
void tree_unlock(btree_t *r)
{
r->lock = FALSE;
}
bool tree_lock(btree_t *r)
{
if(r->lock){
return FALSE;
}
r->lock = TRUE;
return TRUE;
}
You have not shown any code, which makes it difficult to come up with code examples that could fit to your implementation. However, in principle you could take the following approaches:
Write unit-tests for your code. With the B-Tree that would mean to start with small trees (even with an empty tree), and use checks in your tests to verify the properties. You would then add more and more tests, specifically checking for bugs also in the "tricky" scenarios. There is a lot of general information about unit-testing available, you should be able to adapt it to your specific problem.
Add assertions to your code (read about the assert macro in C). Many of the properties you have mentioned could be checked directly within the code at appropriate places.
Certainly, there is more you could do, like, having the code reviewed by some colleague, or using some formal verification tools, but the abovementioned two approaches are good starting points.
UPDATE (after code was added):
Some more hints about how you could approach unit-testing. In principle, you should write your tests with the help of a so called test framework, which is a helper library to make writing tests easier. To explain the concept, however, I just use plain C or even pseudo-code.
Moreover, you would also put some declarations and/or definitions into a header file, like "btree.h". For the sake of example, however, I will just #include "btree.c" in the code examples below.
Create a file "btree-test.c" (the name is a proposal, you can name it as you like).
A first test would look a bit like:
#include "btree.c"
#include <assert.h>
void test_create_empty_btree() {
btree_t *actual_btree = create_btree();
// now, check that the created btree has all desired properties
// for example:
assert(actual_btree != NULL);
assert(actual_btree->order == NODE_ORDER);
assert(actual_btree->lock == FALSE);
assert(actual_btree->root->key_index == EMPTY);
assert(actual_btree->root->leaf == TRUE);
printf("PASSED: test_create_empty_btree");
}
The code above is just an example, I have not even tried compiling it. Note also that the test is not quite clean yet: there will be memory leaks, because the btree is not properly deleted at the end of the test, which would be better practice. It should, however, give you an idea how to start writing unit-tests.
A second test could then again create a btree, but in addition insert some data. In your tests you would then check that the btree has the expected form. And so on, adding more and more tests. It is good practice to have one function per test case...
I'm working on a program that calculates any number in the Fibonacci Sequence without using the int data type since it would overflow. Instead I am using linked lists to hold the digits that represent each number. My current issue is with freeing memory allocated to linked lists that I no longer need. If I'm calculating F(10000), I'd like the thousands of previous lists to be freed. The program as is produces each value up to "F(7) = 13" before crashing and showing "exit status -1". I'd really just like to know what's causing this error and go from there. Any help is appreciated. Thank you and I apologize for the large amount of code.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int digit;
struct Node *next;
} Node;
typedef struct ListyInt
{
Node *head;
int length;
} ListyInt;
Node *create_node(unsigned int digit, ListyInt *listy);
Node *removeNode(Node *node, ListyInt *listy);
void listyPrintHelper(Node *current);
ListyInt *destroyListyInt(ListyInt *listy);
ListyInt *fib(unsigned int n);
void listyPrint(ListyInt *p)
{
if (p == NULL || p->head == NULL)
{
printf("(null pointer)\n");
return;
}
listyPrintHelper(p->head);
printf("\n");
}
void listyPrintHelper(Node *current)
{
if (current == NULL)
return;
listyPrintHelper(current->next);
printf("%d", current->digit);
}
int main()
{
int i;
ListyInt *p;
for (i = 0; i <= 1000; i++)
{
printf("F(%d) = ", i);
listyPrint(p = fib(i));
destroyListyInt(p);
}
return 0;
}
ListyInt *listyAdd(ListyInt *p, ListyInt *q)
{
ListyInt *listy = NULL;
Node *ptemp = NULL;
Node *qtemp = NULL;
Node *temp = NULL;
ListyInt *temp_list = NULL;
unsigned int x = 0;
unsigned int count = 0;
if (p == NULL || q == NULL)
{
return NULL;
}
listy = malloc(sizeof(ListyInt));
if (listy == NULL)
{
return NULL;
}
listy->length = 0;
if (q->length > p->length)
{
temp_list = q;
q = p;
p = temp_list;
}
while (count < p->length)
{
if (count == 0)
{
x = p->head->digit + q->head->digit;
ptemp = p->head->next;
qtemp = q->head->next;
listy->head = create_node(x, listy);
temp = listy->head;
temp->next = create_node(0, listy);
if (temp->digit > 9)
{
temp->digit = temp->digit - 10;
temp->next->digit = temp->next->digit + 1;
}
}
else
{
temp->next->next = create_node(0, listy);
if (qtemp == NULL)
{
temp->next->digit += ptemp->digit;
ptemp = ptemp->next;
temp = temp->next;
}
else
{
x = ptemp->digit + qtemp->digit;
temp->next->digit += x;
if (temp->next->digit > 9)
{
temp->next->digit = temp->next->digit - 10;
temp->next->next->digit = temp->next->next->digit + 1;
}
qtemp = qtemp->next;
ptemp = ptemp->next;
temp = temp->next;
}
}
if (count == p->length - 1 && temp->next->digit == 0)
{
temp->next = removeNode(temp->next, listy);
}
count++;
}
return listy;
}
ListyInt *destroyListyInt(ListyInt *listy)
{
if (listy == NULL)
{
return NULL;
}
Node *current = listy->head;
Node *temp;
while (current != NULL)
{
temp = current->next;
free(current);
current = temp;
}
free(listy);
return NULL;
}
ListyInt *fib(unsigned int n)
{
ListyInt *spiral = malloc(sizeof(ListyInt));
ListyInt *p = NULL;
ListyInt *q = NULL;
unsigned int count = 2;
if (spiral == NULL)
{
return NULL;
}
if (n == 0)
{
spiral->head = create_node(0, spiral);
return spiral;
}
if (n == 1)
{
spiral->head = create_node(1, spiral);
return spiral;
}
p = malloc(sizeof(ListyInt));
p->head = create_node(0, p);
q = malloc(sizeof(ListyInt));
q->head = create_node(1, q);
while (count <= n)
{
spiral = listyAdd(p, q);
destroyListyInt(p);
p = q;
q = spiral;
count++;
}
return spiral;
}
Node *create_node(unsigned int digit, ListyInt *listy)
{
if (listy == NULL)
{
return NULL;
}
Node *new_node = malloc(sizeof(Node));
new_node->digit = digit;
new_node->next = NULL;
listy->length++;
return new_node;
}
Node *removeNode(Node *node, ListyInt *listy)
{
if (node == NULL)
{
return NULL;
}
if (listy == NULL)
{
return NULL;
}
free(node);
node = NULL;
listy->length--;
return NULL;
}
I'd really just like to know what's causing this error and go from there.
Long story short, C's equivalent of a NullPointerException, as far as I can tell.
Long story longer, I haven't had time to fully examine your code or debug it, but I have had time to run it through gdb, which is included with most Linux installations. If you're using Visual Studio, I vaguely remember there being a debug mode, which should show you roughly the same information, just in a different place. This is GDB's output:
Starting program: /home/ubuntu/C/a.out
F(0) = 0
F(1) = 1
F(2) = 1
F(3) = 2
F(4) = 3
F(5) = 5
F(6) = 8
F(7) = 13
Program received signal SIGSEGV, Segmentation fault.
0x00000000004008db in listyAdd (p=0x6036a0, q=0x6036e0) at main.c:117
117 temp->next->digit += ptemp->digit;
(Okay, that's not all of it, but that's the relevant bit.)
What those last three lines mean is that you got a segfault. There are a bunch of things that can cause it, but based on that line, it looks like it's been caused by trying to dereference an invalid pointer. That's either a NULL pointer (a value of 0x0) or a pointer you've already freed.
If you're on Linux, you can then run Valgrind on it to figure out what, exactly, happened. It'll tell you if it's using a freed pointer or a NULL one, and that'll give you a good starting point to find the actual bug. You can also use your IDE's debugger (or GDB, if you want to try playing with the command-line version, but I wouldn't recommend it) to step through your program and see what the values of the variables involved are, which you can walk backwards from to see where they're being changed and invalidated.
If I had to guess, though, I'd say 0andriy's comments hit it on the nose -- you seem to be freeing things twice, and you probably meant to free them once, at the end.
I'm somewhat intentionally leaving this vague. Segfaults are common and (as you've noticed) difficult to debug, and you can only really learn how through experience. I think being shown the answer would honestly be less helpful than working through it yourself, and with tools like Valgrind and your debugger, that's not actually that hard, just tedious.
I found the issue. It was because the length of my linked lists weren't being reset when fib() was called. Thanks for your help everyone.
I am trying to build a binary tree from an unsorted float array for an assignment, but I cannot quite figure it out. My goal is to send the unsorted array xdata of size ndata to the function build_tree(), which creates a new node using the function create_node(). In the case that the array size is greater than 1, it will call the function paritition_data() (which works fine, but I've placed it at the bottom of the question for reference), which will swap the order of array values so that all values less than mid fall on its left, and greater values to its right. The function returns nleft, the number of values on the left of mid. I then want to recursively call partition_data() to create new left and right child nodes. I think it is at this step that my program seems to fail, and despite it compiling, the program seems to recursively call partition_data() infinitely, and I'm not sure why. I appreciate any help.
typedef struct treenode_struct {
int n;
float data;
struct treenode_struct *left, *right;
} treenode;
treenode *create_node( ) {
treenode *node;
node = malloc(sizeof(treenode));
if (node == NULL) {
printf("Allocate Failed");
exit(-1);
}
node->n = 0;
node->right = NULL;
node->left = NULL;
tree_nodes++;
return node;
}
treenode *build_tree( float xdata[], int ndata, float xmin, float xmax ) {
treenode *node;
int nleft;
float mid = (xmin+xmax)/2.;
node = create_node();
node->n = ndata;
if (ndata == 1) { // Add code for this case
node->data = xdata[0];
node->left = NULL;
node->right = NULL;
return node;
}
if (ndata == 0){
printf("Allocate failed\n");
exit(-1);
}
// More than one data point: use partition function
if (ndata > 1) {
nleft = partition_data(xdata,ndata,mid);
int nright = ndata-nleft;
// Add code to make a left child
if(nleft != 0){
node->left=build_tree(xdata,nleft,xmin,xdata[nleft-1]);
}
else{
node->left = NULL;
}
// Add code to make a right child
if(nright != 0){
node->right=build_tree(xdata,nright,xdata[nleft],xmax);
}
else{
node->right = NULL;
}
return node;
}
}
int tree_nodes;
int main() {
const int ndata = 16;
float xdata[] = { 0.963, 0.003, 0.0251, 0.353, 0.667, 0.838, 0.335, 0.915,
0.796, 0.833, 0.345, 0.871, 0.089, 0.888, 0.701, 0.735 };
int i;
float xmiddle = 0.5;
printf("Input data:\n");
for (i=0;i<ndata;i++) printf("%f ",xdata[i]);
printf("\n");
treenode *tree_root;
float tree_xmin, tree_xmax;
tree_nodes = 0;
tree_xmin = 0;
tree_xmax = 1;
tree_root = build_tree( xdata, ndata, tree_xmin, tree_xmax );
printf("Tree Built: nodes %d\n",tree_nodes);
printf("Tree Ordered data:\n");
for (i=0;i<ndata;i++) printf("%f ",xdata[i]);
printf("\n\n");
}
Here is partition_data():
int partition_data( float xdata[], int ndata, float xmiddle ) {
// Your code goes here
int left = 0;
int right = ndata-1;
float temp;
while(left < ndata){ //left loop
if(xdata[left] < xmiddle){
if(left == right){
return left+1;
break;
}//DONE
left = left + 1;
}
else{
while(right<ndata){ //right loop, search for swappable Xright
if(xdata[right] >= xmiddle){//X[right] is greater than/equal to xmiddle
if(left == right){
return left;
break;
}
right=right-1;
}
else{ //found X[right] to swap
temp = xdata[left];
xdata[left] = xdata[right];//swap
xdata[right]=temp;
right = right-1;
if(left == right) {
return left+1;
break;
}
left=left+1;
break;
}
break;
}
}
}
Your recursion problem is caused by the creation of your right node.
You create the right node with this code:
// Add code to make a right child
if(nright != 0){
node->right=build_tree(xdata,nright,xdata[nleft],xmax);
}
else{
node->right = NULL;
}
Now if you look at your build_tree function what you have is:
treenode *build_tree( float xdata[], int ndata, float xmin, float xmax )
Let's interprete it as:
create a tree from the array xdata[] where all elements are greater than xmin and less than xmax
Now don't see xdata[] as array xdata[] but see xdata as the pointer to the first element I have to process. This will (hopefully) help you understand it a little bit (and is actually what it is, it is just a pointer).
In your code to create the right node you use:
node->right=build_tree(xdata,nright,xdata[nleft],xmax);
but there you actually insert as right node the root of the tree that will be created by processing the data starting at the first element of your array. That's not the slice of the array you want. The slice you want to have in your right node is the right part of the array so the part that starts at index ndata-nright. So if you want to change the begin of an array, you just add the index to the pointer of the array. So in your case xdata + (ndata-nright) will represent an array that starts at element ndata-nright (or pointer to that element). So you should have:
node->right=build_tree(xdata + (ndata-nright),mid,xdata[nleft],xmax);
to create your right node!
I'm currently working on a school project where I have to write a few helper functions for Binary Search Trees. One of the functions removes a node from the tree. I'm trying to run some test cases but I can't seem to get them to work. I know the problem has something do with how I'm using pointers, but I'm not quite sure where I'm going wrong.
Here is the code:
int removeBST (struct TreeNode **rootRef, int data)
{
struct TreeNode *current = *rootRef;
struct TreeNode *temp = current;
if (current == NULL)
return 0;
if (data < current->data)
{
current->left = removeBST (¤t->left, data);
}
if (data > current->data)
{
current->right = removeBST (¤t->right, data);
}
if (current->left == NULL || current->right == NULL)
return 0;
else
{
if (current->left == NULL) {
temp = current->right;
current = temp;
free (temp);
return 1;
}
else if (current->right == NULL) {
temp = current->left;
current = temp;
free (temp);
return 1;
}
temp = leftRoot (current->right);
current->data = temp->data;
current->right = removeBST (¤t->right, temp->data);
}
return 1;
}
Note: I didn't include the leftRoot() function, but it's fairly simple and I know it does what it's supposed to (return the leftmost root in a subtree)
Here is the part of the code my professor gave us that tests the remove function:
for(i = -4; i < 25; i+=4)
{
n = removeBST(&bst, i);
if(!n) printf("remove did not find %d\n", i);
}
and in case it's necessary, here's the entire test code that creates the tree and inserts the data:
struct TreeNode* bst = NULL;
for(i = 0; i < 23; ++i)
{
n = (i*17+11) % 23;
bst = insertBST(bst, n);
}
printf("filled BST: ");
printTree(bst);
printf("BST leaves: ");
printLeaves(bst);
printf("BST depth = %d\n", maxDepth(bst));
printf("BST minimum value = %d\n", minValueBST(bst));
printf("BST isBST = %d\n", isBST(bst));
for(i = -4; i < 25; i+=4)
{
n = removeBST(&bst, i);
if(!n) printf("remove did not find %d\n", i);
}
the entire output is:
filled BST: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
BST leaves: 0 6 12 17
BST depth = 8
BST minimum value = 0
BST isBST = 1
remove did not find -4
remove did not find 0
remove did not find 4
(this part repeats all the way up to 24)
BST after removes: 11
Since everything besides the '11' is no longer attached to tree, I'm fairly certain that something in my program is assigning pointers where they shouldn't be assigned and tree nodes are just getting lost in the void. Any ideas?
EDIT: One piece of information I forgot to provide, the deleted node's left-most child is supposed to replace the deleted node.
I'm not sure that I've found all of the issues in your code but here is one major one:
int removeBST (struct TreeNode **rootRef, int data)
Your function returns an int, corroborated by a number of return 1 or return 0 statements...
And yet you do this:
if (data < current->data)
{
current->left = removeBST (¤t->left, data);
}
if (data > current->data)
{
current->right = removeBST (¤t->right, data);
}
Since you're passing ¤t->left to the first argument the I can assume that it's type would be a pointer to a struct TreeNode **rootRef, which is struct TreeNode ***rootRef...
Which means that you're assigning addresses 0 and 1 to the left and right nodes? This seems very odd to me and is likely causing problems for you.
Note: this is not a solution but it is too big to fit into a comment.
Since you've opted for recursion let me see if I can help you fix this somewhat...
int removeBST (struct TreeNode **rootRef, int data)
{
struct TreeNode *current = *rootRef;
struct TreeNode *temp = current;
if (current == NULL)
return 0;
if (data < current->data)
{
// We don't want to modify things here, just let the next
// call take care of it and return what it returns.
return removeBST(¤t->left, data);
}
else if (data > current->data)
{
// Same here.
return removeBST(¤t->right, data);
}
else
{
if (current->left == NULL) {
temp = current->right;
// The rest of the stuff from here moved below.
// Because I added the else, the return isn't needed
// here anymore either, since the one at the bottom
// will return 1 anyway.
}
else if (current->right == NULL) {
temp = current->left;
// I did the same here.
}
else {
temp = leftRoot (current->right);
// This was on the outside but really it should be an else
// since it means less code...
// Additionally, once you got the left root why did you decide
// to remove it too? As far as I can see you only want to
// remove this one... If not, then you might have some work
// to do here...
}
*rootRef = temp; // current and rootRef are not the same.
// You need to use rootRef here so that we
// move the temp pointer to the current one
// (replace it). Think carefully about where
// the pointers are! Pointers also have addresses
// and it matters what address you write to
// where, use pen and paper and draw where things
// point!
free (current); // this means that we can't delete temp! so
// since, we've just deleted the "current"
// pointer we should discard it too...
}
return 1;
}
Draw a diagram for your pointers. I find diagrams like this or this help me most. It is not embarrassing and will help you understand what you're writing. It is important to visualize these things, particularly when you're just learning.
I've tried to fix the code up a little. I will admit that I didn't spend as much time as I possibly should have proof-reading it but it should be ok enough to give you an idea about the solution. Don't just copy/paste this, I don't guarantee it will work. But it should help you get onto the right path.