Heapsort implementation in C - array error - c

I was trying to implement Heapsort algorithm in C but I'm not sure I'm done it right. I also have an error "variably modified 'A' at file scope". I was searching similar topic on stackoverflow and I found out that heapSize should be const but then I couldn't use it as a variable in my functions. What should I do?
#include <stdio.h>
#include <math.h>
int heapSize = 100;
int length;
int A[heapSize];
int Heapify(int i) {
int l = 2*i;
int r = 2*i + 1;
int largest;
int tmp;
if( l <= heapSize && A[l] > A[i]) largest = l;
else largest = i;
if (r <= heapSize && A[r] > A[largest]) largest = r;
if (largest != i) {
tmp = A[i];
A[i] = A[largest];
A[largest] = tmp;
}
}
int BuildHeap() {
heapSize = length;
int i;
for (i = floor(length/2); i <= 1; i--) {
Heapify(i);
}
}
int main(void) {
int i,tmp;
BuildHeap();
for (i = length; i <= 2; i--) {
tmp = A[heapSize];
A[heapSize] = A[1];
A[1] = A[heapSize];
heapSize = heapSize - 1;
Heapify(1);
}
}
EDIT:
I changed the first part of program to:
#include <stdio.h>
#define LENGTH 100
int heapSize = 10;
int A[LENGTH]
and, based on your suggestions, replace the "floor(length/2)" to "LENGTH/2". I solve my problems with compiling but I'm pretty sure this implementation is just bad. Well, anyway thank you very much for your help. I really appreciate it.

There's lots of issues with your code.
First, you declare a global int length variable, but you never assign it any value. So the length is always ZERO.
In BuildHeap() you do:
for (i = floor(length/2); i <= 1; i--) ...
which starts with floor(0/2) that is with i==0. That value is less than 1 so the loop makes the first iteration and decrements i with the i-- expression — and i becomes minus one. Then the loop proceeds until the i value wraps over zero to become positive (and greater than 1). For 32-bit integers it would take about 2.14 billion iterations...
The very first thing your main() does is invoking BuildHeap() which in turn invokes (multiple times) Heapify(). The latter compares array items to decide if they should get swapped – but they were not assigned any values! You never fill the A array with any data...
Did you notice that you compare and swap items which are outside your A array (actually, before it), since BuildHeap() decrements i below zero and passes negatve index values to Heapify()...?
Your Heapify routine performs at most one swap in the array. It doesn't seem sufficient. Suppose the heap is already 3 levels deep, and the current item appears the smallest one in the heap; it should go to the deepest level, but how do you achieve that? A single swap moves the item just one level downwards.
This is how you could do it.
First, decide the maximum size of data you will handle and prepare the array:
#define LENGTH 100
int A[LENGTH + 1];
(You need 'plus one' because A[0] will not be a part of the heap — why?)
Then prepare variables to store an actual size of data:
int dataSize;
int heapSize;
and a routine to fill the array. You can read the user input or load data from a file, or just fill the array by some algorithm.
void FillArrayAscending() {
dataSize = 16;
for(int i = 1; i <= dataSize; i ++)
A[i] = i;
}
void FillArrayDescending() {
dataSize = 25;
for(int i = 1; i <= dataSize; i ++)
A[i] = 50 - i;
}
void FillArrayCrossed() {
dataSize = 20;
for(int i = 1; i <= dataSize; i += 2)
A[i] = 10 + i;
for(int i = 2; i <= dataSize; i += 2)
A[i] = 30 - i;
}
Then you can 'heapify'. To do that you sift the item down the heap – you iterate swapping until the item reaches its place:
void SiftDown(int i) {
while(i < heapSize) {
int largest = i;
if(2*i <= heapSize && A[i] < A[2*i])
largest = 2*i;
if(2*i + 1 <= heapSize && A[largest] < A[2*i + 1])
largest = 2*i + 1;
if(largest == i)
break; // the item reached its place
A[0] = A[largest];
A[largest] = A[i];
A[i] = A[0];
i = largest; // new position to sift down...
}
}
i indicates the item to be sifted down, largest denotes a swap destination, A[0] can be used as a temporary storage (why?).
Now you can build a heap in the array:
void BuildHeap() {
heapSize = dataSize;
for(int i = heapSize/2; i >= 1; i --)
SiftDown(i);
}
and retrieve items from a heap in a descending order:
void ExtractHeap() {
while(heapSize > 1) {
A[0] = A[1]; // take the max item from a heap
A[1] = A[heapSize]; // replace it with the last one
A[heapSize] = A[0]; // add the max one to the sorted part
heapSize --;
SiftDown(1); // re-heapify
}
}
Now you can do the whole processing:
int main(int, char**)
{
FillArrayAscending(); // or Descending or...
BuildHeap();
ExtractHeap();
// and here you can print the array contents
// for indices 1 .. dataSize
// to verify it is actually sorted
}

