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));
Related
I'm really new to this. I've never done anything like this so I'm having issues with this code. I was given a template to write my code in separate functions like this, although I added the findPos one myself. I'm getting the "assignment makes integer from pointer without a cast" warning and also my max, min, sum, avg, and position of max and min are obviously not coming out to the right numbers. I was just wondering if anyone can lead me in the right direction.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int findMin(int arr[], int size);
int findMax(int arr[], int size);
int findSum(int arr[], int size);
int findPos(int arr[], int size);
int size;
int i;
int max;
int min;
int avg;
int sum;
int pos;
int main()
{
srand(time(0));
printf("Enter an integer: ");
scanf("%d", &size);
int arr[size];
max = findMax;
min = findMin;
pos = findPos;
sum = findSum;
avg = sum / size;
printf("max:%7d\tpos:%d\t\n", max, pos);
printf("min:%7d\tpos:%d\t\n", min, pos);
printf("avg:%7d\n", avg);
printf("sum:%7d\n", sum);
printf("\n");
printf(" Pos : Val\n");
printf("-------------\n");
for (i = 0; i < size; i++) {
arr[i] = (rand() % 1001);
printf("%4d :%6d\n", i, arr[i]);
}
return 0;
}
int findMin(int arr[], int size)
{
min = arr[0];
for (i = 0; i < size; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
return min;
}
int findMax(int arr[], int size)
{
max = arr[0];
for (i = 0; i < size; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
int findSum(int arr[], int size)
{
sum = 0;
for (i = 0; i < size; i++) {
sum = sum + arr[i];
}
return sum;
}
int findPos(int arr[], int size)
{
for (i = 0; i < size; i++) {
pos = i;
}
return pos;
}
max = findMax;
min = findMin;
pos = findPos;
sum = findSum;
You're assigning function pointer, not return value, to integer variable. You have to do something like max = findMax(arr, size). Also in that case, you should assign values to arr before calling it.
There are a couple of issues with the code. Let me iterate through the same
Populating Data in Created Array
Since the data has to present the created array before performing any operations,
printf("\n");
printf(" Pos : Val\n");
printf("-------------\n");
for (i = 0; i < size; i++) {
arr[i] = (rand() % 1001);
printf("%4d :%6d\n", i, arr[i]);
}
this snippet should be reordered and moved above the function calls and just after the int arr[size];
Function Calls
All your functions, namely findMax,findMin,findPos,findSum is expecting two parameters
arr - array you have created
size - the size value read from scanf()
Assuming you want to store the return value from the function in the main int variables max,min,pos,sum,avg
the statements
max = findMax;
min = findMin;
pos = findPos;
sum = findSum;
should be replaced with function calls like
max = findMax(arr, size);
min = findMin(arr, size);
pos = findPos(arr, size);
sum = findSum(arr, size);
The Final Main code will be
int main()
{
srand(time(0));
printf("Enter an integer: ");
scanf("%d", &size);
int arr[size];
printf("\n");
printf(" Pos : Val\n");
printf("-------------\n");
for (i = 0; i < size; i++) {
arr[i] = (rand() % 1001);
printf("%4d :%6d\n", i, arr[i]);
}
max = findMax(arr, size);
min = findMin(arr, size);
pos = findPos(arr, size);
sum = findSum(arr, size);
avg = sum / size;
printf("max:%7d\tpos:%d\t\n", max, pos);
printf("min:%7d\tpos:%d\t\n", min, pos);
printf("avg:%7d\n", avg);
printf("sum:%7d\n", sum);
return 0;
}
So I have been tasked from school with writing a function that gets an int size parameter, an array of integers and an int flag, and returns an array of pointers, that holds pointers to the cells of the original int array in a sorted manner (ascending if flag==1, else descending).
I wrote it basically on the principle of merge sort, but for some reason I am getting a runtime error that occurs when the program tries to execute line 123 (free a temp int** array)
any idea why it happens and if its fixable?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define SIZE 100
int **pointerSort(int *arr, unsigned int size, int ascend_flag);
void ptrMerge(int arr[], int start, int mid, int end, int *ptrArr[], int flag);
void pmergeSort(int arr[], int start, int end, int *ptrArr[], int flag);
void main() {
unsigned int size, i;
int arr[SIZE];
int **pointers;
int ascend_flag;
printf("Please enter the number of items:\n");
scanf("%u", &size);
for (i = 0; i < size; i++)
scanf("%d", &arr[i]);
scanf("%d", &ascend_flag);
pointers = pointerSort(arr, size, ascend_flag);
printf("The sorted array:\n"); //Print the sorted array
//printPointers(pointers, size);
for (i = 0; i < size; i++)
printf("d%\t%d", *pointers[i], pointers[i]);
free(pointers);
}
int **pointerSort(int *arr, unsigned int size, int ascend_flag) {
int **sortedArr;
sortedArr = (int**)malloc(size * sizeof(int*));
pmergeSort(arr, 0, size - 1, sortedArr, ascend_flag);
return sortedArr;
}
void pmergeSort(int arr[], int start, int end, int *ptrArr[], int flag) {
if (start < end) {
int mid = (start + end) / 2;
pmergeSort(arr, start, mid, ptrArr, flag);
pmergeSort(arr, mid + 1, end, ptrArr, flag);
ptrMerge(arr, start, mid, end, ptrArr, flag);
}
}
void ptrMerge(int arr[], int start, int mid, int end, int *ptrArr[], int flag) {
int i, k = 0;
int p = start, q = mid + 1;
int **tempArr;
tempArr = (int**)malloc((end - start + 1) * sizeof(int*));
for (i = start; i <= end; i++) {
if (arr[p] < arr[q]) {
tempArr[k] = &arr[p];
k++;
p++;
} else { //(arr[p] > arr[q])
tempArr[k] = &arr[q];
k++;
q++;
}
}
while (p <= mid) {
tempArr[k] = &arr[p];
k++;
p++;
}
while (q <= end) {
tempArr[k] = &arr[q];
k++;
p++;
}
if (flag == 1) {
for (i = 0; i < k; i++)
ptrArr[start] = tempArr[i];
start++;
}
} else {
for (i = k - 1; i >= start; i--) {
ptrArr[start] = tempArr[i];
start++;
}
}
for (i = 0; i < k; i++)
printf("%x\t%d\n", ptrArr[i], *ptrArr[i]);
printf("\n");
free(tempArr);
}
You get a segmentation fault because the ptrMerge function corrupts the memory by writing past the end of the tempArr allocated array.
The first loop iterates end - start + 1 times, potentially accessing arr beyond the end of the slices.
The loop continues until p >= mid and q >= end, writing to tempArr[k] with k greater or equal to the number of elements allocated with malloc().
The logic is flawed: you compare the elements of arr at offsets p and q instead of indirecting through the array ptrArr.
Here is a modified version:
int **pointerSort(int *arr, int size, int ascend_flag) {
int **sortedArr = (int**)malloc(size * sizeof(int*));
for (int i = 0; i < size; i++) {
sortedArr[i] = &arr[i];
}
pmergeSort(sortedArr, 0, size - 1, ascend_flag);
return sortedArr;
}
void pmergeSort(int *ptrArr[], int start, int end, int flag) {
if (start < end) {
int mid = start + (end - start) / 2;
pmergeSort(ptrArr, start, mid, flag);
pmergeSort(ptrArr, mid + 1, end, flag);
ptrMerge(ptrArr, start, mid, end, flag);
}
}
void ptrMerge(int *ptrArr[], int start, int mid, int end, int flag) {
int i, k, n = end - start + 1;
int p = start, q = mid + 1;
int **tempArr = (int**)malloc(n * sizeof(int*));
for (k = 0; k < n; k++) {
if (p <= mid && (q >= end || *ptrArr[p] <= *ptrArr[q])) {
tempArr[k] = ptrArr[p++];
} else {
tempArr[k] = ptrArr[q++];
}
}
if (flag == 1) {
for (k = 0; k < n; k++)
ptrArr[start + k] = tempArr[k];
}
} else {
for (k = 0; k < n; k++) {
ptrArr[end - k] = tempArr[k];
}
}
free(tempArr);
}
Also note that main() must be defined with a return type int and the loop that prints the values is broken. It should read:
for (i = 0; i < size; i++)
printf("%d\t", *pointers[i]);
printf("\n");
So you should use :
int main(void)
In this while q is never updated so i guess infinite loop?
while (q <= end)
{
tempArr[k] = &arr[q];
k++;
p++;
}
Can you provide me your inputs and output you want?
I have tried your code and i'm not getting your error.
The following code is trying to find the averages of a set of numbers in C, but the median and the mean both do not return anything. How do I make it so the mean and the median both return a float? Am I returning an invalid value or?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int compare (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
float mean(int arr[], int size){
int sum = 0;
for(int i = 0; i<size; i++){
sum += arr[i];
}
return ((float)sum/size);
}
int range(int arr[], int size){
int smallest = arr[0];
int largest = arr[0];
for(int i=0; i<size; i++){
if(smallest>arr[i]){
smallest = arr[i];
} if(largest<arr[i]){
largest = arr[i];
}
} int difference = largest - smallest;
return difference;
}
int mode(int arr[], int size){
int maxValue = 0;
int maxCount = 0;
for(int i = 0; i<size; i++){
int count = 0;
for(int j = 0; j<size; j++){
if(arr[j] == arr[i]){
count++;
}
} if(count > maxCount){
maxCount = count;
maxValue = arr[i];
}
} return maxValue;
}
float median(int arr[], int size){
qsort(arr, size, sizeof(int), compare);
float middleOfArray = size/2;
int roundedMiddleOfArray = rint(middleOfArray);
if(ceilf(middleOfArray) == middleOfArray){
return((float)arr[roundedMiddleOfArray]);
}
else{
return((float)arr[roundedMiddleOfArray] - arr[roundedMiddleOfArray-1]);
}
}
int main(){
int array[6] = {1,2,3,4,5,6};
int newMean = mean(array, 5);
int newRange = range(array, 5);
int newMode = mode(array,5);
int newMedian = median(array, 5);
printf("The mean is : %f \n", newMean);
printf("The range is : %d \n",newRange);
printf("The mode is : %d \n",newMode);
printf("The median is : %f \n", newMedian);
return 0;
}
Turns out the way you fix it is by declaring the mean and the median as floats not ints (in main).
I have written a program which generates a random array and sorts it by using both the insertion and quicksort algorithms. The program also measures the runtime of each function. The size of the array is defined in the preamble as a parameterised macro L. My question is:
How can I test both sorting algorithms with arrays of various sizes in a single execution?
I want my program to sort arrays of size L=10, 100, 1000, 5000 and 10000 in one execution. My program code is detailed below.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//Random Array Length
#define MAX 100
#define L 10
void naive_sort(int[]);
void smarter_sort(int[],int,int);
void swap(int[],int,int);
int choose_piv(int[],int,int);
int main(){
int i, a[L], b[L];
clock_t tic, toc;
//Generate an array of random numbers
for(i=0; i<L; i++)
a[i]= rand() % (MAX+1);
//Define b identical to a for fair comparison
for(i=0; i<L; i++)
b[i]=a[i];
//Unsorted Array
printf("\nUnsorted array: ");
for(i=0; i<L; i++)
printf("%d ", a[i]);
//Insertion Sort (1e)
tic = clock();
naive_sort(a);
printf("\nInsertion Sort: ");
for(i=0; i<L; i++)
printf("%d ", a[i]);
toc = clock();
printf(" (Runtime: %f seconds)\n", (double)(toc-tic)/CLOCKS_PER_SEC);
//Quicksort (1f)
tic = clock();
smarter_sort(b,0,L-1);
printf("Quicksort: ");
for(i=0; i<L; i++)
printf("%d ", b[i]);
toc = clock();
printf(" (Runtime: %f seconds)\n", (double)(toc-tic)/CLOCKS_PER_SEC);
return 0;
}
void naive_sort(int a[]){
int i, j, t;
for(i=1; i < L; i++){
t=a[i];
j=i-1;
while((t < a[j]) && (j >= 0)){
a[j+1] = a[j];
j--;
}
a[j+1]=t;
}
}
void smarter_sort(int a[], int l, int r){
if(r > l){
int piv = choose_piv(a, l, r);
smarter_sort(a, l, piv-1);
smarter_sort(a, piv+1, r);
}
}
void swap(int a[], int i, int j){
int t=a[i];
a[i]=a[j];
a[j]=t;
}
int choose_piv(int a[], int l, int r){
int pL = l, pR = r;
int piv = l;
while (pL < pR){
while(a[pL] < a[piv])
pL++;
while(a[pR] > a[piv])
pR--;
if(pL < pR)
swap(a, pL, pR);
}
swap(a, piv, pR);
return pR;
}
I would appreciate any feedback.
EDIT: I modified the code as suggested, and it worked for the small values. But for the quicksort case L=100 and beyond it, I don't get any output:
and as you can see, the few outputs I get are zero. What's wrong with the code?
/*
* Task 1, question h
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//Random Array Length
#define MAX 100
void perf_routine(int);
void naive_sort(int[],int);
void smarter_sort(int[],int,int);
void swap(int[],int,int);
int choose_piv(int[],int,int);
int main(){
perf_routine(10);
perf_routine(100);
perf_routine(1000);
perf_routine(5000);
perf_routine(10000);
return 0;
}
void perf_routine(int L){
int i, a[L], b[L];
clock_t tic, toc;
printf("Arrays of Length %d:\n", L);
//Generate an array of random numbers
for(i=0; i<L; i++)
a[i]= rand() % (MAX+1);
//Define b identical to a for fair comparison
for(i=0; i<L; i++)
b[i]=a[i];
//Insertion Sort (1e)
tic = clock();
naive_sort(a, L);
toc = clock();
printf("Insertion Sort Runtime: %f seconds\n", (double)(toc-tic)/CLOCKS_PER_SEC);
//Quicksort (1f)
tic = clock();
smarter_sort(b,0,L-1);
toc = clock();
printf("Quicksort Runtime: %f seconds\n", (double)(toc-tic)/CLOCKS_PER_SEC);
}
void naive_sort(int a[], int L){
int i, j, t;
for(i=1; i < L; i++){
t=a[i];
j=i-1;
while((t < a[j]) && (j >= 0)){
a[j+1] = a[j];
j--;
}
a[j+1]=t;
}
}
void smarter_sort(int a[], int l, int r){
if(r > l){
int piv = choose_piv(a, l, r);
smarter_sort(a, l, piv-1);
smarter_sort(a, piv+1, r);
}
}
void swap(int a[], int i, int j){
int t=a[i];
a[i]=a[j];
a[j]=t;
}
int choose_piv(int a[], int l, int r){
int pL = l, pR = r;
int piv = l;
while (pL < pR){
while(a[pL] < a[piv])
pL++;
while(a[pR] > a[piv])
pR--;
if(pL < pR)
swap(a, pL, pR);
}
swap(a, piv, pR);
return pR;
}
I would, in each function gives the length of the array in parameters and make sure you don't try to reach element outside of array, for example swap would become:
int swap(int *a, int length, int i, int j)
{
if(i>=length || j>=length)
return -1;
int t=a[i];
a[i]=a[j];
a[j]=t;
return 0;
}
Also note the return -1 or 0 to indicates a failure. Apply that to the rest of the code and you'll have something that can be applied to any array.
When arrays are passed to functions, they are passed as (or "decay into") pointer to their first element. There is no way to know about the size of the array.
It is therefore very common to pass the actual length as additional parameter to the function. An example of your naive sort with three arrays of different size if below.
Of course, one must take care to keep the array and length in sync. Passing a length that is too big may result in undefined behaviour. For example, calling fill(tiny, LARGE) in the example below may result in disaster.
(Aside: An array may have a maximum length or capacity and an actual length. For example if you want to read up to ten numbers from a file, you must pass an array of length 10, but if there are only four numbers read, you are dealing with two additional parameters here: the possible array length, 10, and the actual length, 4. That's not the case here, though.)
Well, here goes. All three array functions have the same signature: They take an array and its length.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void sort(int a[], size_t len)
{
size_t i, j;
for (i = 1; i < len; i++) {
int t = a[i];
j = i - 1;
while (j >= 0 && t < a[j]) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = t;
}
}
void fill(int a[], size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
a[i] = rand() / (1.0 + RAND_MAX) * 100;
}
}
void print(int a[], size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
if (i) printf(", ");
printf("%d", a[i]);
}
puts("");
}
#define TINY 3
#define MEDIUM 10
#define LARGE 15
int main(void)
{
int tiny[TINY];
int medium[MEDIUM];
int large[LARGE];
srand(time(NULL));
fill(tiny, TINY);
fill(medium, MEDIUM);
fill(large, LARGE);
print(tiny, TINY);
print(medium, MEDIUM);
print(large, LARGE);
sort(tiny, TINY);
sort(medium, MEDIUM);
sort(large, LARGE);
print(tiny, TINY);
print(medium, MEDIUM);
print(large, LARGE);
return 0;
}
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 )