comparing sorted arrays - nlogn - c

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;
}

Related

using new array to store the sorted values in heap sort

I am currently studying about the algorithm about heap sorts, I wonder if it is possible to make a heapsort function that stores the sorted value in a new array (aside from the initial array where the unsorted values is stored) and not do anything to the initial array?
if you delete in heap sort, the root will switch with the last element right? so the last element will now have the address of the root, and the previous root will be placed in the last index/address in the array. After swapping the values, the size of the array will be decremented and the current address of the previous root will now not be considered as part of the array (because of decrease in array size).
So, what I want to know is a heapsort function that takes the initial array as the parameter. Im wondering if it is possible to take the element that will be deleted in the initial array and storing it in the new array in min heap order without doing anything to the initial array.
this is the code that Im studying from a website, im copying it here so that you can all see what im into
#include <stdio.h>
#include <stdlib.h>
typedef struct MinHeap MinHeap;
struct MinHeap {
int* arr;
// Current Size of the Heap
int size;
// Maximum capacity of the heap
int capacity;
};
int parent(int i) {
// Get the index of the parent
return (i - 1) / 2;
}
int left_child(int i) {
return (2*i + 1);
}
int right_child(int i) {
return (2*i + 2);
}
int get_min(MinHeap* heap) {
// Return the root node element,
// since that's the minimum
return heap->arr[0];
}
MinHeap* init_minheap(int capacity) {
MinHeap* minheap = (MinHeap*) calloc (1, sizeof(MinHeap));
minheap->arr = (int*) calloc (capacity, sizeof(int));
minheap->capacity = capacity;
minheap->size = 0;
return minheap;
}
MinHeap* insert_minheap(MinHeap* heap, int element) {
// Inserts an element to the min heap
// We first add it to the bottom (last level)
// of the tree, and keep swapping with it's parent
// if it is lesser than it. We keep doing that until
// we reach the root node. So, we will have inserted the
// element in it's proper position to preserve the min heap property
if (heap->size == heap->capacity) {
fprintf(stderr, "Cannot insert %d. Heap is already full!\n", element);
return heap;
}
// We can add it. Increase the size and add it to the end
heap->size++;
heap->arr[heap->size - 1] = element;
// Keep swapping until we reach the root
int curr = heap->size - 1;
// As long as you aren't in the root node, and while the
// parent of the last element is greater than it
while (curr > 0 && heap->arr[parent(curr)] > heap->arr[curr]) {
// Swap
int temp = heap->arr[parent(curr)];
heap->arr[parent(curr)] = heap->arr[curr];
heap->arr[curr] = temp;
// Update the current index of element
curr = parent(curr);
}
return heap;
}
MinHeap* heapify(MinHeap* heap, int index) {
// Rearranges the heap as to maintain
// the min-heap property
if (heap->size <= 1)
return heap;
int left = left_child(index);
int right = right_child(index);
// Variable to get the smallest element of the subtree
// of an element an index
int smallest = index;
// If the left child is smaller than this element, it is
// the smallest
if (left < heap->size && heap->arr[left] < heap->arr[index])
smallest = left;
// Similarly for the right, but we are updating the smallest element
// so that it will definitely give the least element of the subtree
if (right < heap->size && heap->arr[right] < heap->arr[smallest])
smallest = right;
// Now if the current element is not the smallest,
// swap with the current element. The min heap property
// is now satisfied for this subtree. We now need to
// recursively keep doing this until we reach the root node,
// the point at which there will be no change!
if (smallest != index)
{
int temp = heap->arr[index];
heap->arr[index] = heap->arr[smallest];
heap->arr[smallest] = temp;
heap = heapify(heap, smallest);
}
return heap;
}
MinHeap* delete_minimum(MinHeap* heap) {
// Deletes the minimum element, at the root
if (!heap || heap->size == 0)
return heap;
int size = heap->size;
int last_element = heap->arr[size-1];
// Update root value with the last element
heap->arr[0] = last_element;
// Now remove the last element, by decreasing the size
heap->size--;
size--;
// We need to call heapify(), to maintain the min-heap
// property
heap = heapify(heap, 0);
return heap;
}
MinHeap* delete_element(MinHeap* heap, int index) {
// Deletes an element, indexed by index
// Ensure that it's lesser than the current root
heap->arr[index] = get_min(heap) - 1;
// Now keep swapping, until we update the tree
int curr = index;
while (curr > 0 && heap->arr[parent(curr)] > heap->arr[curr]) {
int temp = heap->arr[parent(curr)];
heap->arr[parent(curr)] = heap->arr[curr];
heap->arr[curr] = temp;
curr = parent(curr);
}
// Now simply delete the minimum element
heap = delete_minimum(heap);
return heap;
}
void print_heap(MinHeap* heap) {
// Simply print the array. This is an
// inorder traversal of the tree
printf("Min Heap:\n");
for (int i=0; i<heap->size; i++) {
printf("%d -> ", heap->arr[i]);
}
printf("\n");
}
void free_minheap(MinHeap* heap) {
if (!heap)
return;
free(heap->arr);
free(heap);
}
int main() {
// Capacity of 10 elements
MinHeap* heap = init_minheap(10);
insert_minheap(heap, 40);
insert_minheap(heap, 50);
insert_minheap(heap, 5);
print_heap(heap);
// Delete the heap->arr[1] (50)
delete_element(heap, 1);
print_heap(heap);
free_minheap(heap);
return 0;
}
EDIT:
if what im saying about is possible, can you please show me how? so that i can see and study the code. many thanks.