Related

How to generate an array of a specific value with given input array in C code

The title may be a little confusing so I will explain my goal a bit more in detail here;
I want to write a code that takes an input array of the x numbers
index_x = [0,0,1,0,1,0,0,0,1,0,0,1,0];
Then I want to write a logic that will generate an array that has the index of all the 1s
index_ones = [3,5,9,12];
Current code slightly modified from Jacon:
Edit 1:
#include <stdio.h>
int index_x[] = {0,0,1,0,1,0,0,0,1,0,0,1,0}; // any number of elements
int len = 12;
int main(void) {
int arr[len];
int j = 0;
for (int i = 0; i < len; i++)
if (index_x[i])
arr[j++] = i; // save and advance j only if value is "1"
for (int i = 0; i < j; i++) // only print below j !
printf("%d\n", arr[i]);
}
Output:
2
4
8
11
From this output, I would like to generate another array that is the difference between these elements. In this case the new array would be {2,4,3}.
Edit 2: I will move this to another thread as the discussion has now moved from one problem to another. Do not want to complicate things for future users.
As you do not know how many indexes you need you will need to allocate the memory dynamically. You need also to remember the number of indexes
struct index
{
size_t size;
size_t indexes[];
};
struct index *addIndex(struct index *index, size_t pos)
{
size_t new_size = index ? index -> size + 1 : 1;
index = realloc(index, sizeof(*index) + new_size * sizeof(index -> indexes[0]));
if(index)
{
index -> size = new_size;
index -> indexes[new_size - 1] = pos;
}
return index;
}
struct index *buildIndex(int *arr, size_t arr_size, int val)
{
struct index *index = NULL, *tmp;
for(size_t pos = 0; pos < arr_size; pos++)
{
if(arr[pos] == val)
{
tmp = addIndex(index, pos);
if(tmp) index = tmp;
else { /* error handling */ }
}
}
return index;
}
Find array element count of index_x[].
int index_x[] = {0,0,1,0,1,0,0,0,1,0,0,1,0};
...
// e.g. 13, not 12 as implied with int len = 12;
size_t index_x_count = sizeof index_x / sizeof index_x[0];
Then run through index_x[] to find numbers of the ones.
size_t ones = 0;
for (size_t i = 0; i < index_x_count; i++) {
if (index_x[i] == 1) {
ones++;
}
}
Now we know the size needed for "generate an array that has the index of all the 1s"
// Error check, can't have array size 0
if (ones == 0) Handle_patholocial_case();
// We should avoid forming huge arrays. 10000 is arbitrary.
// When large, rather than form _arrays_, allocate memory (not shown).
if (ones > 10000) Handle_patholocial_case();
// Form the array
int arr[ones];
size_t a = 0;
for (size_t i = 0; i < ones; i++) {
if (index_x[i] == 1) {
arr[a++] = i;
}
}
generate another array that is the difference between these elements.
// Error check for at least one difference, can't have array size 0
if (ones <= 1) Handle_patholocial_case();
// Form the array
size_t diff_count = ones - 1;
int diff[diff_count];
for (size_t d = 0; d < diff_count; d++) {
diff[a] = arr[d+1] - arr[d];
}
Do something with diff[]
for (size_t d = 0; d < diff_count; d++) {
printf("%d ", diff[d]);
}

Make sums of left and right sides of array equal by removing subarray

