Implementing Binary search tree using array in C - arrays

I am trying to implement a binary search tree using a 1-D array. I'm familiar with the fact that the left node will be parent*2+1 and right node will be parent*2+2. I am using this concept to write the insertion function here:
int* insert(int tree[], int element){
int parent=0;
if(tree[parent]=='\0'){
tree[parent]=element;
return tree;
}
else{
if(element<tree[parent]){
parent=parent*2+1;
tree[parent]=insert(tree[parent], element);
}
else{
parent=parent*2+2;
tree[parent]=insert(tree[parent], element);
}
}
return tree;
}
However, I'm quite sure this won't work, since I'm passing an element of the array into the insert() function while recursing, when it actually needs an array. I'm not sure how to go about it. Do I replace the return type from int* to int? Any help is appreciated

the fact that the left node will be parent2+1 and right node will be parent2+2
That's correct. You want to use the array index like
0
/ \
/ \
/ \
/ \
1 2
/ \ / \
/ \ / \
3 4 5 6
But your recursion is not doing that.
You always do int parent=0; so you have no knowledge of the real array index and consequently, you access the wrong array elements.
For instance:
When you pass tree[2] you really want the function to use either tree[5] or tree[6] in the next recursive call. However, since you start by setting parent to zero, your next recursive call will us either tree[3] or tree[4].
Conclusion If you want to use recursion, you need to track the actual array index of the current node. Simply passing a pointer to the current node is not sufficient.
Instead your code could be:
int insert(int* tree, unsigned current_idx, int element){
if (current_idx >= ARRAY_SIZE) return -1;
if(tree[current_idx]=='\0'){
tree[current_idx]=element;
return 0;
}
if(element<tree[current_idx]){
return insert(tree, 2*current_idx + 1, element);
}
return insert(tree, 2*current_idx + 2, element);
}
That said - you should also spend some time considering whether recursion is really a good solution for this task.
Without recursion you can do:
int insert(int* tree, int element){
unsigned current_idx = 0;
while (1)
{
if (current_idx >= ARRAY_SIZE) return -1;
if(tree[current_idx]=='\0'){
tree[current_idx]=element;
return 0;
}
if(element<tree[current_idx]){
current = 2*current_idx + 1;
}
else {
current = 2*current_idx + 2;
}
}
}
As you can see the recursive approach didn't give you anything. Instead it made things worse...

You can avoid recursion and do it iteratively. Note tree is actually an integer array of size size. In the function insert() we pass a pointer to the array. Assuming the array is initialized with 0s:
void insert(int* tree, int size, int element)
{
if (tree == NULL)
return;
int pos = 0;
while (pos < size)
{
if (tree[pos])
{
if (tree[pos] < element)
pos = 2 * pos + 2; // right
else if (tree[pos] && tree[pos] > element)
pos = 2 * pos + 1; // left
}
else
{
tree[pos] = element;
return;
}
}
}
Full code:
#include <stdio.h>
#include <stdlib.h>
void insert(int* tree, int size, int element)
{
if (tree == NULL)
return;
int pos = 0;
while (pos < size)
{
if (tree[pos])
{
if (tree[pos] < element)
pos = 2 * pos + 2; // right
else if (tree[pos] && tree[pos] > element)
pos = 2 * pos + 1; // left
}
else
{
tree[pos] = element;
return;
}
}
}
void print(int* tree, int size)
{
for (int i = 0; i < size; i++)
printf("%d ", tree[i]);
printf("\n");
}
int main()
{
int tree[100] = {0};
const int tsize = 100;
// print first 20 elements
print(tree, 20);
insert(tree, tsize, 2);
insert(tree, tsize, 3);
insert(tree, tsize, 5);
insert(tree, tsize, 1);
insert(tree, tsize, 4);
print(tree, 20);
return 0;
}

Related

Need to decrement a counter in a recursive tree function, but only when I am moving "upwards" in the tree

