I've built an adjust heap function, but my assert(position < array->size) is failing and I can't figure out why.
void adjustHeap(DynamicArray* heap, int max, int pos, compareFunction compare)
{
// FIXME: implement
int leftChild = 2 * pos + 1;
int rightChild = 2 * pos + 2;
int idxSmallest = indexSmallest(heap, leftChild, rightChild);
if(rightChild < max) { /* we have two children */
if(dyGet(heap, pos) > dyGet(heap, idxSmallest)) {
dySwap(heap,pos,idxSmallest);
adjustHeap(heap, max, idxSmallest, compare);
}
}
else if (leftChild < max) { /* we have one child */
if(dyGet(heap, pos) > dyGet(heap, leftChild)) {
dySwap(heap,pos,leftChild);
adjustHeap(heap, max, leftChild, compare);
}
}
else {
return;
}
}
My dyGet() function:
TYPE dyGet(DynamicArray* array, int position)
{
assert(position < array->size);
return array->data[position];
}
My assert(position < array->size) is failing in dyGet() using the following test:
void testAdjustHeap(CuTest* test)
{
const int n = 100;
Task* tasks = createTasks(n);
for (int j = 0; j < n; j++)
{
DynamicArray* heap = dyNew(1);
for (int i = 0; i < n; i++)
{
dyAdd(heap, &tasks[i]);
}
for (int i = 0; i < n; i++)
{
dyPut(heap, &tasks[rand() % n], 0);
adjustHeap(heap, dySize(heap) - 1, 0, taskCompare);
assertHeapProperty(test, heap);
}
dyDelete(heap);
}
free(tasks);
}
'indexSmallest' function:
int indexSmallest(struct DynamicArray * v, int i, int j) { /* return index of smallest element */
if(i < j) {
return i;
}
return j;
}
What is the purpose of passing your array into index smallest? The function looks wrong. i is always going to be less than j no matter what based on
int leftChild = 2 * pos + 1;
int rightChild = 2 * pos + 2;
if youre talking about the actual data contained at those children, then it might look different.
perhaps passing in
indexSmallest(v->data[leftChild], v->data[rightChild])
I hope that helps
Related
I hope i made my self clear enough in the title but if not i am here to explain my self
i got an array from an input ( like Arr = {, ).
we can use only 1 additional array (1 original 1 additional)
this is what i made so far :
I made a new array named newArr and assigned it all the values Arr contains.
i sorted it (because its requires time complexity of nlogn)
and then moved duplicates to the end.
now what i can't figure out :
now i need to move the original digits to their place according to the main
(all the values in the arrays are positive and they can be bigger then
n-which is the size of the array and ofc they can be also smaller then n)
i also need to return the number of original digits in the array
the original number should stay in the same position and the duplicates in the end of the array their order doesn't matter.
from here we can't use another additional array only the current arrays that we have ( which are 2)
i have been thinking about doing some kind of binary search but all of them went wrong.(like bin_search_first) and original binary and still couldn't manage it.
can some one give me an hint?
here is the code at where i am
#define _CRT_SECURE_NO_WARNINGS
/*Libraries*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
int* input_array(int);
int moveDuplicatesV2(int*, int);
void merge(int* a, int p, int q, int r);
void merge_sort(int* a, int first, int last);
void swap(int* v, int* u);
int bin_search_first(int , int* , int );
int main()
{
int arr[10] = { };
int n = 12;
int k = 0;
int first = 0;
int last = n - 1;
int mid = (first + last) / 2;
int l = n - 1;
int* D = arr + 1;
int j = 0;
size_t dupes_found = 0;
int* newArr = (int*)malloc(12 * sizeof(int));
assert(newArr);
for (int i = 0; i < n; i++)
{
newArr[i] = arr[i];
}
merge_sort(newArr, first, last);
for (size_t i = 0; i < n - 1 - dupes_found;)
{
if (newArr[i] == newArr[i + 1])
{
dupes_found++;
int temp = newArr[i];
memmove(&newArr[i], &newArr[i + 1], sizeof(int) * (n - i - 1));
newArr[n - 1] = temp;
}
else {
i++;
}
}
j = 0;
int key = 0;
first = 0;
for (int i = 0; i < n - dupes_found; i++)
{
key = newArr[i];
first = bin_search_first(key, arr,n);
swap(&newArr[i], &newArr[first]);
newArr[first] = newArr[i];
}
for (int i = 0; i < n; i++)
{
arr[i] = newArr[i];
}
for (int i = 0; i < n; i++)
{
printf("%d", arr[i]);
}
return n - dupes_found;
}
void merge(int* a, int p, int q, int r)
{
int i = p, j = q + 1, k = 0;
int* temp = (int*)malloc((r - p + 1) * sizeof(int));
assert(temp);
while ((i <= q) && (j <= r))
if (a[i] < a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
while (j <= r)
temp[k++] = a[j++];
while (i <= q)
temp[k++] = a[i++];
/* copy temp[] to a[] */
for (i = p, k = 0; i <= r; i++, k++)
a[i] = temp[k];
free(temp);
}
void merge_sort(int* a, int first, int last)
{
int middle;
if (first < last) {
middle = (first + last) / 2;
merge_sort(a, first, middle);
merge_sort(a, middle + 1, last);
merge(a, first, middle, last);
}
}
void swap(int* v, int* u)
{
int temp;
temp = *v;
*v = *u;
*u = temp;
}
int bin_search_first(int key, int* a, int n)
{
int low, high, mid;
low = 0;
high = n - 1;
while (low <= high)
{
mid = (low + high) / 2; // low + (high - low) / 2
if (key > a[mid])
low = mid + 1;
else
if (key < a[mid])
high = mid - 1;
else //key==a[mid]
if ((low == high) || (a[mid - 1] < key))
return mid;
else
high = mid - 1;
}
return -1;
}
Here is my idea:
Sort the array (nlogn)
Loop over the array and for each value, save a pointer to its first occurence (n)
Loop over the original array and insert the value into a result array if it is the values first occurrence. Whether or not it is the first occurrence can be checked using the sorted array: each element in this array has an additional flag that will be set if the value has already been seen. So, search for the element using bsearch, if seen append to back of result array (order does not matter), if not seen append to beginning of array and set seen value. (nlogn, since bsearch doesn't need to seek the first element because it was precomputed thus logn, over the array n)
Here is an example code (you can replace the qsort by mergesort to make the algorithm actually nlogn, I just used qsort because it is given):
#include <stdio.h>
#include <stdlib.h>
struct arr_value {
int value;
int seen;
struct arr_value *first;
};
int compar(const void *p1,const void *p2) {
struct arr_value *v1 = (struct arr_value *)p1;
struct arr_value *v2 = (struct arr_value *)p2;
if(v1->value < v2->value) {
return -1;
} else if(v1->value == v2->value) {
return 0;
}
return 1;
}
int main()
{
#define NumCount (12)
int arr[NumCount] = { 7, 3, 1, 2, 7, 9, 3, 2, 5, 9, 6, 2 };
int arrResult[NumCount];
int resultCount = 0;
int resultCountBack = 0;
struct arr_value arrseen[NumCount];
for(int i = 0; i < NumCount; ++i) {
arrseen[i].value = arr[i];
arrseen[i].seen = 0;
}
qsort(arrseen, NumCount, sizeof(struct arr_value), compar);
struct arr_value *firstSame = arrseen;
firstSame->first = firstSame;
for(int i = 1; i < NumCount; ++i) {
if(arrseen[i].value != firstSame->value) {
firstSame = arrseen + i;
}
arrseen[i].first = firstSame;
}
struct arr_value key;
for(int i = 0; i < NumCount; ++i) {
key.value = arr[i];
struct arr_value *found = (struct arr_value *)bsearch(&key, arrseen, NumCount, sizeof(struct arr_value), compar);
struct arr_value *first = found->first;
if(first->seen) {
// value already seen, append to back
arrResult[NumCount - 1 - resultCountBack] = first->value;
++resultCountBack;
} else {
// value is new, append
arrResult[resultCount++] = first->value;
first->seen = 1;
}
}
for(int i = 0; i < NumCount; ++i) {
printf("%d ", arrResult[i]);
}
return 0;
}
Output:
7 3 1 2 9 5 6 2 9 2 3 7
To begin with, memmove doesn't run in a constant time, so the loop
for (size_t i = 0; i < n - 1 - dupes_found;)
{
if (newArr[i] == newArr[i + 1])
{
dupes_found++;
int temp = newArr[i];
memmove(&newArr[i], &newArr[i + 1], sizeof(int) * (n - i - 1));
newArr[n - 1] = temp;
}
else {
i++;
}
}
drives the time complexity quadratic. You have to rethink the approach.
It seems that you are not using a crucial point:
all the values in the arrays are positive
It seriously hints that changing values to their negatives is a way to go.
Specifically, as you iterate over the initial array, and bin-search its elements in temp, comparing the _ absolute values_. When an element is found in temp, and it is still positive there, flip all its dupes in temp to negative. Otherwise flip it in initial.
So far, it is O(n log n).
Then perform an algorithm known as stable_partition: all positives are moved in front of negatives, retaining the order. I must not spell it here - I don't want to deprive you of a joy figuring it out yourself (still O(n log n)
And finally flip all negatives back to positives.
I am trying to split set of numbers to 2 different heaps, from their middle value. I used heap data structure to do this. i.e Input is 10 in this example. Apparently I am making some mistake while allocating memory, it gives the following output when I try to allocate dynamically:
[ 4 3 2 0 1 ]
[ 0 0 0 0 0 ]
why the second heap is always 0 ?
Because if I uncomment the static memory allocation and use it instead, it gives true output which is:
[ 4 3 2 0 1 ]
[ 9 8 7 5 6 ]
I have tested my heap and other parts well enough, I am pretty sure the problem is on memory allocation but I couldn't find out where the mistake is.
int main(int argc, char *argv[])
{
int M = atoi(argv[1]);
int pq_1_size = M / 2;
int pq_2_size = M - pq_1_size;
int *a;
int *b;
a = (int *)malloc(pq_1_size * sizeof(int));
b = (int *)malloc(pq_2_size * sizeof(int));
for (int i = 0; i < pq_1_size; i++) {
a[i] = i;
}
for (int j = pq_1_size; j < M; j++) {
b[j] = j;
}
//int a[5] = { 0, 1, 2, 3, 4 }; // if I use this section instead it works fine.
//int b[5] = { 5, 6, 7, 8, 9 }; // if I use this section instead it works fine.
Heap someHeap = { 0, {0} };
Heap *A = &someHeap;
buildHeap(A, a, pq_1_size);
//buildHeap(A, a, 5);
print(A);
printf("\n");
Heap anotherHeap = { 0, {0} };
Heap *B = &anotherHeap;
buildHeap(B, b, pq_2_size);
//buildHeap(B, b, 5);
print(B);
return 0;
}
Below is the heap code:
#define HEAPSIZE 500
#define left(i) ((i)<<1)
#define right(i) (((i)<<1)+1)
#define parent(i) ((i)>>1)
typedef struct {
int size;
int element[HEAPSIZE];
} Heap;
//Swaps the values of two ints a and b
void swap(int * a, int * b) {
int temp;
temp = * a;
* a = * b;
* b = temp;
}
//Ensures that the max heap property in heap A is satisfied at and below index i
void makeHeap(Heap * A, int i) {
int largest = A->element[i];
int position = i;
int l = left(i);
if(l <= A->size && A->element[l] > largest) {
largest = A->element[l];
position = l;
}
int r = right(i);
if(r <= A->size && A->element[r] > largest) {
largest = A->element[r];
position = r;
}
if(i != position) {
swap(&A->element[i], &A->element[position]);
makeHeap(A, position);
}
}
//Get the maximum value in the heap A
int extractMax(Heap * A) {
if(!A->size) {
puts("error: heap empty");
return 0;
}
int max = A->element[0];
swap(&A->element[0], &A->element[A->size]);
--A->size;
makeHeap(A, 0);
return max;
}
//Increase the key of the ith element in heap A to be k
void increaseKey(Heap * A, int i, int k) {
if(A->element[i] >= k) {
printf("error: %d is less than the key of %d\n", k, i);
return;
}
int position = i;
while(position != 0 && A->element[parent(position)] < k) {
A->element[position] = A->element[parent(position)];
position = parent(position);
}
A->element[position] = k;
}
//Inserts the value i into the heap A
void insert(Heap * A, int i) {
if(A->size >= HEAPSIZE) {
printf("error: heap full\n");
return;
}
A->element[A->size] = INT_MIN;
increaseKey(A, A->size, i);
++A->size;
}
//Prints the heap A as an array
void print(Heap * A) {
int i = 0;
printf("[ ");
for(i = 0; i < A->size; i++) {
printf("%d ", A->element[i]);
}
printf("]\n");
}
//Makes a heap out of an unsorted array a of n elements
void buildHeap(Heap * A, int * a, int n) {
if(n > HEAPSIZE) {
printf("error: too many elements\n");
return;
}
if(A->size) {
printf("error: heap not empty\n");
return;
}
int nbytes = n * sizeof(int);
memcpy(A->element, a, nbytes);
A->size = n;
int i = 0;
for(i = A->size/2; i >= 0; i--) {
makeHeap(A, i);
}
}
You forgot that arrays are using index values starting from 0.
int pq_1_size = M / 2;
int pq_2_size = M - pq_1_size; << This is either M/2 or M/2+1
a = (int *)malloc(pq_1_size * sizeof(int));
b = (int *)malloc(pq_2_size * sizeof(int));
for (int i = 0; i < pq_1_size; i++) {
a[i] = i;
}
for (int j = pq_1_size; j < M; j++) {
b[j] = j; << j is in range M/2 .. M-1 but must be in range 0..M/2-1
This means you are writing out of bounds for the second array which causes undefined behaviour.
You must adjust the index accordingly:
for (int j = pq_1_size; j < M; j++) {
b[j-pq_1_size] = j;
or
for (int j = 0; j < pq_2_size; j++) {
b[j] = j+pq_1_size;
Regarding your questions:
Why the second heap is always 0?
That is just by accident. Memory allocated via malloc has no determined content. It can contain any values. You cannot rely on anything. As your loop does not touch the correct elements of that memory, you get these "random" values.
Why does it work if you use an initialized array?
If you use
int b[5] = { 5, 6, 7, 8, 9 };
you have an array that contains the provided values starting from index 0.
I'm working on this program for my University exam. I need to sort passenger array with a sorting algorithm (I choose bubblesort due to it's simplicity).
I need to create a generic function and pass as formal parameters:
-a list of objects i want to sort;
-a sort criterion.
So I think that I'll have to create only 1 Increasing sorting function and 1 decreasing sorting function and pass them the parameters to sort by.
I already tried to pass char *file_name to function, but I think that I'm wrong.
int passengersIncreasingBubbleSort_Birthyear(passengers test[], int x) {
int i = 0, j = 0, min_idx, flag = 0;
passengers temp;
for (i = 0; i < x; i++) {
min_idx = i;
for (j = i + 1; j < x; j++) {
if (test[j].birth_date.year < test[min_idx].birth_date.year) {
min_idx = j;
}
}
temp = test[min_idx];
test[min_idx] = test[i];
test[i] = temp;
flag = 1;
}
return flag;
}
I tried this:
int passengersIncreasingBubbleSort_Birthyear(passengers test[], int x, char *value1, char *value2) {
int i = 0, j = 0, min_idx, flag = 0;
passengers temp;
for (i = 0; i < x; i++) {
min_idx = i;
for (j = i + 1; j < x; j++) {
if (value1 < value2) {
min_idx = j;
}
}
temp = test[min_idx];
test[min_idx] = test[i];
test[i] = temp;
flag = 1;
}
return flag;
}
But it doesn't work as expected.
Ok, I achieved it.
int cmpfunction_Increasing_Birthdate (const void * a, const void * b)
{
passengers *passengerA = (passengers *)a;
passengers *passengerB = (passengers *)b;
return ( passengerA->signup_date.year - passengerB->signup_date.year );
}
and this is my call:
qsort(array, x, sizeof(passengers), cmpfunction_Increasing_Birthdate);
Now the question is, how can I also compare both year, month and day? Could I do it in the same compare function?
When I use mergeSort to sort my void** array (this array contains void* pointers that point to integers), an extra 1 (a new element) appears to be added to the array. I am nearly certain the issue is in mergeSort or merge, as when print my void** array before calling mergeSort, the data is correct (just unsorted). Here is the code.
#define SIZE 10
void mergeSort(void**, int, int);
void merge(void**, int, int, int);
int compare(void*, void*);
int main(void) {
int array[SIZE] = { 5, 6, 3, 2, 5, 6, 7, 4, 9, 3 };
void *voidArray[SIZE];
int query = 1;
void *queryPointer = &query;
for (int j = 0; j < SIZE; j++) {
voidArray[j] = &array[j];
}
printArray(voidArray);
mergeSort(voidArray, 0, SIZE);
printArray(voidArray);
result = binarySearch(voidArray, 0, SIZE, queryPointer);
if (result == -1) {
puts("Query not found.");
return(0);
}
printf("Query found at index %d.\n", result);
return(0);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void mergeSort(void **array, int head, int tail) {
if (head < tail) {
int middle = (head + ((tail - head) / 2));
mergeSort(array, head, middle);
mergeSort(array, (middle + 1), tail);
merge(array, head, middle, tail);
}
}
void merge(void **array, int head, int middle, int tail) {
int headLength = (middle - head + 1);
int tailLength = (tail - middle);
void *headSide[headLength];
void *tailSide[tailLength];
for (int i = 0; i < headLength; i++) {
headSide[i] = array[head + i];
}
for (int j = 0; j < tailLength; j++) {
tailSide[j] = array[middle + 1 + j];
}
int k = head;
int l = 0;
int m = 0;
while (l < headLength && m < tailLength) {
if (compare(headSide[l], tailSide[m]) == -1) {
array[k] = headSide[l];
l++;
} else {
array[k] = tailSide[m];
m++;
}
k++;
}
while (l < headLength) {
array[k] = headSide[l];
l++;
k++;
}
while (m < tailLength) {
array[k] = tailSide[m];
m++;
k++;
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int compare(void *index, void *query) {
if (*((int *)index) == *((int *)query)) {
return (0);
}
if (*((int*)index) > *((int*)query)) {
return (1);
}
return (-1);
}
The output should have the unsorted array, the sorted array, and whether the query was found. There is no 1 in the unsorted array, but then there is a 1 in the sorted array; also, the number 9 is missing from the sorted results (interestingly, if I perform a binary search for 9, it will tell me that 9 is found at index 10).
Example output (for a query of 1):
5 6 3 2 5 6 7 4 9 3
1 2 3 3 4 5 5 6 6 7
Query found at index 0.
Check your array subscript.
int tailLength = (tail - middle)
tail is the size of array,I think tailLength is incorrect.
headSide[i] = array[head + i];
headSide[i] is void and array[head + i] is void*
There is some confusion in the arguments to margeSort and merge. Passing the index of the last element in the range is not idiomatic in C. It is much simpler to pass the index of the element after the end of the range, which is consistent with passing 0 and SIZE int main(): mergeSort(voidArray, 0, SIZE); and result = binarySearch(voidArray, 0, SIZE, queryPointer);
Here is a modified version with this API:
void mergeSort(void **array, int head, int tail) {
if (tail - head > 1) {
int middle = head + (tail - head) / 2);
mergeSort(array, head, middle);
mergeSort(array, middle, tail);
merge(array, head, middle, tail);
}
}
void merge(void **array, int head, int middle, int tail) {
int headLength = middle - head;
int tailLength = tail - middle;
void *headSide[headLength];
void *tailSide[tailLength];
for (int i = 0; i < headLength; i++) {
headSide[i] = array[head + i];
}
for (int j = 0; j < tailLength; j++) {
tailSide[j] = array[middle + j];
}
int k = head;
int l = 0;
int m = 0;
while (l < headLength && m < tailLength) {
if (compare(headSide[l], tailSide[m]) <= 0) {
array[k++] = headSide[l++];
} else {
array[k++] = tailSide[m++];
}
}
while (l < headLength) {
array[k++] = headSide[l++];
}
while (m < tailLength) {
array[k++] = tailSide[m++];
}
}
Note however that allocating the temporary arrays headSide and tailSide with automatic storage (aka on the stack) is risky for large arrays. Furthermore, it is not necessary to save the elements from the right half into tailSide as they will not be overwritten before they are copied to the final position. Here is a simpler version of merge:
void merge(void **array, int head, int middle, int tail) {
int headLength = middle - head;
void *headSide[headLength];
for (int i = 0; i < headLength; i++) {
headSide[i] = array[head + i];
}
int k = head;
int l = 0;
while (l < headLength && middle < tail) {
if (compare(headSide[l], array[middle]) <= 0) {
array[k++] = headSide[l++];
} else {
array[k++] = array[middle++];
}
}
while (l < headLength) {
array[k++] = headSide[l++];
}
}
I was trying to solve Project Euler question 16 using c. I did not use bignnum libraries. The question asks 2^1000. I decided to store every digit of that number in an array.
For Example: 45 means arr[0]=4, arr[1]=5;
The problem is definitely i the function int multi.
#include<stdio.h>
#include<conio.h>
int multi(int *base, int k);// does the multiplication of array term by 2
void switcher();//switches every term when the fore mostvalue is >10
int finder();// finds the array address of last value
int arr[1000];
int summer();//sums all values of the array
int main()
{
arr[1000] = { 0 };
arr[0] = 1;
int i, j, sum, k, p;
for (i = 0; i < 1000; i++)
{
j = 0;
k = finder();
p = multi(arr + k, j);
}
sum = summer();
printf("sum of digits of 2^1000 is %d", sum);
_getch();
}
int multi(int *base, int k)
{
int p;
if (base == arr)
{
*base = *base - 1;
*base = *base + k;
if (*base > 10)
{
*base = *base - 10;
switcher();
}
return 0;
}
*base = *base * 2;
*base = *base + k;
if (*base > 10)
{
*base = *base - 10;
p = multi(base - 1, 1);
}
else
{
p = multi(base - 1, 0);
}
}
void switcher()
{
int j;
for (j = 0;; j++)
{
if (arr[j] == 0)
{
break;
}
}
j--;
for (; j > 0; j--)
{
arr[j + 1] = arr[j];
}
arr[0] = 1;
}
int finder()
{
int j;
for (j = 0;; j++)
{
if (arr[j] == 0)
{
break;
}
}
return --j;
}
int summer()
{
int summ, i;
summ = 0;
for (i = 0; i<1000; i++)
{
summ = summ + arr[i];
if (arr[i] == 0)
break;
}
return summ;
}
It compiles but during runtime it shows Access Write Violation, base was ......
Please explain this error and how to resolve it ?
Array is of 100 Bytes but you are looping for 1000. Also in function Finder() , you do not have a limit on variable j so your array size is going beyond 100 bytes.
Also use memset to assign array variables to 0.
As said in the comments, 2^1000 has 302 decimal digits.
You're going far outside your array.
But your code is very complicated because you store the digits with the most significant one first.
Since you're only interested in the digits and not the order in which they would be written, you can store the number "in reverse", with the least significant digit first.
This makes the code much simpler, as you can loop "forwards" and no longer need to shuffle array elements around.
Using -1 as "end of number" marker, it might look like this:
void twice(int* digits)
{
int i = 0;
int carry = 0;
while (digits[i] >= 0)
{
digits[i] *= 2;
digits[i] += carry;
if (digits[i] >= 10)
{
carry = 1;
digits[i] -= 10;
}
else
{
carry = 0;
}
i++;
}
if (carry)
{
digits[i] = 1;
digits[i+1] = -1;
}
}
int main()
{
int digits[302] = {1, -1}; /* Start with 1 */
twice(digits); /* digits is now { 2, -1 } */
return 0;
}