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;
}
Related
how to output data into new files g1 g2 g3 for each sorting method in c language
This is the code that i have done .. Might be a little messy but i somehow managed to make it work i think. I was wondering how to separately print the sorting output in each of their different files. Any advice or suggestions on how to do it will be appreciated
edit: i dont know if the program works because the plan was to run the loop till the array size (which will be the total values in the file) but i didnt know how to run a loop through an array without knowing its size in c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
void getRandomArray(int arr[], int n, int max); //initiate an array with random numbers
void cloneArray(int arrB[], int arrA[], int size); //copy an array to another
void printArray(int arr[], int size); //print all elements of an array
void swap(int *xp, int *yp);
void selectionSort(int arr[], int n); //selection sort
void insertionSort(int list[], int n); //insertion sort
int main(int argc, char *argv[]) {
FILE *myFile;
myFile = fopen("test_dat.txt", "r");
//read file into array
int i;
int SIZE=10000;
int arrA[SIZE], arrB[SIZE];
if (myFile == NULL){
printf("Error Reading File\n");
exit (0);
}
for (i = 0; i <SIZE; i++){
fscanf(myFile, "%d,", &arrA[i] );
}
cloneArray( arrB, arrA, SIZE);
printArray(arrA, SIZE);
clock_t start = clock();
cloneArray(arrB, arrA, SIZE);
start = clock();
selectionSort(arrB, SIZE);
printf("Time = %f ms\n", 1000.0*(clock()-start)/CLOCKS_PER_SEC);
printArray(arrB, SIZE);
cloneArray(arrB, arrA, SIZE);
start = clock();
insertionSort(arrB, SIZE);
printf("Time = %f ms\n", 1000.0*(clock()-start)/CLOCKS_PER_SEC);
printArray(arrB, SIZE);
free(arrA);
free(arrB);
fclose(myFile);
}
//=======================================================
void cloneArray(int arrB[], int arrA[], int size) {
for (int i = 0; i < size; i++)
arrB[i] = arrA[i];
}
void printArray(int arr[], int size) {
for (int i=0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
void swap(int *xp, int *yp) {
int temp = *xp;
*xp = *yp;
*yp = temp;
}
//=======================================================
void selectionSort(int arr[], int n) {
puts("\n==================== Selection Sort ==================== ");
int comp = 0, swp = 0;
int min_idx;
for (int i = 0; i < n-1; i++) {
min_idx = i;
for (int j = i+1; j < n; j++)
if (arr[j] < arr[min_idx]) {
min_idx = j;
comp++;
}
swap(&arr[min_idx], &arr[i]);
swp++;
}
printf("No. comparisons = %d; No. swaps = %d\n", comp, swp);
}
void insertionSort(int list[], int n) {
puts("\n==================== Insertion Sort ====================");
int comp = 0, assg = 0;
for (int h = 1; h < n; h++) {
int key = list[h];
int k = h - 1; //start comparing with previous item
while (k >= 0 && key < list[k]) {
list[k + 1] = list[k];
comp++;
assg++;
--k;
}
list[k + 1] = key;
}
printf("No. comparisons = %d; No. assignments = %d\n", comp, assg);
return 0;
} //end insertionSort
according to introduction to algorithms I wrote a code for quicksort using Hoare's partition in the codeblocks IDE .The code was successfully built but the sorted array is not displayed on the console,only the unsorted array is displayed followed by a blinking underscore.
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
int partition(int arr[],int p,int r)
{
int i,j,x,temp;
x=arr[p];
i=p-1;
j=r+1;
while(true)
{
do{
j=j-1;
}while(arr[j]<=x);
do{
i=i+1;
}while(arr[i]>=x);
if (i<j)
{
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
else
return j;
}
}
void quicksort(int arr[],int p,int r)
{
if (p<r)
{
int q=partition(arr,p,r);
quicksort(arr,p,q-1);
quicksort(arr,q-1,r);
}
}
void print(int A[],int size)
{
int i;
for(i=0;i<size;i++)
printf("%d ",A[i]);
}
int main()
{
int arr[]={1,12,56,2,67,0,98,23};
int size=sizeof(arr)/sizeof(arr[0]);
printf("\nthe array is\n");
print(arr,size);
quicksort(arr,0,size-1);
printf("\nthe sorted array is\n ");
print(arr,size);
return 0;
}
the output was as follows
the array is
1 12 56 2 67 0 98 23
`
Okay, I refactored your algorithm, based on a guide from wikipedia: https://en.wikipedia.org/wiki/Quicksort
As mentioned in my comment above, the [recursive] quicksort calls used the wrong arguments. But, then, as Weather Vane mentioned, it [still] didn't sort.
Edit: My original post was using Lomuto partitioning instead of Hoare.
The partition algorithm differed from the wiki by using a different initial value for the pivot and using <=,>= on the do/while termination conditions instead of <,>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int
partition(int arr[], int p, int r)
{
int i,
j,
x,
temp;
x = arr[(p + r) / 2];
i = p - 1;
j = r + 1;
while (1) {
do {
i += 1;
} while (arr[i] < x);
do {
j -= 1;
} while (arr[j] > x);
if (i >= j)
return j;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
void
quicksort(int arr[], int p, int r)
{
if (p < r) {
int q = partition(arr, p, r);
quicksort(arr, p, q);
quicksort(arr, q + 1, r);
}
}
void
print(int A[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", A[i]);
}
int
main()
{
int arr[] = { 1, 12, 56, 2, 67, 0, 98, 23 };
int size = sizeof(arr) / sizeof(arr[0]);
printf("\nthe array is\n");
print(arr, size);
quicksort(arr, 0, size - 1);
printf("\nthe sorted array is\n ");
print(arr, size);
printf("\n");
return 0;
}
I have implemented a quicksort algorithm in C to sort the elements of an array. It works for all cases except when an the array has two or more equal elements. I've been trying to fix it and have been debugging it but I can't seem to manage to get it to work when there are repeated elements.
I'd appreciate any assistance on how I can change my code to work for repeated elements too.
#include <stdio.h>
#include <stdlib.h>
//Random Array Length
#define L 10
#define MAX 100
void smarter_sort(int[],int,int);
void swap(int[],int,int);
int choose_piv(int[],int,int);
int main(){
int i, a[L];
//Generate an array of random numbers
for(i=0; i<L; i++)
a[i]= rand() % (MAX+1);
//Unsorted Array
printf("\nUnsorted array: ");
for(i=0; i<L; i++)
printf("%d ", a[i]);
//Sorted Array
smarter_sort(a,0,L-1);
printf("\nSorted array: ");
for(i=0; i<L; i++)
printf("%d ", a[i]);
return 0;
}
//Recursively defined quicksort (Pseudo-code listing 1.9)
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);
}
}
//Swap Elements
void swap(int a[], int i, int j){
int t=a[i];
a[i]=a[j];
a[j]=t;
}
//Choosing the pivot (pseudo-code listing 1.10)
int choose_piv(int a[], int l, int r){
//defining pointers and pivot
int pL = l, pR = r;
int piv = l;
while (pL < pR){
//finding the first left element greater than piv
while(a[pL] < a[piv])
pL++;
//finding the first right element greater than piv
while(a[pR] > a[piv])
pR--;
//swapping if the pointers do not overlap
if(pL < pR)
swap(a, pL, pR);
if(a[pL]==a[piv]||a[pR]==a[piv]){
pL++;
pR--;
}
}
//swapping and returning the rightmost pointer as the pivot
swap(a, piv, pR);
return pR;
}
This is your code modified in order to work properly even with array containing equal elements:
#include <stdio.h>
#include <stdlib.h>
//Random Array Length
#define L 10
#define MAX 100
void smarter_sort(int[],int,int);
void swap(int[],int,int);
int main(){
int i, a[L];
//Generate an array of random numbers
for(i=0; i<L; i++)
a[i]= rand() % (MAX+1);
//Unsorted Array
printf("\nUnsorted array: ");
for(i=0; i<L; i++)
printf("%d ", a[i]);
//Sorted Array
smarter_sort(a,0,L-1);
printf("\nSorted array: ");
for(i=0; i<L; i++)
printf("%d ", a[i]);
return 0;
}
//Recursively defined quicksort (Pseudo-code listing 1.9)
void smarter_sort(int arr[], int left, int right) {
int i = left, j = right;
int pivot = arr[(left + right) / 2];
while (i <= j) {
while (arr[i] <pivot)
i++;
while (arr[j]>pivot)
j--;
if (i <= j) {
swap(arr,i,j);
i++;
j--;
}
};
if (left < j)
smarter_sort(arr, left, j);
if (i < right)
smarter_sort(arr, i, right);
}
//Swap Elements
void swap(int a[], int i, int j){
int t=a[i];
a[i]=a[j];
a[j]=t;
}
I posted this question on the site earlier, whose solution I managed to get to (more or less). In a nutshell, I need to test the insertion and quicksort algorithms for arrays of various sizes, and see how their runtime varies with respect to array size.
The only issue is that my program seems to freeze when it tries to calculate the runtime of the quicksort algorithm for arrays with 100 elements and larger. I've tried debugging the code and I can't seem to understand why this is the case. When I run it, this is the output I get:
Why does it stop there? and why is the runtime zero? Can anyone help me with this? In my original question, some commenters suggested I use malloc but I'm not sure how to go about it.
My code is listed below, I'd appreciate any suggestions.
/*
* Task 1, question h
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//Random Array Length
#define MAX 1000
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((j >= 0) && (t < a[j])){
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;
}
choose_piv can go into an infinite loop if there are duplicate values in the array. If a[pL], a[pR], and a[piv] are the same, then the inner while loops both exit immediately, the swap has no effect (since both values are the same), and the outer while loop will loop forever. Try it with a small array where all element are the same (e.g., all zero).
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));