C program that finds starting and ending indexes of subarray to remove to make given array have equal sums of left and right side. If its impossible print -1. I need it to work for any array, this is just for testing. Heres a code that finds equilibrium.
#include <stdio.h>
int equilibrium(int arr[], int n)
{
int i, j;
int leftsum, rightsum;
/* Check for indexes one by one until
an equilibrium index is found */
for (i = 0; i < n; ++i) {
/* get left sum */
leftsum = 0;
for (j = 0; j < i; j++)
leftsum += arr[j];
/* get right sum */
rightsum = 0;
for (j = i + 1; j < n; j++)
rightsum += arr[j];
/* if leftsum and rightsum are same,
then we are done */
if (leftsum == rightsum)
return i;
}
/* return -1 if no equilibrium index is found */
return -1;
}
// Driver code
int main()
{
int arr[] = { -7, 1, 5, 2, -4, 3, 0 };
int arr_size = sizeof(arr) / sizeof(arr[0]);
printf("%d", equilibrium(arr, arr_size));
getchar();
return 0;
}
You could solve this problem in O(NlogN) or O(N)(in average case).
First, you need to make a pre-processing, saving all the sums from right to left in a data structure, specifically a balanced binary search tree(e.g. Red Black tree, AVL Tree, Splay Tree, etc, if you could use stdlib, just use std::multiset) or a HashTable(in stdlib it's std::unordered_multiset):
void preProcessing(dataStructure & ds, int * arr, int n){
int sum = 0;
int * toDelete = (int) malloc(n)
for(int i = n-1; i >= 0; --i){
sum += arr[i];
toDelete[i] = sum; // Save items to delete later.
tree.insert(sum);
}
So to solve problem you just need to traverse the array one time:
// It considers that the deleted subarray could be empty
bool Solve(dataStructure & ds, int * arr, int n, int * toDelete){
int sum = 0;
bool solved = false; // true if a solution is found
for(int i = 0 ; i < n; ++i){
ds.erase(toDelete[i]); // deletes the actual sum up to i-th element from data structure, as it couldn't be part of the solution.
// It costs O(logN)(BBST) or O(1)(Hashtable)
sum += arr[i];
if(ds.find(sum)){// If sum is in ds, then there's a leftsum == rightsum
// It costs O(logN)(BBST) or O(1)(HashTable)
solved = true;
break;
}
}
return solved;
}
Then, if you use a BBST(Balanced Binary Search Tree) your solution would be O(NlogN), but, if you use HashTable, your solution would be O(N) on average. I wouldn't implemented it, so maybe there's a bug, but I try to explain the main idea.

Find recursively the third biggest element of array in c

This one was asked in one of my computer science exam months has passed but I couldn't find any answers.Sometimes I wonder if its possible or not here is the prototype.
The objective is to return the index of third largest element in an integer array.I have learned how to find the largest and second largest but this seems hard.
int third_max(int arr[],int size);
I am looking a recursive function that will find it by maybe only one functions help that is max(a,b) which returns the max of a,b.
Edit : There is no duplicate elements
My implementation of third_max(). (It uses an assert to catch a starting array shorter than three elements.) First it sorts the first three elements in the array in place; if the array is only three elements long, it returns the first. If the array is more than three elements, it compares the first and forth elements, keeping the larger as the fourth element. Finally, it calls it self recursively dropping off the first array element and decrimenting the array size:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define ARRAY_SIZE (10)
int third_max(int array[], size_t size) {
assert(size > 2);
if (array[0] > array[1]) {
int temp = array[1];
array[1] = array[0];
array[0] = temp;
}
if (array[1] > array[2]) {
int temp = array[2];
array[2] = array[1];
array[1] = temp;
}
if (array[0] > array[1]) {
int temp = array[1];
array[1] = array[0];
array[0] = temp;
}
if (size == 3) {
return array[0];
}
if (array[0] > array[3]) {
array[3] = array[0];
}
return third_max(array + 1, size - 1);
}
int compare(const void *a, const void *b) {
const int *aa = a;
const int *bb = b;
return (*aa > *bb) - (*aa < *bb);
}
int main() {
int array[ARRAY_SIZE], control[ARRAY_SIZE];
srandomdev();
for (int i = 0; i < ARRAY_SIZE; i++) {
int x = -1;
while (x == -1) {
x = (random() & 127) - 63;
for (int j = 0; j < i; j++) {
if (array[j] == x) { // avoid duplicates
x = -1;
break;
}
}
}
control[i] = array[i] = x;
}
printf("[");
for (int i = 0; i < ARRAY_SIZE; i++) {
printf("%d, ", array[i]);
}
printf("] -> ");
printf("%d ", third_max(array, ARRAY_SIZE));
qsort(control, ARRAY_SIZE, sizeof(int), &compare);
printf("(%d)\n", control[ARRAY_SIZE - 3]);
return 1;
}
The rest of the code tests the third_max() function by creating an array of unique positive integers. It compares the results of the recursive function to that of a matching control array that is sorted and the third to last element extracted for comparison.
My third_max() doesn't call any other functions other than itself (i.e. no helper functions.) It is destructive on the array passed in.
Without any additional constraints, a naive but effective solution would simply be to create a sorted copy of the array, take the third element, then find that element in the original array and return its index. The theoretical complexity is O(n log n) in time and O(n) in space. An O(n) time solution is possible.

Wrong output in Merge Sort Algorithm

I've followed all the algorithm steps very carefully , but still this always outputs me the wrong answer. I don't understand why. I think something's wrong in the merge algorithm that's causing this but cannot pinpoint what. Please help. Also if there is anything that can be done to improve the code please suggest.
Thank you
INPUT - {5,6,1,8,9,7}
OUTPUT - {1,0,7,0,9,7}
#include<stdio.h>
#include<malloc.h>
void mergeSort(int array[],int length);
void merge(int *leftArray,int *rightArray,int *array);
void main()
{
int array[] = {5,6,1,8,9,7};
int length_of_array;
length_of_array = sizeof(array) / sizeof(array[0]);
mergeSort(array,length_of_array);
int i;
for(i=0;i<length_of_array;i++)
{
printf("%d->",array[i]);
}
}
void mergeSort(int array[],int length)
{
if(length < 2)
return;
int mid;
int i;
mid = length/2;
int *leftArray, *rightArray;
leftArray = (int*)malloc(mid*sizeof(int));
rightArray = (int*)malloc((length-mid)*sizeof(int));
for(i=0;i<mid;i++)
leftArray[i] = array[i];
for(i=mid;i<length;i++)
rightArray[i-mid] = array[i];
mergeSort(leftArray, mid);
mergeSort(rightArray, length-mid);
merge(leftArray,rightArray,array);
}
void merge(int *leftArray,int *rightArray,int *array)
{
int i,j,k;
i = j = k = 0;
int leftSize = sizeof(leftArray)/sizeof(leftArray[0]);
int rightSize = sizeof(rightArray)/sizeof(rightArray[0]);
while(i < leftSize && j < rightSize)
{
if(leftArray[i]<rightArray[j])
{
array[k] = leftArray[i];
k = k + 1;
i = i + 1;
}
else
{
array[k] = rightArray[j];
k = k + 1;
j = j + 1;
}
}
while(i<leftSize)
{
array[k] = leftArray[i];
k = k + 1;
i = i + 1;
}
while(j<rightSize)
{
array[k] = rightArray[j];
k = k + 1;
j = j + 1;
}
}
As commented by #molbdnilo, you can't get the size of an array from a pointer parameter. So merge needs to take the length of the left and right arrays as well as the pointers to them.
The issue is that arrays in C are not a 'complete' data type, but rather just a convenient syntax. In your merge function, the parameter int *leftArray is exactly what it says - a pointer to an integer. So sizeof will tell you the size of a pointer. In your main function, array is known to be an array, and its length is known (from the initial value given), so sizeof can give the actual size of memory allocated to that variable. But that size is not stored anywhere with the variable, so it is not passed into merge - the only thing passed in is the pointer to the block of memory.
In addition, while it won't be causing you problems in this case, you should be freeing the leftArray and rightArray pointers that you malloc. That way you can use your sorting function in an actual application without leaking memory.

Given an array of single digit, positive integers, convert to a whole number, multiply by 2, return an array of new product with each digit in array

For example:
[1,2,3] -> [2,4,6]
[9,1] -> [1,8,2]
[6,7,5] -> [1,3,5,0]
I got this question on my first tech interview yesterday (did it in C because that's my best language, so a C answer would be help more) and completely blanked :(
This is what I was thinking:
Start at the end of the array and keeping moving left
At every arr[i], multiply by 2 and see if there're 2 digits (if arr[i]/10 != 0) and if there is a left most digit, carry it over to arr[i-1] as long as a[i-1] != NULL.
I just could not figure out how to actually do this in C. I had something like:
int* multTwo(int* arr, int len) {
int *newarr; // I know i have to malloc, but not sure what size because
// wouldnt the size depend on the new number's size?
int temp, i;
for (i=len-1; i>=0; i--) {
temp = arr[i]*2;
newarr[i] = temp%2;
if(temp/10 != 0)
newarr[i-1] = temp/2;
}
return newarr;
}
But there are a lot of bugs in my code. Is there a better way or am I on the right track?
Some pseudo code. The main idea is to show the depth of C knowledge as part of the interview, not Code golf.
What signature?
// arr is not changed, use `const`
// array indexing best done with `size_t`
int* multTwo(const int* arr, size_t len) {
Size needed and show error handling. Maybe also detect arr == NULL when len > 0
need = len;
// if lead element is 5 or more, add 1.
// Error if element is not in 0-9 range
Allocate memory. Allocating to size of variable de-referenced type is less error prone, easier to review and maintain than coding the variable type. Showing maintenance concerns during a C interview is a good thing. Think if later code changed to unsigned char* multTwo(const unsigned char* arr, size_t len) {, no need to change newarr = malloc(sizeof *newarr * need).
newarr = malloc(sizeof *newarr * need)
Check allocation. An allocation of 0 is OK to return NULL. Yet maybe this routine should still allocate 1 byte, a tad wasteful, to insure a NULL return is an error. Discussing issues like with the interviewer is good. Shows you want to clearly understand the customer's need not just in the meat of the function, but the corner cases.
if (newarr == NULL && need > 0) fail()
Loop though and populate the new array much like OP coded with meaningful variable names and using unsigned array indexing.
size_t arr_i=len;
size_t newarr_i=need;
int carry = 0;
while (arr_i > 0)
sum = arr[--arr_i]*2 + carry;
newarr[--newarr_i] = sum%10;
carry = sum/10;
}
if (carry) {
newarr[--newarr_i] = carry;
}
Return newarr
Best I can think in a short time, like an interview
#include <stdio.h>
#include <stdlib.h>
void invert (int *head, int *tail)
{
int temp;
if (head < tail)
{
temp = *head;
*head = *tail;
*tail = temp;
invert(++head, --tail);
}
}
int* multTwo(int* arr, size_t len)
{
int value = 0;
int n_digits =0 ;
// CONVERT THE ARRAY TO NUMBER
while(len--)
{
value += *arr;
value *=10;
arr++;
}
value /= 10;
// DOUBLE THE NUMBER
value *= 2;
// CONVERT IT TO BUFFER
int *digits = malloc(sizeof(*digits));
while ((value>0) && (digits != NULL))
{
digits[n_digits++] = value%10;
value /= 10;
digits = realloc( digits, sizeof(*digits) * (n_digits+1) );
}
if (digits != NULL)
{
invert(digits, &digits[n_digits-1]);
printf("[ ");
for (int i=0; i<n_digits; i++)
printf("%d, ", digits[i]);
printf("]\n");
}
return digits;
}
int main(void)
{
int array[] = {6,7,5};
multTwo(array, sizeof(array)/sizeof(array[0]));
return 0;
}
I would start by looking to see if either the first digit in arr is 5 or more to check if the newarr array needs to be 1 larger than the original array.
So something like this for initialization:
int* newarr;
int newlen;
if (*arr >= 5)
newlen = len + 1;
else
newlen = len;
newarr = (int*)malloc(sizeof(int) * newlen);
memset(newarr, 0, newlen); //initialize all newarr values to 0
Now obviously we have to do our multiplication now. To get the 1's digit we do use the modulo operator %, and to get the 10's digit we use the division operator /. Of course we only need to do the division if our multiplied value is 10 or greater. So our loop to populate newarr will look something like this:
int i, temp;
for (i = 1; i <= len; i++) {
temp = *(arr + i - 1) * 2;
if (temp < 10) {
*(newarr + i - 1) += temp;
}
else {
*(newarr + i - 1) += temp / 10; //inset 10's digit
*(newarr + i) += temp % 10; //inset 1's digit
}
}
So our full function ends up being
#include <stdlib.h>
#include <string.h>
int* multTwo(int* arr, int len)
{
int* newarr;
int newlen;
if (*arr >= 5)
newlen = len + 1;
else
newlen = len;
newarr = (int*)malloc(sizeof(int) * newlen);
memset(newarr, 0, newlen); //initialize all newarr values to 0
int i, temp;
for (i = 1; i <= len; i++) {
temp = *(arr + i - 1) * 2;
if (temp < 10) {
*(newarr + i - 1) += temp;
}
else {
*(newarr + i - 1) += temp / 10; //insert 10's digit
*(newarr + i) += temp % 10; //inset 1's digit
}
}
return newarr; //don't forget to free once you're done with newarr!
}

Resources