I am writing a recursive function to find if there is a path from the root to a leaf that sums up to a certain number or not (user inputs the sum). Each time I move forward into a new recursive call, I increment the value of current_sum with the value of node->data. Current_sum is declared/initialized outside of the function. So this works fine to get the sum to the left-ermost leaf. However after that, the current_sum just keeps increasing, as I don't have an appropriate decrement operation to go with it. So if there does exist a path that adds up to a certain number in the righter branches, for example: 1 2 # # 3 # #, and I check for path sum = 4, (1+3), it would not get that. (If i check for sum=3 (1+2), it does get it.)
So I am looking for the correct place in my code to put the decrement operation. I was thinking something like: current_sum -= root->data. However I've tried putting it a lot of different places, but all of them seem to be wrong places. Either they disrupt the original tracker to get to even the very first leftermost leaf. Or they don't decrement at all (if I put it after the both the left/right recursive calls). I also do need it to keep decrementing while it goes UP but increment while it goes DOWN. Is there a way to write this in code, I am curious? Or, is this just a bad algorithm/approach?
I've seen other ways of solving this problem, such as https://www.geeksforgeeks.org/root-to-leaf-path-sum-equal-to-a-given-number/, which seem really nice, I just wanted to know if there was a way to resolve the one I started.
int current_sum = 0;
int sumPath(Node * root, int sum)
{
if (root == NULL)
{
return 0;
}
current_sum += root->data;
if ((root->left == NULL) && (root->right == NULL))
{
if (current_sum == sum)
{
return 1;
}
else
{
return 0;
}
}
int the_left = sumPath(root->left, sum);
int the_right = sumPath(root->right, sum);
////////////////////current_sum -= root->data; (?)
if (the_left>0)
{
return the_left;
}
else if (the_right>0)
{
return the_right;
}
return 0;
}
You may get invalid output, because of not sending current_sum as a parameter. Because current_sum needs to be updated for a particular stack-trace or function call, not for commonly for all the function calls. and this may give you an invalid state.
UPDATE
int isPossible(Node * root, int currentSum, int sum) {
if(!root) return 0;
currentSum += root.node;
// when you find the sum, and can't move further down
if(sum == currentSum && root->left == null && root->right == null) return 1;
int flag = 0;
// going down on left side
flag = isPossible(root->left, currentSum, sum);
// needs to check right side, only when you couldn't find sum on left
if(!flag)
flag = isPossible(root->right, currentSum, sum);
// return the state
return flag;
}
your code is fine, u just need to pass sum - current_sum in the recursive call. This is your code with some hinted modifications.
#include <stdio.h>
// remove global current_sum
struct Node {
char* name;
int data;
struct Node* left;
struct Node* right;
};
int sumPath(struct Node* root, int sum) {
if (root == NULL) {
return 0;
}
if ((root->left == NULL) && (root->right == NULL)) {
if (current_sum == sum) {
printf("%s ", root->name); // if the branch matches, print name
return 1;
} else {
return 0;
}
}
int the_left = sumPath(root->left, sum - root->data); // pass the subtracted sum
int the_right = sumPath(root->right, sum - root->data); // pass the subtracted sum
if (the_left > 0) {
printf("%s ", root->name); // if the branch matches, print name
return the_left;
} else if (the_right > 0) {
printf("%s ", root->name); // if the branch matches, print name
return the_right;
}
return 0;
}
int main() {
struct Node n1 = {.data = 1, .name = "n1"}; // n1
struct Node n2 = {.data = 1, .name = "n2"}; // ___|___
struct Node n3 = {.data = 1, .name = "n3"}; // | |
struct Node n4 = {.data = 1, .name = "n4"}; // n2 n4
// ___|
n1.left = &n2; // |
n1.right = &n4; // n3
n2.left = &n3; //
sumPath(&n1, 3); // no. of steps including the root
return 0;
}
// output
// n3 n2 n1

Recovering elements of large array with multiple index ranges