How do I free struct pointers with nested double pointers?

I pasted code at the bottom that allocates lots of pointers but doesn't free any. I have a struct named Node that has fields of type struct Node**. In my main function I have the variable: Node** nodes = malloc(size * typeof(Node*));. I would like to know how to properly deallocate nodes.
typedef struct Node {
size_t id; // identifier of the node
int data; // actual data
size_t num_parents; // actual number of parent nodes
size_t size_parents; // current maximum capacity of array of parent nodes
struct Node** parents; // all nodes that connect from "upstream"
size_t num_children; // actual number of child nodes
size_t size_children; // current maximum capacity of array of children nodes
struct Node** children; // all nodes that connect "downstream"
} Node;
I've pasted the whole code down at the bottom because it is already almost minimal (only things we don't need here are the printing function and find_smallest_value function). VS2019 also gives me two warnings for two lines within the main loop in the main function where I'm allocating each node:
Node** nodes = malloc((num_nodes + 1) * sizeof(Node*));
for (size_t i = 1; i <= num_nodes; i++) {
nodes[i] = malloc(sizeof(Node)); // WARNING Buffer overrun while writing to 'nodes': the writable size is '((num_nodes+1))*sizeof(Node *)' bytes, but '16' bytes might be written.
nodes[i]->id = i; // WARNING Reading invalid data from 'nodes': the readable size is '((num_nodes+1))*sizeof(Node *)' bytes, but '16' bytes may be read.
I don't understand these warnings at all. Finally, you can obtain large input for this program from this website. Just save it to a text file and modify the hardcoded file name in the main function. The program runs fine if I comment out the last lines where I try to deallocate my nodes. My attempt at deallocating crashes the program. I'd greatly appreciate if anyone could explain the correct way to do it.
Explaining the purpose of the code:
The code at the bottom has the following goal. I'm trying to build a directed graph where every vertex has a label and a value. An example of such a graph. The graphs I'm interested in all represent hierarchies. I am to perform two operations on these graphs: I. given a vertex, find the one with smallest value that above it in the hierarchy and print its value; II. given a pair of vertices, swap their places. For example, given vertices 4 and 2 in that figure, the result of operation II would be the same graph but the vertices labelled 2 and 4 would have their labels and data swapped. Given vertex 6, the result of operation I would be "18". I implemented both operations successfully, I believe.
My main function reads from a txt file in order to build the data structure, which I chose to be a multiply linked list. Any input file should be of the following format (this file generates the graph shown in the figure and performs some operations on it):
7 8 9
21 33 33 18 42 22 26
1 2
1 3
2 5
3 5
3 6
4 6
4 7
6 7
P 7
T 4 2
P 7
P 5
T 1 4
P 7
T 4 7
P 2
P 6
First line has three numbers: number of vertices (nodes), number of edges (k, connections) and number of instructions (l, either operation I or II).
Second line is the data in each node. Labels correspond to the index of the node.
The next k lines consist of two node labels: left is a parent node, right is a child node.
The next l lines consist of instructions. P stands for operation I and it's followed by the label of the node. T stands for operation II and it's followed by the two labels of the nodes to be swapped.
The entire pattern can repeat.
The code:
#include<stdlib.h>
#include<stdio.h>
typedef unsigned int uint;
typedef struct Node {
size_t id; // identifier of the node
int data; // actual data
size_t num_parents; // actual number of parent nodes
size_t size_parents; // current maximum capacity of array of parent nodes
struct Node** parents; // all nodes that connect from "upstream"
size_t num_children; // actual number of child nodes
size_t size_children; // current maximum capacity of array of children nodes
struct Node** children; // all nodes that connect "downstream"
} Node;
Node** reallocate_node_array(Node** array, size_t* size) {
Node** new_array = realloc(array, sizeof(Node*) * (*size) * 2);
if (new_array == NULL) {
perror("realloc");
exit(1);
}
*size *= 2;
return new_array;
}
// The intention is to pass `num_children` or `num_parents` as `size` in order to decrease them
void remove_node(Node** array, size_t* size, size_t index) {
for (size_t i = index; i < *size - 1; i++) {
array[i] = array[i + 1];
}
(*size)--; // the decrement to either `num_children` or `num_parents`
}
void remove_parent(Node* node, size_t id) {
for (size_t i = 0; i < node->num_parents; i++) {
if (node->parents[i]->id == id) {
remove_node(node->parents, &node->num_parents, i);
}
}
}
void remove_child(Node* node, size_t id) {
for (size_t i = 0; i < node->num_children; i++) {
if (node->children[i]->id == id) {
remove_node(node->children, &node->num_children, i);
}
}
}
void add_parent(Node* node, Node* parent) {
if (node->num_parents >= node->size_parents) {
node->parents = reallocate_node_array(node->parents, &node->size_parents);
}
node->parents[node->num_parents++] = parent;
}
void add_child(Node* node, Node* child) {
if (node->num_children >= node->size_children) {
node->children = reallocate_node_array(node->children, &node->size_children);
}
node->children[node->num_children++] = child;
}
uint number_of_digits(int n) {
uint d = 0;
do { d++; n /= 10; } while (n != 0);
return d;
}
// return format: "{ parent1.id parent2.id ...} { id data } { child1.id child2.id ...}"
void print_node(Node node) {
printf("{ ");
for (size_t i = 0; i < node.num_parents; i++) {
printf("%zu ", node.parents[i]->id);
}
printf("} [ %zu %d ] { ", node.id, node.data);
for (size_t i = 0; i < node.num_children; i++) {
printf("%zu ", node.children[i]->id);
}
printf("}\n");
}
void switch_nodes(Node* n1, Node* n2, Node** array) {
uint temp_id = n1->id;
uint temp_data = n1->data;
n1->id = n2->id;
n1->data = n2->data;
n2->id = temp_id;
n2->data = temp_data;
Node* temp = array[n1->id];
array[n1->id] = array[n2->id];
array[n2->id] = temp;
}
int find_smallest_valued_parent(Node* node, uint depth) {
// has no parents
if (node->num_parents == 0 || node->parents == NULL) {
if (depth == 0) return -1; // there was no parent on first call (nothing to report)
else return node->data;
}
else {
depth++;
int minimum_value = node->parents[0]->data; // we're guaranteed 1 parent
for (size_t i = 0; i < node->num_parents; i++) {
int next_value = find_smallest_valued_parent(node->parents[i], depth);
if (node->parents[i]->data < next_value) next_value = node->parents[i]->data;
if (next_value < minimum_value) minimum_value = next_value;
}
return minimum_value;
}
}
void free_node_array(Node** array, size_t start, size_t end) {
for (size_t i = start; i < end; i++) {
free(array[i]);
}
free(array);
}
int main() {
char* file_name = "input_feodorv.txt";
FILE* data_file = fopen(file_name, "r");
if (data_file == NULL) {
printf("Error: invalid file %s", file_name);
return 1;
}
for (;;) {
size_t num_nodes, num_relationships, num_instructions;
if (fscanf(data_file, "%zu %zu %zu\n", &num_nodes, &num_relationships, &num_instructions) == EOF)
break;
Node** nodes = malloc((num_nodes + 1) * sizeof(Node*));
for (size_t i = 1; i <= num_nodes; i++) {
nodes[i] = malloc(sizeof(Node)); // WARNING Buffer overrun while writing to 'nodes': the writable size is '((num_nodes+1))*sizeof(Node *)' bytes, but '16' bytes might be written.
nodes[i]->id = i; // WARNING Reading invalid data from 'nodes': the readable size is '((num_nodes+1))*sizeof(Node *)' bytes, but '16' bytes may be read.
fscanf(data_file, "%u ", &nodes[i]->data);
nodes[i]->num_children = 0;
nodes[i]->size_children = 2;
nodes[i]->children = (Node**)malloc(2 * sizeof(Node*));
for (size_t j = 0; j < 2; j++) nodes[i]->children[j] = malloc(sizeof(Node));
nodes[i]->num_parents = 0;
nodes[i]->size_parents = 2;
nodes[i]->parents = (Node**)malloc(2 * sizeof(Node*));
for (size_t j = 0; j < 2; j++) nodes[i]->parents[j] = malloc(sizeof(Node));
}
for (size_t i = 0; i < num_relationships; i++) {
size_t parent_id, child_id;
fscanf(data_file, "%zu %zu\n", &parent_id, &child_id);
add_child(nodes[parent_id], nodes[child_id]);
add_parent(nodes[child_id], nodes[parent_id]);
}
for (size_t i = 0; i < num_instructions; i++) {
char instruction;
fscanf(data_file, "%c ", &instruction);
if (instruction == 'P') {
size_t id;
fscanf(data_file, "%zu\n", &id);
int minimum_value = find_smallest_valued_parent(nodes[id], 0);
if (minimum_value == -1) printf("*\n");
else printf("%u\n", minimum_value);
}
else {
size_t n1_id, n2_id;
fscanf(data_file, "%zu %zu\n", &n1_id, &n2_id);
switch_nodes(nodes[n1_id], nodes[n2_id], nodes);
}
}
/**/
for (size_t i = 1; i <= num_nodes; i++) {
free_node_array(nodes[i]->parents, 0, nodes[i]->size_parents);
free_node_array(nodes[i]->children, 0, nodes[i]->size_children);
}
free_node_array(nodes, 0, num_nodes);
/**/
}
}
There is a memory leak in your code. In the main() function, you are doing:
nodes[i]->children = (Node**)malloc(2 * sizeof(Node*));
for (size_t j = 0; j < 2; j++) nodes[i]->children[j] = malloc(sizeof(Node));
and
nodes[i]->parents = (Node**)malloc(2 * sizeof(Node*));
for (size_t j = 0; j < 2; j++) nodes[i]->parents[j] = malloc(sizeof(Node));
that mean, allocating memory to nodes[i]->children[j] and nodes[i]->parents[j] pointers.
In add_child() and add_parent() function, you are making them point to some other node resulting in loosing there allocated memory reference:
void add_parent(Node* node, Node* parent) {
.....
node->parents[node->num_parents++] = parent;
}
void add_child(Node* node, Node* child) {
.....
node->children[node->num_children++] = child;
}
You actually don't need to allocate memory to nodes[i]->children[j] and nodes[i]->parents[j] pointers in main() because these pointer are suppose to point to the existing nodes of the graph and you are already allocating memory to those nodes here in main():
nodes[i] = malloc(sizeof(Node));
nodes[i] is an element of array of all the nodes of the given graph and childrens and parents pointer should point to these nodes only.
Now coming to freeing these pointers:
The way you are freeing the nodes of graph is not correct. Look at free_node_array() function:
void free_node_array(Node** array, size_t start, size_t end) {
for (size_t i = start; i < end; i++) {
free(array[i]);
}
free(array);
}
and you are calling it in this way:
for (size_t i = 1; i <= num_nodes; i++) {
free_node_array(nodes[i]->parents, 0, nodes[i]->size_parents);
free_node_array(nodes[i]->children, 0, nodes[i]->size_children);
}
That mean, you are freeing the pointers pointed by array of pointers nodes[i]->parents and nodes[i]->children. The members of nodes[i]->parents and nodes[i]->children are pointers which are pointing to elements of nodes array. It is perfectly possible that a node can be a child 1 or more parents and a parent node can have more than 1 child. Now assume case where a child node is pointed by 2 parent nodes, say n1 and n2. When you call free_node_array() function and pass the first parent (n1), it will end you freeing that child node and when free_node_array() function is called to free the second parent (n2), it will try to free the node which is already freed while freeing n1.
So, this way of freeing the memory is not correct. The correct way to free the memory is, simply, free the elements of nodes array because it's the array which will contain all the nodes of given graph and parents and children pointers are supposed to point to these nodes only. No need to traverse the hierarchy of parent and child nodes. To free the graph appropriately, you should do:
Traverse through the nodes array and for each element of array:
Free the array of parents pointer (free (nodes[i]->parents).
Free the array of children pointer (free (nodes[i]->children).
Free that element of nodes array (free (nodes[i]).
Once, this is done then free the nodes array - free (nodes).

Implementing Binary search tree using array in C

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;
}

Deleting Consecutive Element in a Linked List

Given the following definition of linked-list
typedef struct elemento {
int inf;
struct elemento *next;
} lista;
I'm trying to create a function
lista *SeekAndDestroy(lista *p, int k);
that, given a list *p and a positive integer k, which searches on the list, the first sequence of consecutive elements whose sum is exactly k and eliminate such elements from the list.
My try:
lista *SeekAndDestroy(lista *p, int k) {
lista *a, *nuovo;
int x = 0;
a = (lista *)malloc(sizeof(lista));
a->inf = p->inf;
nuovo = a;
p = p->next;
while (p != NULL) {
if (p->next != NULL) {
if ((p->inf + p->next->inf) == k) {
if (x != 1) {
p = p->next->next;
x = 1;
continue;
}
}
}
nuovo->next = (lista *)malloc(sizeof(lista));
nuovo = nuovo->next;
nuovo->inf = p->inf;
p = p->next;
}
nuovo->next = NULL;
return a;
}
This my solution has two main problems:
1) erases a maximum of two consecutive elements and not more
2) if the items to be deleted are the first two, the function does not work
How can i solve this problem? Thanks
For now, let's forget about linked list and pointer and stuffs. Say, we have to solve the problem for a given array. Can we do that? Sure!
for (int i = 0; i < array.length; ++i) {
for (int j = i; j < array.length; ++j) {
int sum = getRangeSum(array, i, j);
if (sum != k) continue;
// construct new array and return
}
}
This code can be optimized further but let's keep it simple for now. So, in linked list, similar approach can be used. And the delete part is also simple. You can keep a variable to keep track of the previous node of i. Let's call it iParent. Now, we can remove the [i, j] segment as iParent->next = j->next.
Obviously, you need to consider some corner cases like if such segment is not found or if the segment starts from the beginning of the linked list etc.
Here's a function I wrote to tackle the two problems faced by you and any other boundary conditions:
list* Seek_Destroy(list* head, int target){
if(head == NULL)
return NULL;
list* temp = head;
bool find_complete = false;
list *prev = temp;
//Loop for iterating until list is complete or target sum is found.
while( !find_complete){
//Create a pointer for loop calculations
list* sum_loop = temp;
//Initialize sum to 0
int sum =0;
//Loop for checking whether the sum is equal to the target
while(sum <= target && sum_loop->next!= NULL){
//Keep adding the sum
sum += sum_loop->inf;
if(sum == target){
//Set the flag for exiting outer loop
find_complete = true;
//Test whether head of the list is included in the sum
if (temp == head){
//Make head point to the struct after the last element included in the sum loop
head = sum_loop->next;
//Delete and free memory
while(temp!= sum_loop){
list* del = temp;
temp = temp->next;
free(del);
}
}else {
//Set the next pointer of previous element of the list to point after the last element included in the sum loop
prev->next= sum_loop->next;
//Delete and free memory
while(temp!= sum_loop){
list* del = temp;
temp = temp->next;
free(del);
}
}
break;
}
//Increment the pointer for the sum calculation
sum_loop = sum_loop->next;
}
prev = temp;
//Make temp point to next element in the list
temp = temp->next;
//IF entire list is traversed set the flag to true
if (temp ==NULL){
find_complete = true;
}
}
return head;
}
Assuming your numbers are all non-negative, there's a more efficient algorithm you can use. You simply run two pointers, ptrA and ptrB, through the list, maintaining the sum of the inclusive elements.
If the sum isn't what you need, you do one of two things. First, if your current sum is less than that needed, bring the next element into the array by advancing ptrB.
If your current sum is more than what you need, you take out the first element in your range by advancing ptrA. Both these operations should, of course, adjust the current range sum. There's an edge case here in that you don't want to do this if there's currently only one item in the range.
And it should go without saying that, if the current range sum is equal to what you need, you simply delete that range and exit.
In terms of pseudo-code, it would be something like:
def delExact(list, desiredSum):
# Check non-empty and start range.
if list is empty:
return
ptrA = list.first
ptrB = ptrA
rangeSum = ptrA.value
# Continue until match found
while rangeSum is not equal to desiredSum:
# Select add-another or remove-first.
if ptrA == ptrB, or rangeSum < desiredSum:
# Need to bring another in, returning if list exhausted.
ptrB = ptrB.next
if ptrB == null:
return
rangeSum = rangeSum + ptrB.value
else:
# Need to remove one.
rangeSum = rangeSum - ptrA.value
ptrA = ptrA.next
# If we exit the loop, we've found a sum match.
# Hence we need to delete ptrA through ptrB inclusive.
However, that two-pointer approach breaks down if negative numbers are allowed since you don't actually know what effect later elements may have.
In that case, you basically have to do an exhaustive search of all possibilities, and that basically boils down to:
for each element in list:
for each possible segment from that element on:
check and act on summed data
That's actually more of an English representation, the pseudo-code for such a beast would be along the lines of:
def delExact(list, desiredSum):
# For each list element.
ptrA = list.first
while ptrA is not null:
# For each possible segment starting at that element.
segmentSum = 0
ptrB = ptrA
while ptrB is not null:
add ptrB.value to segmentSum
# Delete segment if sum matches, then return.
if segmentSum is equal to desiredSum:
# Here we delete from ptrA through ptrB inclusive.
return
# Otherwise, keep adding elements to segment.
ptrB = ptrB.next
# No matching segment, move on to next element.
ptrA = ptrA.next
# No matching segment at any element, just return.
The use of either of those algorithms will solve your problem regarding only deleting two elements.
The problem of deleting at the start of the list is to simply recognise that fact (ptrA == list.first) and make sure you adjust the first pointer in that case. This is a standard edge case in linked list processing, and can be implemented as something like:
def deleteRangeInclusive(list, ptrA, ptrB):
# Adjust list to remove ptrA/ptrB segment,
# allowing for possibility ptrA may be the head.
if ptrA == list.first:
list.first = ptrB.next
else:
beforeA = list.first
while beforeA.next != ptrA:
beforeA = beforeA.next
beforeA.next = ptrB.next
# Now we can safely remove the ptrA-ptrB segment.
while ptrA != ptrB:
tempA = ptrA
ptrA = ptrA.next
delete element tempA
delete element ptrB
I solved like that:
Lista *Distruggi(Lista *p, int k) {
Lista *n = NULL, *nuova = NULL;
int z = 0;
for (Lista *i = p; i != NULL && z != 1; i = i->next) {
for (Lista *j = i; j != NULL; j = j->next) {
int sum = somma(i, j);
if (sum != k) continue;
n = (Lista *)malloc(sizeof(Lista));
n->inf = p->inf;
p = p->next;
nuova = n;
while (p != i) {
nuova->next = (Lista *)malloc(sizeof(Lista));
nuova = nuova->next;
nuova->inf = p->inf;
p = p->next;
}
while (j != NULL) {
nuova->next = (Lista *)malloc(sizeof(Lista));
nuova = nuova->next;
nuova->inf = j->inf;
j = j->next;
}
z = 1;
break;
}
}
if (z == 0) return p;//NO CHANGE
else {//CHANGE
nuova->next = NULL;
return n;
}
}

Measuring time in C

I'm writing a lab assignment for programming classes. I need to do it in C :). The task I choose looks as follows: I created three kinds of data types in C: linked list, binary tree and avl tree. All the data handle 5,000,000 elements. I need to measure how long it takes to find and not find element in certain step. I have fixed values for positive and negative findings.
Here is some of my code that contains function for creating array of 5,000,000 numbers and two function for binary tree adding and finding node. I hope that the code is quite clear.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5000000
typedef struct Node {
int data;
struct Node *left, *right;
} Node;
void evenArrayGen(int num, int even_nums[]);
void shuffle(int numbers[]);
void addNode(Node **root, int value);
Node* findNode(Node *root, int value);
/** Recursively adds given value to the tree
*
* #param root
* #param value
*
*/
void addNode(Node **root, int value) {
Node *temp;
///check statement to avoid infinite loop in adding
if(*root == NULL) {
temp = (Node*)malloc(sizeof(Node));
temp->data = value;
temp->left = temp->right = NULL;
*root = temp;
return;
}
///recursively check where to add node
///if smaller than the root add to the left
///if bigger than the root add to the right
else {
temp = *root;
if(value < temp->data) {
addNode(&(temp->left), value);
} else {
addNode(&(temp->right), value);
}
return;
}
}
/** Recursively searches for Node with given value
*
* #param root
* #param value
* #return Node or NULL (if Node was not found)
*
*/
Node* findNode(Node *root, int value) {
Node *temp;
///check statement to avoid infinite loop in searching
///if it reachese that point given value is not in the tree
if(root == NULL) {
// printf("Given value is not in the tree\n");
return NULL;
}
temp = root;
if(temp->data == value) {
// printf("Searched value is: %i\n", temp->data);
return temp;
} else if(value < temp->data) {
findNode(temp->left, value);
} else {
findNode(temp->right, value);
}
}
/** Generates array of ordered even numbers from 2
*
* #param num number of uniqe even digits
* #param array of size equal to the number
*
*/
void evenArrayGen(int num, int even_nums[]) {
int i, current;
i = current = 0;
for(; i<num; i++) {
even_nums[i] = current += 2;
}
return;
}
/** Shuffle the array in random order. Radomly gets the index between 0 and
* current last index. Swaps number at random index with last one and
* decreses the current_last index by 1.
*
* #param array of numbers to be shuffled
*
*/
void shuffle(int nums[]) {
int i, len, current_last, index, temp;
///set the current_last to length of the array to track index for
///swaping nums
current_last = len = SIZE;
for (i=0; i<len; i++) {
srand(time(NULL));
index = rand()%(current_last);
temp = nums[index];
nums[index] = nums[current_last];
nums[current_last] = temp;
current_last--;
}
return;
}
int main() {
//initialize root for the tree
Node *root;
//intilialize array of 5,000,000 elements, and scores
static int nums[SIZE];
int i; //iterator
//initialize positive and negative numbers for find method
int positive_num, negative_num;
//initilaize timer
clock_t start_for_adding, start_for_finding;
//add elements to the array
evenArrayGen(SIZE, nums);
shuffle(nums);
//set positive number to one of the first 5000 elements
positive_num = nums[3222];
negative_num = 345; //all numbers in num are even so negative need to be odd
root = NULL; //set the root Node to NULL
start_for_adding = clock(); //zero the timer
//now iterate trough all elements in nums array and add each to
//the binary tree
for(i=0; i<SIZE; i++) {
//check if i reached proper value
if (i == 5000 || i == 50000 || i == 500000 || i == (5000000-1)) {
//add the adding time
printf("\nIndex: %d\n", i);
printf("Adding: %.5f\n", (double) clock() - start_for_adding);
start_for_finding = clock(); //zero the timer
//search for positive num
findNode(root, positive_num);
printf("Finding positive: %.5f\n",
(double) clock() - start_for_finding);
start_for_finding = clock(); //zero the timer
//search for negative num
findNode(root, negative_num);
printf("Finding negative: %.5f\n",
(double) clock() - start_for_finding);
start_for_adding = clock(); //reset the timer for adding
}
addNode(&root, nums[i]);
}
return;
}
The times for finding elements are pointing to zero (in both cases)
I'm pretty lost, have no idea where to follow now (the easiest part for my task shows that is the hardest one...)
The resolution of clock is most likely to coarse to measure the time taken by individual calls to your findNode function. Typically the time is measured to perform such a call lots of times and then divide this time by the number of times the call was performed.

Resources