Number of Comparisons for Heap Sort - c

I wrote some C code to analyze the number of comparisons and runtime of building a heap and running heapsort. However, I'm not sure if the output of my code makes sense. Heapsort should perform at O(n log n), but the number of comparisons I'm seeing doesn't seem to be very close to that. For example, for an input of size n = 100, I'm seeing ~200 comparisons to build the heap and ~800 comparisons in heap sort. Am I just analyzing the data wrong, or is there something wrong with the way I'm collecting comparisons in my code?
I can provide a link to github if it would make a difference for anyone.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
void bottom_up_heap_sort(int*, int);
void heap_sort(int*, int);
void sift_up(int*, int);
void sift_down(int*, int);
void build_max_heap(int*, int);
void bottom_up_build_max_heap(int*, int);
void randomize_in_place(int*, int);
int* generate_array(int);
void swap(int*, int*);
int cmp(int, int);
void print_array(int*, int);
int heapsize;
unsigned long comparison_counter;
clock_t begin, end;
double time_spent;
int main() {
int k, N;
int* A;
int* B;
int i;
printf("Testing Sift_Down Heap Sort\n");
for(k = 2; k <= 5; k++) {
comparison_counter = 0;
N = (int)pow((double)10, k);
begin = clock();
A = generate_array(N);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Time Spent Generating Array: %f\n", time_spent);
// print the first unsorted array
//printf("Unsorted Array:\n");
//print_array(A, N);
begin = clock();
// call heap_sort on the first unsorted array
heap_sort(A, N);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
// show that the array is now sorted
//printf("Sorted array: \n");
//print_array(A, N);
printf("Done with k = %d\n", k);
printf("Comparisons for Heap Sort: %lu\n", comparison_counter);
printf("Time Spent on Heap Sort: %f\n", time_spent);
printf("\n");
}
printf("----------------------------------\n");
printf("Testing Sift_Up Heap Sort\n");
for(k = 2; k <= 5; k++) {
comparison_counter = 0;
N = (int)pow((double)10, k);
begin = clock();
B = generate_array(N);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Time Spent Generating Array: %f\n", time_spent);
// print the unsorted array
//printf("Unsorted Array:\n");
//print_array(B, N);
begin = clock();
// call heap_sort on the unsorted array
bottom_up_heap_sort(B, N);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
// show that the array is now sorted
//printf("Sorted array: \n");
//print_array(B, N);
printf("Done with k = %d\n", k);
printf("Comparisons for Heap Sort: %lu\n", comparison_counter);
printf("Time Spent on Heap Sort: %f\n", time_spent);
printf("\n");
}
printf("----------------------------------\n");
return 0;
}
void bottom_up_heap_sort(int* arr, int len) {
int i;
// build a max heap from the bottom up using sift up
bottom_up_build_max_heap(arr, len);
printf("Comparisons for heap construction: %lu\n", comparison_counter);
comparison_counter = 0;
for(i = len-1; i >= 0; i--) {
// swap the last leaf and the root
swap(&arr[i], &arr[0]);
// remove the already sorted values
len--;
// repair the heap
bottom_up_build_max_heap(arr, len);
}
}
void heap_sort(int* arr, int len) {
int i;
// build a max heap from the array
build_max_heap(arr, len);
printf("Comparisons for heap construction: %lu\n", comparison_counter);
comparison_counter = 0;
for(i = len-1; i >= 1; i--) {
swap(&arr[0], &arr[i]); // move arr[0] to its sorted place
// remove the already sorted values
heapsize--;
sift_down(arr, 0); // repair the heap
}
}
void sift_down(int* arr, int i) {
int c = 2*i+1;
int largest;
if(c >= heapsize) return;
// locate largest child of i
if((c+1 < heapsize) && cmp(arr[c+1], arr[c]) > 0) {
c++;
}
// if child is larger than i, swap them
if(cmp(arr[c], arr[i]) > 0) {
swap(&arr[c], &arr[i]);
sift_down(arr, c);
}
}
void sift_up(int* arr, int i) {
if(i == 0) return; // at the root
// if the current node is larger than its parent, swap them
if(cmp(arr[i], arr[(i-1)/2]) > 0) {
swap(&arr[i], &arr[(i-1)/2]);
// sift up to repair the heap
sift_up(arr, (i-1)/2);
}
}
void bottom_up_build_max_heap(int* arr, int len) {
int i;
for(i = 0; i < len; i++) {
sift_up(arr, i);
}
}
void build_max_heap(int* arr, int len) {
heapsize = len;
int i;
for(i = len/2; i >= 0; i--) {
// invariant: arr[k], i < k <= n are roots of proper heaps
sift_down(arr, i);
}
}
void randomize_in_place(int* arr, int n) {
int j, k;
double val;
time_t t;
// init the random number generator
srand((unsigned)time(&t));
// randomization code from class notes
for(j = 0; j < n-1; j++) {
val = ((double)random()) / 0x7FFFFFFF;
k = j + val*(n-j);
swap(&arr[k], &arr[j]);
}
}
// this function is responsible for creating and populating an array
// of size k, and randomizing the locations of its elements
int* generate_array(int k) {
int* arr = (int*) malloc(sizeof(int)*k-1);
int i, j, x, N;
double val;
time_t t;
// init the random number generator
srand((unsigned)time(&t));
// fill the array with values from 1..N
for(i = 0; i <= k-1; i++) {
arr[i] = i+1;
}
N = (int)pow((double)10, 5);
// randomize the elements of the array for 10^5 iterations
for(i = 0; i < N; i++) {
randomize_in_place(arr, k);
}
return arr;
}
// swap two elements
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int cmp(int a, int b) {
comparison_counter++;
if(a > b) return 1;
else if(a < b) return -1;
else return 0;
}
// print out an array by iterating through
void print_array(int* arr, int size) {
int i;
for(i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
}

O(n log n) (or in general O(f(x))) does not give you any idea about the expected value at a single point.
That's because big-O notation ignores constant factors. In other words, all of n * log(n), 0.000001 * n * log(n) and 1000000 * n * log(n) are in O(n log n). So the result for a particular value of n is completely undetermined.
What you can deduce from big-O notation is the effect of modify the control variable. If a function involves O(n) operations, then it is expected that doubling n will double the number of operations. If a function involves O(n2) operations, then it is expected that doubling n will quadruple the number of operations. And so on.

The actual number for such small values of n doesn't really matter, as the constant factors are omitted in the complexity. What matters is the growth of your algorithm, measuring for increasingly larger values of n, and plotting them should give roughly the same graph as your theoretical complexity.
I tried your code for a couple of n, and the increase in complexity was approximately O(n logn )

Related

mergeSort algorithm with fewer global variables

I wrote a program that implements the mergeSort algorithm, which sorts across multiple threads.
The algorithm is able to spread the sorted vector over several threads
The program contains mutexes to protect global counters that are incremented by each thread.
I would like you to help me modify the program so that I do not use so many global variables. I also think that the program is making too many copies and that problems may occur
#include <stdio.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
pthread_mutex_t mutex_p = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_pi = PTHREAD_MUTEX_INITIALIZER;
int MAX; // number of elements in the array
int THREAD_MAX; // number of threads
int idx[20]; // hold the right end at each vector subdivision
int p_i = 0;
int *a;
int part = 0;
// mergeSort function to interclass two parts
void merge(int l1, int h1, int h2)
{
int count = h2 - l1 + 1;
int sorted[count];
int i = l1, k = h1 + 1, m = 0;
while (i <= h1 && k <= h2)
{
if (a[i] < a[k])
sorted[m++] = a[i++];
else if (a[k] < a[i])
sorted[m++] = a[k++];
else if (a[i] == a[k])
{
sorted[m++] = a[i++];
sorted[m++] = a[k++];
}
}
while (i <= h1)
sorted[m++] = a[i++];
while (k <= h2)
sorted[m++] = a[k++];
for (i = 0; i < count; i++, l1++)
a[l1] = sorted[i];
}
// mergeSort function
void merge_sort(int low, int high)
{
// calculates the middle of the array
int mid = low + (high - low) / 2;
if (low < high)
{
// I call the first half
merge_sort(low, mid);
// I call the second half
merge_sort(mid + 1, high);
// interclassification between the two halves
merge(low, mid, high);
}
}
// thread function for multi-threading
void *mergeSort(void *arg)
{
pthread_mutex_lock(&mutex_p);
int thread_part = part++;
pthread_mutex_unlock(&mutex_p);
// calculate the minimum and maximum
int low = thread_part * (MAX / THREAD_MAX);
int high = (thread_part + 1) * (MAX / THREAD_MAX) - 1;
// allocate the rest of the original array to the last thread
if (thread_part == THREAD_MAX - 1)
{
high = MAX - 1;
}
// stores the right edge for each split array
pthread_mutex_lock(&mutex_pi);
idx[++p_i] = high;
pthread_mutex_unlock(&mutex_pi);
// calculate the midpoint
int mid = low + (high - low) / 2;
merge_sort(low, mid);
merge_sort(mid + 1, high);
merge(low, mid, high);
return NULL;
}
void isSorted(int len)
{
if (len == 1)
{
printf("Sorting completed\n");
return;
}
int i;
for (i = 1; i < len; i++)
{
if (a[i] < a[i - 1])
{
printf("Sorting is not complete\n");
return;
}
}
printf("Sorting completed\n");
return;
}
// The main program
int main()
{
printf("Enter the number of items in the array:");
scanf("%d", &MAX);
printf("Enter the number of threads you want:");
scanf("%d", &THREAD_MAX);
// generates random number in array up to 1000
a = malloc(MAX * sizeof(int));
srand(time(NULL));
for (int i = 0; i < MAX; i++)
{
a[i] = rand() % 1000;
}
// t1 and t2 to calculate the time to mergeSort
clock_t t1 = clock();
pthread_t threads[THREAD_MAX];
// thread creation
for (int i = 0; i < THREAD_MAX; i++)
{
pthread_create(&threads[i], NULL, mergeSort, (void *)NULL);
}
// joining all threads
for (int i = 0; i < THREAD_MAX; i++)
{
pthread_join(threads[i], NULL);
}
// merging on the last elements
int p = 1;
int mid, high;
for (int q = 1; q < THREAD_MAX; q++)
{
mid = idx[p];
p++;
high = idx[p];
merge(0, mid, high);
}
clock_t t2 = clock();
printf("Time required: %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
isSorted(MAX);
//sorted array display
printf("Sorted array: ");
for (int i = 0; i < MAX; i++)
printf("%d ", a[i]);
printf("\n");
free(a);
return 0;
}
The key to remove global variable is to locally pass data from functions to functions. First of all, pthread_create have a parameter called arg which enable you to pass a structure with many fields in argument to the created thread. The idea is to declare a structure like this:
// TODO: check all the fields are actually needed
struct ThreadContext
{
pthread_mutex_t mutex_p;
pthread_mutex_t mutex_pi;
int MAX; // number of elements in the array
int THREAD_MAX; // number of threads
int idx[20]; // hold the right end at each vector subdivision
int p_i = 0;
int *a;
int part = 0;
};
Then create it on the stack, then fill it (typically the mutex fields), before creating threads, and finally pass it to the threads using:
// &your_struct is a pointer to your_struct
pthread_create(&threads[i], NULL, mergeSort, (void*)&your_struct);
Your mergeSort function can then extract the data structure from the void* pointer.
void* mergeSort(void* arg)
{
struct ThreadContext* context = (struct ThreadContext*)arg;
pthread_mutex_lock(&context.mutex_p); // Example of usage
// [...]
}
You can also add new parameters to the merge and merge_sort functions if needed.
Note that int idx[20]; can be replaced by int* idx and allocated dynamically (using malloc and free) so not to have a predetermined limit to the number of threads that can be used in your program.
I am surprised to see mutexes in a merge sort. Indeed, the idea of a parallel merge sort is to split the work between thread so each work on different data. As a result, there is no need for critical sections. You can use the thread ID to select with thread do the merge instead of preventing other threads to do operations with critical sections.
Note that you can create an array of ThreadContext and fill it with different data so each thread have different information (filled by the main thread). For example, the thread ID can be different as well as the start/stop indices. This help you not to use any mutexes in your code. To avoid the replication of some fields in each thread you can even split the structure into 3 different structures:
struct SharedContext
{
// Shared fields like the number of threads, the array pointer, the total number of element, mutexes (if any), etc.
};
struct PrivateContext
{
// Thread private fields like the thread ID, the start/stop indices, etc.
};
struct ThreadContext
{
struct SharedContext* sharedCtx;
struct PrivateContext privateCtx;
};
Note that sharedCtx should be filled with the pointer to a SharedContext structure created by the main thread (eg. allocated on the stack).
You can remove the global variables by passing the appropriate arguments to each thread.
For this, you can define an array of structures, one for each thread, populate it with arguments before launching the thread and pass the structure pointer to pthread_create.
With each thread acting on its own data, you no longer need the global variables, nor even the mutexes.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
struct thread_data {
int *a;
int low;
int high;
};
// mergeSort function to interclass two parts
void merge(int *a, int lo, int mid, int hi) {
int count = hi - lo;
int sorted[count];
int i = lo, k = mid, m = 0;
while (i < mid && k < hi) {
if (a[i] <= a[k])
sorted[m++] = a[i++];
else
sorted[m++] = a[k++];
}
while (i < mid)
sorted[m++] = a[i++];
for (i = 0; i < m; i++)
a[lo + i] = sorted[i];
}
// mergeSort function
void merge_sort(int *a, int low, int high) {
// calculates the middle of the array
int mid = low + (high - low) / 2;
if (high - low > 1) {
// I call the first half
merge_sort(a, low, mid);
// I call the second half
merge_sort(a, mid, high);
// interclassification between the two halves
merge(a, low, mid, high);
}
}
// thread function for multi-threading
void *mergeSort(void *arg) {
struct thread_data *data = arg;
merge_sort(data->a, data->low, data->high);
return NULL;
}
void isSorted(const int *a, int len) {
for (int i = 1; i < len; i++) {
if (a[i] < a[i - 1]) {
printf("Sorting is not complete\n");
return;
}
}
printf("Sorting completed\n");
}
void printArray(const int *a, int len) {
for (int i = 0; i < len; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
// The main program
int main() {
int *a; // array pointer
int MAX; // number of elements in the array
int THREAD_MAX; // number of threads
printf("Enter the number of items in the array:");
if (scanf("%d", &MAX) != 1)
return 1;
printf("Enter the number of threads you want:");
if (scanf("%d", &THREAD_MAX) != 1)
return 1;
// generates random number in array up to 1000
a = malloc(MAX * sizeof(int));
srand(time(NULL));
for (int i = 0; i < MAX; i++) {
a[i] = rand() % 1000;
}
// t1 and t2 to calculate the time to mergeSort
clock_t t1 = clock();
// thread creation
pthread_t threads[THREAD_MAX];
struct thread_data data[THREAD_MAX];
for (int i = 0; i < THREAD_MAX; i++) {
data[i].a = a;
data[i].low = i * MAX / THREAD_MAX;
data[i].high = (i + 1) * MAX / THREAD_MAX;
pthread_create(&threads[i], NULL, mergeSort, &data[i]);
}
// joining all threads
for (int i = 0; i < THREAD_MAX; i++) {
pthread_join(threads[i], NULL);
}
// merging on the last elements
// this merge phase is inefficient
for (int i = 1; i < THREAD_MAX; i++) {
int mid = data[i].low;
int high = data[i].high;
merge(a, 0, mid, high);
}
clock_t t2 = clock();
printf("Time required: %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
isSorted(a, MAX);
//sorted array display
if (MAX < 100) {
printf("Sorted array: ");
printArray(a, MAX);
}
free(a);
return 0;
}

Segmentation fault: 11 on mac but not on linux while creating an array in C

Hello I've recently started testing out QuickSort. I've written a program that makes array with the size of user's input and fills it with random numbers, then it uses quicksort to sort it. Now here is my problem. On linux machine with just 4gb of RAM I could make array with a size up to 10^8 before computer would become unusable. On my mac with 8gb of RAM I can only make an array with a size up to 10^6. If I try making an array with size of 10^7 and greater I get segmentation fault. Is it some hard restriction from operating system, can it be changed?
Here is my code :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int FindPivot(int i, int j);
void PrintTable(int* table, int size);
void NextThing(int* table, int size);
void QuickSort(int* table, int i, int j);
void RandomizeTable (int* table, int size) {
int i;
for (i = 0; i < size; i++) {
table[i] = -10000 + rand() % (10000+1-(-10000));
//printf("%d\t", table[i]);
}
printf("\n");
NextThing(table, size);
}
void NextThing(int* table, int size) {
printf("Sorting the table...\n");
clock_t x = clock();
QuickSort(table, 0, size - 1);
clock_t y= clock();
printf("Time it took : %fs\n", ((double)(y - x))/CLOCKS_PER_SEC);
//Second sorting of the table, just to see how long does it take for quicksort to sort an already sorted table
printf("Sorting the table...\n");
clock_t x2 = clock();
QuickSort(table, 0, size - 1);
clock_t y2= clock();
printf("Time it took : %fs\n", ((double)(y2 - x2))/CLOCKS_PER_SEC);
exit(0);
}
void Swap(int* table, int i, int j) {
int temp;
temp = table[i];
table[i] = table[j];
table[j] = temp;
}
int Partition(int* table, int i, int j) {
int p, q, key;
p = FindPivot(i, j);
key = table[p];
Swap(table, i, p);
for (p = i, q = i + 1; q <= j; q++)
if (table[q] < key) {
p++;
Swap(table, p, q);
}
Swap(table, i, p);
return p;
}
void QuickSort(int* table, int i, int j) {
int p;
if (i < j) {
p = Partition(table, i, j);
QuickSort(table, i, p - 1);
QuickSort(table, p + 1, j);
}
}//QuickSort
void PrintTable(int* table, int size) {
int i;
for (i = 0; i < size; i++)
printf("%d", table[i]);
printf("\n");
}
int FindPivot(int i, int j) {
int pivot;
/*pivot = i + rand() % (j + 1 - i); */ //Method I randomizing pivot
pivot = (i + j) / 2; //Method II arithmetic avarage
return pivot;
}
int main () {
time_t t;
srand((unsigned) time(&t));
int n;
printf("Array size:");
scanf("%d", &n);
int tab[n]; //Here is where error occurs if array size is > 10^6
RandomizeTable(tab, n);
}
I am almost sure it's problem with making an array of such size. I've tried debugging the code with a printf. It printed text if it was before making an array (in main()) and wouldn't print it if I put it afterwards.
Assuming you're using C99,it may be implementation specific (but probably not), where the maximum size of any object is limited by SIZE_MAX, from this post, which means the minimum (in theory) could be less than 10^6 (1,000,000) bytes.
If this is the issue, you can check with something like
size_t max_size = (size_t)-1;
From here.
Otherwise, the other post is your best bet - if you can't implement it on the stack, using malloc can allocate it in the heap.
int *tab = malloc(n*sizeof(int));
This will allocate the (n * sizeof(int in bytes)) bytes in the heap, and should work.
Note that if you allocate memory this way, it'll need to be manually deleted, so you should call free on it when you're done.
free(tab)

Need to implement a recursive mergesort code in C using array pointer, its length and a workspace array for the merge function

I need to implement mergesort for arrays up to 100000 integers but the specifications are a bit troublesome: I need to use a pointer to an integer array, its length and an extra workspace array for merging,
The mergesort function should look something like this:
void merge_sort(int *a, int *w, int n)
where a is to be sorted and w is the workspace used for merging, cant use an array and two indexes between what I wanna sort
pseudocode:
merge_sort(int *a, int *w, int n) {
/* take care of stopping condition first */
if the array to be sorted has fewer than two elements then
return
merge_sort( first half of array a);
merge_sort( second half of array a);
merge the two halves of array a into array w
copy array w back into array a
}
merge(int *array, int *workspace, int len) {
initialise indices to point to the beginning of
the left and right halves of array
while there are elements in both halves of array {
compare the elements at the current left and right indices
put the smallest into workspace and increment both the index
it was taken from, and the index in workspace
}
add any remaining elements from left half of array to workspace
add any remaining elements from right half of array to workspace
}
Here is what I got so far:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ARRAY_MAX 100000
void merge_sort(int *a, int *w, int n) {
if (n == 1)
return;
else {
int *temp;
merge_sort(a, w, n / 2);
merge_sort(a + (n / 2), w, (n - (n / 2)));
/** Cannot figure what to pass to merge since it has to be the two halves
and how to copy contents of a to w **/
}
}
void merge(int *a, int *w, int n) {
/** Cannot figure this out **/
}
int main(void) {
int my_array[ARRAY_MAX];
int work_space[ARRAY_MAX];
int count = 0;
int i;
while (count < ARRAY_MAX && 1 == scanf("%d", &my_array[count])) {
count += 1;
}
start = clock();
merge_sort(my_array, workspace, count);
end = clock();
merge_sort(my_array, work_space, count);
for (i = 0; i < count; i++) {
printf("%d\n", my_array[i]);
}
fprintf(stderr, "%d %f \n", count, (end - start) / (double)CLOCKS_PER_SEC);
return EXIT_SUCCESS;
}
The merging phase in function merge_sort iterates on both halves in parallel, taking the smallest element from either side at a time:
void merge_sort(int *a, int *w, int n) {
if (n < 2) {
return;
} else {
int i, j, k;
int n1 = n / 2;
int *b = a + n1;
int n2 = n - n1;
/* sort the left half */
merge_sort(a, w, n1);
/* sort the right half */
merge_sort(b, w, n2);
/* merge the halves into w */
for (i = j = k = 0; i < n1 && j < n2;) {
if (a[i] <= b[j]) {
/* get smallest value from a */
w[k++] = a[i++];
} else {
/* get smallest value from b */
w[k++] = b[j++];
}
}
/* copy remaining elements from a */
while (i < n1) {
w[k++] = a[i++];
}
/* copy remaining elements from b */
while (j < n2) {
w[k++] = b[j++];
}
/* copy sorted elements back to a */
for (i = 0; i < n; i++) {
a[i] = w[i];
}
}
}
The rest of the code has a few issues too:
2 arrays of 100000 ints might exceed the space available for automatic variables.
you sort the array twice
start and end are not defined
Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ARRAY_MAX 100000
int main(void) {
int my_array[ARRAY_MAX];
int work_space[ARRAY_MAX];
int i, count;
clock_t start, end;
count = 0;
while (count < ARRAY_MAX && scanf("%d", &my_array[count]) == 1) {
count += 1;
}
start = clock();
merge_sort(my_array, workspace, count);
end = clock();
for (i = 0; i < count; i++) {
printf("%d\n", my_array[i]);
}
fprintf(stderr,"%d %f\n", count, (end - start) / (double)CLOCKS_PER_SEC);
return EXIT_SUCCESS;
}
Remember that in C, when you send an array as an argument to a function, what is really sent is a pointer to the first element. Then you can use that pointer inside the function in a way very similar to an array. So if you are confused about the ”pointers” in the description of (I assume) your homework, perhaps that is the reason?

Linear Search using functions and dynamic memory allocation in C

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define LIMIT 30000
void CreateArray(int *p, int N) {
int i;
p = (int *)malloc(N * sizeof(int));
srand((long)210);
for (i = 0; i < N; i++)
*(p + i) = rand() % LIMIT;
for (i = 0; i < N; i++)
printf("%d ", p[i]);
}
void Search(int *p, int N, int key) {
int comparisons = 0, success_search = 0;
int i;
clock_t start, end;
double elapsed;
start = clock();
for (i = 0; i < N; i++) {
if (key == p[i]) {
comparisons++;
success_search++;
printf("\nFound!");
break;
} else {
comparisons++;
printf("\nNot found!");
}
}
end = clock();
elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("\nTotal comparisons: %d \n", comparisons);
printf("Time elapsed: %f \n", elapsed);
printf("Successful comparisons: %d \n\n", success_search);
}
int main() {
int N, i, p, key;
key = 1;
CreateArray(&p, N = 7);
Search(&p, N, key);
}
I'm trying to create a pseudo-random array and then try to search for a specific number in it and keep track of the total comparisons made and the total time needed to complete the search. I have manually inserted a number that is not in the array and it keeps saying that the number was found after 3 comparisons. Also the time elapsed always appears to be zero. I can't figure out what's wrong.
Make the following changes.
1) You need to allocate array and pass it to different functions. So "n" should be a pointer.
int *n = NULL;
2) You want CreateArray() to allocate memory and pass the pointer.
void CreateArray (int **p, int N)
3) You have to pass pointer to Search(). So call from main() becomes
Search(p, N, key);
I think it should work fine as expected now.
For time elapsed, you refer to Weather Vane's comment in your question.
There are multiple problems in your code:
CreateArray should return the pointer to the allocated space. Passing it a pointer to a local int in main() makes no sense.
you should test for malloc potential failure.
Search should get the pointer to the allocated array, not the address of a local int.
Search should print the Not found message just once at the end of the scan phase.
If you want to count the number of successful comparisons, you should not break from the loop when you find the first one, but then the total number of comparisons is N.
for better timing accuracy, you should avoid using printf inside the timed fragment.
you should free the memory before exiting the program.
Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LIMIT 30000
void CreateArray(int N) {
int i;
int *p = (int *)malloc(N * sizeof(int));
if (p != NULL) {
srand((long)210);
for (i = 0; i < N; i++)
*(p + i) = rand() % LIMIT;
for (i = 0; i < N; i++)
printf("%d ", p[i]);
}
return p;
}
void Search(int *p, int N, int key) {
int comparisons = 0, success_search = 0;
int i;
clock_t start, end;
double elapsed;
start = clock();
for (i = 0; i < N; i++) {
comparisons++;
if (key == p[i])
success_search++;
}
end = clock();
elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
if (success_search)
printf("Found!\n");
else
printf("Not found!\n");
printf("Total comparisons: %d\n", comparisons);
printf("Successful comparisons: %d\n\n", success_search);
printf("Time elapsed: %f\n", elapsed);
}
int main() {
int N, i, key;
int *p;
key = 1;
N = 7;
p = CreateArray(N);
if (p == NULL) {
fprintf(stderr, "cannot allocate memory for %d elements\n", N);
return 1;
}
Search(p, N, key);
free(p);
return 0;
}

printing time taken for merge sort

i'm tryin' to print the time taken for a merge sort on an array of random numbers generated by the computer, whose size should be taken from the user during runtime, but it's givin' a segmentation fault. can anyone help correct my mistake?
part(int arr[],int min,int max)
{
int mid;
if(min<max)
{
mid=(min+max)/2;
part(arr,min,mid);
part(arr,mid+1,max);
merge(arr,min,mid,max);
}
}
merge(int arr[],int min,int mid,int max)
{
int tmp[30];
int i,j,k,m;
j=min;
m=mid+1;
for(i=min; j<=mid && m<=max ; i++)
{
if(arr[j]<=arr[m])
{
tmp[i]=arr[j];
j++;
}
else
{
tmp[i]=arr[m];
m++;
}
}
if(j>mid)
{
for(k=m; k<=max; k++)
{
tmp[i]=arr[k];
i++;
}
}
else
{
for(k=j; k<=mid; k++)
{
tmp[i]=arr[k];
i++;
}
}
for(k=min; k<=max; k++)
arr[k]=tmp[k];
}
main(){
int x, *b, i;
double t5;
printf("array size = \t");
scanf("%d", &x);
b = (int)malloc(x*sizeof(int));
srand(time(NULL));
for(i = 0; i<x; i++) b[i] = rand();
time_t t1 = 0;
time_t t2 = 0;
t1 = time(NULL);
part(b, 0, (x-1));
t2 = time(NULL);
printf("time taken for merge sort = %f sec\n", (t1 - t2));
}
There are several issues with the code here:
All relevant prototypes to system functions are missing, Fix this by including the necessary headers.
The prototype for merge() is missing, as needed by part(). Add it.
Functions not returning anything shall be typed as void. Declare them alike.
There is no need to cast the result of malloc(). And if it is done it should be done to the correct type: int * here not int!
time_t is an integer in most of the cases, so if it is don't use the conversion specifier for double when trying to print time_t, but the correct integer conversion specifier that is d for 32bit wide time_t or ld for 64bit wide time_t. However to print difference of time_ts use difftime(), which actually results in a double.
Last not least the temporary buffer in merge() doesn't scale. Make it max+1 elements wide.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void merge(int arr[], int min, int mid, int max);
void part(int arr[], int min, int max);
void part(int arr[], int min, int max)
{
int mid;
if (min < max)
{
mid = (min + max) / 2;
part(arr, min, mid);
part(arr, mid + 1, max);
merge(arr, min, mid, max);
}
}
void merge(int arr[], int min, int mid, int max)
{
int tmp[max + 1];
int i, j, k, m;
j = min;
m = mid + 1;
for (i = min; j <= mid && m <= max; i++)
{
if (arr[j] <= arr[m])
{
tmp[i] = arr[j];
j++;
}
else
{
tmp[i] = arr[m];
m++;
}
}
if (j > mid)
{
for (k = m; k <= max; k++)
{
tmp[i] = arr[k];
i++;
}
}
else
{
for (k = j; k <= mid; k++)
{
tmp[i] = arr[k];
i++;
}
}
for (k = min; k <= max; k++)
arr[k] = tmp[k];
}
int main(void)
{
int x, *b, i;
printf("array size = \t");
scanf("%d", &x);
b = malloc(x * sizeof(int));
srand(time(NULL ));
for (i = 0; i < x; i++)
b[i] = rand();
time_t t1 = 0;
time_t t2 = 0;
t1 = time(NULL);
part(b, 0, x - 1);
t2 = time(NULL);
printf("time taken for merge sort = %f sec\n", difftime(t2, t1));
}
time uses a type called time_t. To use it to find an elapsed time in seconds you must do something like this:
time_t time1, time2;
double seconds;
time(&time1);
...
time(&time2);
seconds = difftime(time2, time1);
Also, remove the cast from malloc. malloc returns a void pointer which is implicitly cast to an int pointer for you:
b = malloc(x * sizeof(*b));

Resources