This is a tricky problem that I have been thinking about for a long time and have yet to see a satisfactory answer anywhere. Lets say I have a large int array of size 10000. I can simply declare it in the following manner:
int main()
{
int foo[10000];
int i;
int n;
n = sizeof(foo) / sizeof(int);
for (i = 0; i < n; i++)
{
printf("Index %d is %d\n",i,foo[i] );
}
return 0;
}
It is pretty clear that each index in the array will hold a random assortment of numbers before I formally initialize them:
Index 0 is 0
Index 1 is 0
Index 2 is 0
Index 3 is 0
.
.
.
Index 6087 is 0
Index 6088 is 1377050464
Index 6089 is 32767
Index 6090 is 1680893034
.
.
.
Index 9996 is 0
Index 9997 is 0
Index 9998 is 0
Index 9999 is 0
Then lets say that I initialize select index ranges of my array with values that hold a specific value for the program as a whole and must be preserved, with the goal of passing in those values for subsequent operation to some function:
//Call this block 1
foo[0] = 0;
foo[1] = 7;
foo[2] = 99;
foo[3] = 0;
//Call this block 2
foo[9996] = 0;
foo[9997] = 444;
foo[9998] = 2;
foo[9999] = 0;
for (i = 0; i < (What goes here?); i++)
{
//I must pass in only those values initialized to select indices of foo[] (Blocks 1 and 2 uncorrupted)
//How to recover those values to pass into foo_func()?
foo_func(foo[]);
}
Some of those values that I initialized foo[] with overlap with pre-existing values in the array before formally initializing the array myself. How can I pass in just the indices of the array elements that I initialized, given that there are multiple index ranges? I just can't figure this out. Thanks for any and all help!
EDIT:
I should also mention that the array itself will be read from a .txt file. I just showed the initialization in the code for illustrative purposes.
There's a number of ways you can quickly zero out the memory in the array, either while initializing or after.
For an array on the stack, initialize it with zeros. {0} is shorthand for that.
int foo[10000] = {0};
For an array on the heap, use calloc to allocate memory and initialize it with 0's.
int *foo = calloc(10000, sizeof(int));
If the array already exists, use memset to quickly overwrite all the array's memory with zeros.
memset(foo, 0, sizeof(int) * 10000);
Now all elements are zero. You can set individual elements to whatever you like one by one. For example...
int main() {
int foo[10] = {0};
foo[1] = 7;
foo[2] = 99;
foo[7] = 444;
foo[8] = 2;
for( int i = 0; i < 10; i++ ) {
printf("%d - %d\n", i, foo[i]);
}
}
That will print...
0 - 0
1 - 7
2 - 99
3 - 0
4 - 0
5 - 0
6 - 0
7 - 444
8 - 2
9 - 0
As a side note, using only a few elements of a large array is a waste of memory. Instead, use a hash table, or if you need ordering, some type of tree. These can be difficult to implement correctly, but a library such as GLib can provide you with good implementations.
Introduction
I'm making a strong assumption on your problem, and it is sparsness (a majority of the elements in your array will remain zero).
Under this assumption I would build the array as a list. I'm including a sample code, that it is not complete and it is not intended to
be---you should do your own homework :)
The core object is a struct with a pointer to a begin element and the size:
typedef struct vector {
size_t size;
vector_element_t * begin;
} vector_t;
each element of the vector has its own index and value and a pointer to the next element in a list:
typedef struct vector_element vector_element_t;
struct vector_element {
int value;
size_t index;
vector_element_t *next;
};
on this basis we can build a dynamical vector as a list, by dropping a constraint on the ordering (it is not needed, you can modify this code
to maintain the ordering), using some simple custom methods:
vector_t * vector_init(); // Initialize an empty array
void vector_destroy(vector_t* v); // Destroy the content and the array itself
int vector_get(vector_t *v, size_t index); // Get an element from the array, by searching the index
size_t vector_set(vector_t *v, size_t index, int value); // Set an element at the index
void vector_delete(vector_t *v, size_t index); // Delete an element from the vector
void vector_each(vector_t *v, int(*f)(size_t index, int value)); // Executes a callback for each element of the list
// This last function may be the response to your question
Test it online
The main example
This is a main that uses all this methods and prints in console:
int callback(size_t index, int value) {
printf("Vector[%lu] = %d\n", index, value);
return value;
}
int main() {
vector_t * vec = vector_init();
vector_set(vec, 10, 5);
vector_set(vec, 23, 9);
vector_set(vec, 1000, 3);
printf("vector_get(vec, %d) = %d\n", 1000, vector_get(vec, 1000)); // This should print 3
printf("vector_get(vec, %d) = %d\n", 1, vector_get(vec, 1)); // this should print 0
printf("size(vec) = %lu\n", vec->size); // this should print 3 (the size of initialized elements)
vector_each(vec, callback); // Calling the callback on each element of the
// array that is initialized, as you asked.
vector_delete(vec, 23);
printf("size(vec) = %lu\n", vec->size);
vector_each(vec, callback); // Calling the callback on each element of the array
vector_destroy(vec);
return 0;
}
And the output:
vector_get(vec, 1000) = 3
vector_get(vec, 1) = 0
size(vec) = 3
Vector[10] = 5
Vector[23] = 9
Vector[1000] = 3
size(vec) = 3
Vector[10] = 5
Vector[1000] = 3
The callback with the function vector_each is something you really should look at.
Implementations
I'm giving you some trivial implementations for the functions in the introdution. They are not complete,
and some checks on pointers should be introduced. I'm leaving that to you. As it is, this code is not for production and under some circumstances can also overflow.
The particular part is the search of a specific element in the vector. Every time you tranverse the list,
and this is convenient only and only if you have sparsity (the majority of your index will always return zero).
In this implementation, if you access an index that is not enlisted, you get as a result 0. If you don't want this
you should define an error callback.
Initialization and destruction
When we initialize, we allocate the memory for our vector, but with no elements inside, thus begin points to NULL. When we destroy the vector we have not only to free the vector, but also each element contained.
vector_t * vector_init() {
vector_t * v = (vector_t*)malloc(sizeof(vector_t));
if (v) {
v->begin = NULL;
v->size = 0;
return v;
}
return NULL;
}
void vector_destroy(vector_t *v) {
if (v) {
vector_element_t * curr = v->begin;
if (curr) {
vector_element_t * next = curr->next;
while (next) {
curr = curr->next;
next = next->next;
if (curr)
free(curr);
}
if (next)
free(next);
}
free(v);
}
}
The get and set methods
In get you can see how the list works (and the same concept
is used also in set and delete): we start from the begin, and
we cross the list until we reach an element with an index equal
to the one requested. If we cannot find it we simply return 0.
If we need to "raise some sort of signal" when the value is
not found, it is easy to implement an "error callback".
As long as sparsness holds, searching in the whole array for an index is a good compromise in terms of memory requirements, and efficiency may be not an issue.
int vector_get(vector_t *v, size_t index) {
vector_element_t * el = v->begin;
while (el != NULL) {
if (el->index == index)
return el->value;
el = el->next;
}
return 0;
}
// Gosh, this set function is really a mess... I hope you can understand it...
// -.-'
size_t vector_set(vector_t *v, size_t index, int value) {
vector_element_t * el = v->begin;
// Case 1: Initialize the first element of the array
if (el == NULL) {
el = (vector_element_t *)malloc(sizeof(vector_element_t));
if (el != NULL) {
v->begin = el;
v->size += 1;
el->index = index;
el->value = value;
el->next = NULL;
return v->size;
} else {
return 0;
}
}
// Case 2: Search for the element in the array
while (el != NULL) {
if (el->index == index) {
el->value = value;
return v->size;
}
// Case 3: if there is no element with that index creates a new element
if (el->next == NULL) {
el->next = (vector_element_t *)malloc(sizeof(vector_element_t));
if (el->next != NULL) {
v->size += 1;
el->next->index = index;
el->next->value = value;
el->next->next = NULL;
return v->size;
}
return 0;
}
el = el->next;
}
}
Deleting an element
With this approach it is possible to delete an element quite easily, connecting
curr->next to curr->next->next. We must though free the previous curr->next...
void vector_delete(vector_t * v, size_t index) {
vector_element_t *curr = v->begin;
vector_element_t *next = curr->next;
while (next != NULL) {
if (next->index == index) {
curr->next = next->next;
free(next);
return;
} else {
curr = next;
next = next->next;
}
}
}
An iteration function
I think this is the answer to the last part of your question,
instead passing a sequence of indexes, you pass a callback to the vector.
The callback gets and sets value in a specific index. If you want to
operate only on some specific indexes, you may include a check in the
callback itself. If you need to pass more data to the callback, check
the very last section.
void vector_each(vector_t * v, int (*f)(size_t index, int value)) {
vector_element_t *el = v->begin;
while (el) {
el->value = f(el->index, el->value);
el = el->next;
}
}
Error callback
You may want to raise some out of bounds error or something else. One solution is to enrich your list with function pointer that represent a callback that should be called when your user sk for an undefined element:
typedef struct vector {
size_t size;
vector_element_t *begin;
void (*error_undefined)(vector *v, size_t index);
} vector_t
and maybe at the end of your vector_get function you may want to do something like:
int vector_get(vector_t *v, size_t index) {
// [ . . .]
// you know at index the element is undefined:
if (v->error_undefined)
v->error_undefined(v, index);
else {
// Do something to clean up the user mess... or simply
return 0;
}
}
usually it is nice to add also an helper function to set the callback...
Passing user data to "each" callback
If you want to pass more data to the user callback, you may add a void* as last argument:
void vector_each(vector_t * v, void * user_data, int (*f)(size_t index, int value, void * user_data));
void vector_each(vector_t * v, void * user_data, int (*f)(size_t index, int value, void * user_data)) {
[...]
el->value = f(el->index, el->value, user_data);
[...]
}
if the user do not need it, he can pass a wonderful NULL.

Iterator and Pointer on Matrix in C

For a JPEG image compression, I manipulate image in grey levels and 8bits by pixels
I have this type of matrix I dynamically allocated :
typedef char pixel_t;
pixel_t ** pix_matrix;
after allocating and filling it, I have a bidimensional array with the values (from -128 to +127) of the luminance of the picture.
For the JPEG compression, I need to iterate this array in zigzag like this:
So I want to create an Iterator structure for this type. This iterator must have 'current' and 'begin' members and I want those members to be pointers to the current element and first one of the matrix. In other words, I want to store the addresses and not the indexes. But after hours of tests, prints and researches, I couldn't find the way to make that possible. What type of pointer do I have to use? how make it point to the first address of my matrix? Is my request simply possible?
And if all of this is possible, how can I get the next element, and the value of the current one?
You can write an interator structure:
struct zigzag_t {
int width; // width, must be initialised
int height; // height, must be initialised
int x; // current x index
int y; // current y index
int underway; // dummy value to start at (0, 0)
};
which you must initialise with the width and height of your image. Write an interator function, so that you can use this iterator like this:
struct zigzag_t zz = {8, 8};
while (zigzag_next(&zz)) {
printf("(%d, %d)\n", zz.y, zz.x);
}
The iterator itself is not too complicated: If the sum of the x and y indices is odd, you walk southwest until you hit either the west or south edge. If the sum is even, you walk northeast until you hit either the north or east wall. If you hit the ne or sw edges, the east and south edges get priority. The iteration ends after you have visited the se edge.
Because the struct starts off with x and y both zero, the first point is (0, 1). In order to fix this, the dummy field underway, which also is zero, is used.
The iterator must be reset if you want to use it a second time. better yet, define and initialise a fresh iterator.
The iterator function:
int zigzag_next(struct zigzag_t *zz)
{
int odd = (zz->x + zz->y) % 2;
if (zz->underway == 0) {
zz->x = zz->y = 0;
zz->underway = 1;
return 1;
}
if (odd) {
/* walk southwest */
int w_edge = zz->x == 0;
int s_edge = zz->y == zz->height - 1;
if (s_edge) {
zz->x++;
return zz->x < zz->width;
} else if (w_edge) {
zz->y++;
} else {
zz->x--;
zz->y++;
}
} else {
/* walk northeast */
int e_edge = zz->x == zz->width - 1;
int n_edge = zz->y == 0;
if (e_edge) {
zz->y++;
return zz->y < zz->height;
} else if (n_edge) {
zz->x++;
} else {
zz->x++;
zz->y--;
}
}
return 1;
}
This solution returns the x and y positions, which you can use as indices to your double pointer to pixel data. It would not be hard to extend the struct to hold the base pointer to your pixel data and have the iterator function return a pointer to a pixel or NULL if the iteration has run out.
An example solution with pointers is below.
#include <stdlib.h>
#include <stdio.h>
typedef char pixel_t;
struct zigzag_t {
pixel_t **p; // base data
int width; // width, must be initialised
int height; // height, must be initialised
int x; // current x index
int y; // current y index
int underway; // dummy value to start at (0, 0)
};
pixel_t *zigzag_next(struct zigzag_t *zz)
{
int odd = (zz->x + zz->y) % 2;
if (zz->underway == 0) {
zz->x = zz->y = 0;
zz->underway = 1;
return *zz->p;
}
if (odd) {
/* walk southwest */
int w_edge = zz->x == 0;
int s_edge = zz->y == zz->height - 1;
if (s_edge) {
zz->x++;
if (zz->x == zz->width) return NULL;
} else if (w_edge) {
zz->y++;
} else {
zz->x--;
zz->y++;
}
} else {
/* walk northeast */
int e_edge = zz->x == zz->width - 1;
int n_edge = zz->y == 0;
if (e_edge) {
zz->y++;
if (zz->y == zz->height) return NULL;
} else if (n_edge) {
zz->x++;
} else {
zz->x++;
zz->y--;
}
}
return zz->p[zz->y] + zz->x;
}
int main()
{
pixel_t *data[] = {
"abcde", "fghij", "klmno", "pqrst", "uvwxy"
};
struct zigzag_t zz = {data, 5, 5};
for (;;) {
pixel_t *p = zigzag_next(&zz);
if (p == NULL) break;
putchar(*p);
}
putchar('\n');
return 0;
}
This solution is a C solution. There is no begin member function; initialisation is done via simple struct initialisation. There is no increment operator and no end member function; moving the iterator forward and checking for the end is done in a plain old function.
You have tagged the question C, but iterators are more frequent in C++, where they can be implemented as classes. The above C example may serve as a base for such an implementation.
Something nice and simple.
Function next is the iterator; it returns true until all cells have been visited.
A variable of type POSITION holds the iterator state.
Function current returns a pointer to the current cell in the matrix.
Demo function sample_application puts it all together.
#define MAX_XY 7
typedef struct { int x, y; } POSITION;
static int sign_of(int i)
{
return i < 0 ? -1 : i > 0 ? 1 : 0;
}
static int get_direction(int a, int b, int odd_is_forward)
{
return sign_of(((a + b) % 2 == odd_is_forward || b >= MAX_XY ? MAX_XY : 0) - a);
}
int next(POSITION *pos)
{
int x = pos->x;
int y = pos->y;
pos->x += get_direction(x, y, 0);
pos->y += get_direction(y, x, 1);
return x < MAX_XY || y < MAX_XY;
}
pixel_t *current(POSITION *pos)
{
return &pix_matrix[pos->y][pos->x];
}
void sample_application() // just demonstrating the use of POSITION
{
POSITION pos = {-1, -1}; // always start from these dummy coordinates
while (next(&pos)) // this iterates through the matrix
{
int coord_x = pos.x; // this is how you get the current coordinates
int coord_y = pos.y;
*current(&pos) = 12; // this is how you access the current cell
}
}

Max in array and its frequency

How do you write a function that finds max value in an array as well as the number of times the value appears in the array?
We have to use recursion to solve this problem.
So far i am thinking it should be something like this:
int findMax(int[] a, int head, int last)
{
int max = 0;
if (head == last) {
return a[head];
}
else if (a[head] < a[last]) {
count ++;
return findMax(a, head + 1, last);
}
}
i am not sure if this will return the absolute highest value though, and im not exactly sure how to change what i have
Setting the initial value of max to INT_MIN solves a number of issues. #Rerito
But the approach OP uses iterates through each member of the array and incurs a recursive call for each element. So if the array had 1000 int there would be about 1000 nested calls.
A divide and conquer approach:
If the array length is 0 or 1, handle it. Else find the max answer from the 1st and second halves. Combine the results as appropriate. By dividing by 2, the stack depth usage for a 1000 element array will not exceed 10 nested calls.
Note: In either approach, the number of calls is the same. The difference lies in the maximum degree of nesting. Using recursion where a simple for() loop would suffice is questionable. To conquer a more complex assessment is recursion's strength, hence this approach.
To find the max and its frequency using O(log2(length)) stack depth usage:
#include <stddef.h>
typedef struct {
int value;
size_t frequency; // `size_t` better to use that `int` for large arrays.
} value_freq;
value_freq findMax(const int *a, size_t length) {
value_freq vf;
if (length <= 1) {
if (length == 0) {
vf.value = INT_MIN; // Degenerate value if the array was size 0.
vf.frequency = 0;
} else {
vf.value = *a;
vf.frequency = 1;
}
} else {
size_t length1sthalf = length / 2;
vf = findMax(a, length1sthalf);
value_freq vf1 = findMax(&a[length1sthalf], length - length1sthalf);
if (vf1.value > vf.value)
return vf1;
if (vf.value == vf1.value)
vf.frequency += vf1.frequency;
}
return vf;
}
Your are not thaaaat far.
In order to save the frequency and the max you can keep a pointer to a structure, then just pass the pointer to the start of your array, the length you want to go through, and a pointer to this struct.
Keep in mind that you should use INT_MIN in limits.h as your initial max (see reset(maxfreq *) in the code below), as int can carry negative values.
The following code does the job recursively:
#include <limits.h>
typedef struct {
int max;
int freq;
} maxfreq;
void reset(maxfreq *mfreq){
mfreq->max = INT_MIN;
mfreq->freq = 0;
}
void findMax(int* a, int length, maxfreq *mfreq){
if(length>0){
if(*a == mfreq->max)
mfreq->freq++;
else if(*a > mfreq->max){
mfreq->freq = 1;
mfreq->max = *a;
}
findMax(a+1, length - 1, mfreq);
}
}
A call to findMax will recall itself as many times as the initial length plus one, each time incrementing the provided pointer and processing the corresponding element, so this is basically just going through all of the elements in a once, and no weird splitting.
this works fine with me :
#include <stdio.h>
#include <string.h>
// define a struct that contains the (max, freq) information
struct arrInfo
{
int max;
int count;
};
struct arrInfo maxArr(int * arr, int max, int size, int count)
{
int maxF;
struct arrInfo myArr;
if(size == 0) // to return from recursion we check the size left
{
myArr.max = max; // prepare the struct to output
myArr.count = count;
return(myArr);
}
if(*arr > max) // new maximum found
{
maxF = *arr; // update the max
count = 1; // initialize the frequency
}
else if (*arr == max) // same max encountered another time
{
maxF = max; // keep track of same max
count ++; // increase frequency
}
else // nothing changes
maxF = max; // keep track of max
arr++; // move the pointer to next element
size --; // decrease size by 1
return(maxArr(arr, maxF, size, count)); // recursion
}
int main()
{
struct arrInfo info; // return of the recursive function
// define an array
int arr[] = {8, 4, 8, 3, 7};
info = maxArr(arr, 0, 5, 1); // call with max=0 size=5 freq=1
printf("max = %d count = %d\n", info.max, info.count);
return 0;
}
when ran, it outputs :
max = 8 count = 3
Notice
In my code example I assumed the numbers to be positive (initializing max to 0), I don't know your requirements but you can elaborate.
The reqirements in your assignment are at least questionable. Just for reference, here is how this should be done in real code (to solve your assignment, refer to the other answers):
int findMax(int length, int* array, int* maxCount) {
int trash;
if(!maxCount) maxCount = &trash; //make sure we ignore it when a NULL pointer is passed in
*maxCount = 0;
int result = INT_MIN;
for(int i = 0; i < length; i++) {
if(array[i] > result) {
*maxCount = 1;
result = array[i];
} else if(array[i] == result) {
(*maxCount)++;
}
}
return result;
}
Always do things as straight forward as you can.

comparing sorted arrays - nlogn

i have 2 int arrays i need to print all the identical integers in O(nlogn)
the arrays are not sorted and after sorting can be:
X [ 1,2,3,4,5,6,7,8,9]
Y [1,2,8,9]
so checking only till the 4 place(the size of the smaller array) is not an option.
what kind of loop\equation do i need to use so it would be nlogn
?
if i will run the for till the last value of the smaller array -will it still be nlogn-
how can i take\reach only the last integer in arraya without running till the end of it?
I'm hoping this is enough of a hint...
Once the arrays are sorted, just walk through the arrays 'side-by-side'. Keep track of the 'current' element for each array (X and Y). You might do this using an index variable for each array or by using a pointer. Personally, I'd find it easier to use pointers, but you or your friend may have a different preference.
For each pair of 'current' elements, if the elements match then print the value. Then consider what needs to be done, if anything, to move to the next element of each array (for the cases where the elements don't match as well as for the case where they do match). There are only three cases:
x[cur_x] == y[cur_y]
x[cur_x] < y[cur_y]
y[cur_y] < x[cur_x]
so it shouldn't be too difficult to determine what should be done in each case.
Sorting the arrays in an O(n log n) operation. Walking through the arrays is an O(n) operation, so altogether it's an O(n) + O(n log n) operation, which reduces down to O(n log n). In other words, the overall time complexity of the operation is determined by the sort operation.
Using a binary search will also work, but it might be a little more complicated - especially to properly handle duplicated elements in the arrays if that's a requirement (and depending on what 'properly' might mean according to the requirements).
You can take the smaller array and search each element in the bigger element with binary search
for(int i = 0; i < size1; i++) {
binarysearch(arr_small[i], arr_big);
}
binary search requires O(log n) time for each search. Total search time for all elements is O(nlogn)
If you dont remember binary search, refer the link: http://en.literateprograms.org/Binary_search_(C)
throw one array in a hash. Look up the other array in the hash. But that's not nlogn.. it's m+n.
This approach does not need the X and Y to be sorted.
Add the elements of X to a binary search tree (avoid duplicate entries, i.e. if X[0] = 1 and X[1] = 1 then don't add X[1]; just ignore it).
Then try to add the contents of Y to the same binary search tree and If you find the element already in there, then its identical.
The total time complexity boils down to the time complexity of adding element to BST which is O(n log n) but worst case would be O(n) if the tree is skewed (i.e. if the arrays are sorted).
Here is the code for your reference!
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
typedef struct node {
int data;
struct node *left;
struct node *right;
} NODE;
NODE *root = NULL;
NODE * newnode (int data)
{
NODE * n = NULL;
if (n = (NODE *) malloc (sizeof (NODE))) {
n->data = data;
n->right = n->left = NULL;
} else {
printf("%d - %d - unalbe to create new node \n", __LINE__, data);
}
return n;
}
NODE * getnode(NODE * n, int data)
{
if (n == NULL)
return NULL;
if (n->data == data)
return n;
if (data < n->data) {
return getnode (n->left, data);
}
if (data > n->data) {
return getnode (n->right, data);
}
return NULL;
}
NODE * insert (NODE * node, int data, int *dup)
{
NODE * n = NULL;
if (node != NULL) {
if (getnode(node, data) != NULL) {
/* element already present in the tree..
so set the dup and return the root */
*dup = 1;
return node;
}
}
if (node == NULL) {
n = newnode(data);
return (n);
}
if (data <= node->data)
node->left = insert(node->left, data, dup);
else
node->right = insert(node->right, data, dup);
return node;
}
NODE * deletetree(NODE * from)
{
if (from != NULL) {
deletetree(from->left);
deletetree(from->right);
//printf("deleting %d \n", from->data);
free(from);
}
return NULL;
}
int main()
{
int sum = 35;
int X[] = {1,2,3,4,5,6,7,8,9,1,2,3,4,5};
int Y[] = {1,2,8,9};
int i, dup = 0;
int xlen = sizeof(X)/sizeof(X[0]);
int ylen = sizeof(Y)/sizeof(Y[0]);
printf("len of X is : %d \n", xlen);
printf("len of Y is : %d \n", ylen);
NODE * root1 = NULL;
for (i=0; i<xlen; i++) {
root = insert(root, X[i], &dup);
}
for (i=0; i<ylen; i++) {
dup = 0;
root = insert(root, Y[i], &dup);
if (dup == 1) {
printf("%d ", Y[i]);
}
}
printf("\n");
root = deletetree(root);
return 0;
}

Resources