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).
Related
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)
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?
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 )
i wrote this code in C language on Xcode following the algorithm of mergesort.
The problem is that sometimes i get EXC_BAD_ACCESS and i can't manage where the error is!
The merge algorithm should work (i tried it outside the mergesort function and works!). Thank you for your help and patience!
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define DIM 6
void mymerge (int v[], int i1,int i2, int last); //mergesort core: merge two ordinated arrays in one bigger ordinated array
void mymergesort (int v[], int lower, int upper);//mergesort
void printv (int v[],int lower, int upper);
int main () {
int i;
srand((unsigned int)time(NULL));
int v[DIM];
for (i=0; i<DIM; i++)
v[i]=rand()%15;
printv(v, 0, DIM-1);
getc(stdin);
mymergesort(v, 0, DIM-1);
printv(v, 0, DIM-1);
}
void printv (int v[],int lower, int upper){
int i;
for (i=lower; i<=upper; i++)
printf("%d\t",v[i]);
}
void mymergesort (int v[], int lower, int upper){
int mid=(upper+lower)/2;
if (upper<lower) {
mymergesort(v, lower, mid);
mymergesort(v, mid+1, upper);
mymerge(v,lower,mid+1,upper);
}
}
void mymerge (int v[], int i1,int i2, int last){
int i=i1,j=i2,k=i1,*vout;
vout=(int*)malloc((last-i1+1)*sizeof(int));
while (i<i2 && j<=last) {
if (v[i]<=v[j]) {
vout[k++]=v[i++];
}else {
vout[k++]=v[j++];
}
}
for (;i<i2;i++) vout[k++]=v[i];
for (;j<=last;j++) vout[k++]=v[j];
for (k=i1; k<=last; k++) v[k]=vout[k];
free(vout);
}
EDIT:
thank you very much! but i think think there is another problem, when I try to sort a bigger array (200 elements), the program doesn't work (i get a malloc error: incorrect checksum for freed object - object was probably modified after being freed). But if I run it from the xCode debugger everything works fine
This: vout=(int*)malloc((last-i1)*sizeof(int)); is wrong.
First, the number of elements you want is last-i1+1, not last-i1 - classic off-by-1. This kind of error is one of the reasons why the convention in C code is to make lower bounds inclusive and upper bounds exclusive - less +1 and -1 you need to do, less opportunity to screw up.
The more serious error is that you index vout starting from i1. If you do it this way, you need to allocate last+1 element for vout, and you never use the first i1 (index 0 .. i1-1).
Fix: First, allocate last-i1+1 elements. Second, initialize k to 0 at the beginning, not i1. Third, change the final copy to be
for (k=i1; k<=last; k++) v[k] = vout[k-i1];
You have two problems. The first is that your calculation of the midpoint is incorrect - you use (upper - lower)/ 2, but this is not guaranteed to lie between lower and upper. What you actually want is lower + (upper - lower) / 2. It's also not necessary to do any work if there's only 1 number in the interval to be sorted - so the mymergesort() function should look like:
void mymergesort (int v[], int lower, int upper)
{
if (upper > lower) {
int mid = lower + (upper - lower)/2;
mymergesort(v, lower, mid);
mymergesort(v, mid+1, upper);
mymerge(v,lower,mid+1,upper);
}
}
The second problem is the one in the mymerge() function already pointed out by Fabian Giesen.
#include<stdio.h>
#include<stdlib.h>
void merge(int *a, int n1, int *b, int n2, int *arr)
{
int i=0, j=0, n=0;
while(i<n1 && j<n2)
{
if (a[i] < b[j])
{
arr[n++] = a[i];
i++;
}
else
{
arr[n++] = b[j];
j++;
}
}
while( i < n1)
arr[n++] = a[i++];
while( j < n2)
arr[n++] = b[j++];
}
void merge_sort(int *a, int n)
{
int left[n/2], right[n-n/2],i=0;
if (n<=1)
return ;
while(i<n/2)
left[i] = a[i++];
while(i<n)
right[i - n/2] = a[i++];
merge_sort( left, n/2 );
merge_sort( right, n-n/2);
merge(left, n/2, right, n-n/2, a);
}
void main()
{
int a[] = { 6, 5, 3, 1,9, 8, 7, 2, 4},i;
merge_sort(a,sizeof(a)/sizeof(a[0]));
for(i=0;i<9;i++)
printf("--%d",a[i]);
printf("\n");
}
-- s.k
#include<stdio.h>
#include<conio.h>
#define max 20
/*** function for merging the adjecent subarrays in sorted order ***/
void merge(int A[max],int n,int low,int high, int mid)
{
int i=low,j=mid+1,k,temp;
while((i<=j)&&(j<=high))
{
if(A[i]>A[j]) /** if element of the second half is greater then exchg and shift **/
{
temp=A[j];
for(k=j;k>i;k--) /** shifting the elements **/
{
A[k]=A[k-1];
}
A[i]=temp;
j++;
}
i++;
}
}
/******* iterative function for merge sort ********/
void merge_sort(int A[max],int n,int low,int high)
{
int mid;
if(low<high) /** terminating condition **/
{
mid=(high+low)/2; /** calculating the mid point ***/
merge_sort(A,n,low,mid); /*** recursive call for left half of the array ***/
merge_sort(A,n,mid+1,high); /*** recursive call for right half of the array ***/
merge(A,n,low,high,mid); /** merging the both parts of the array **/
}
}
/******* begening of the main function **********/
int main()
{
int A[max],n,i;
/** reading the inputs fro users **/
printf("\n enter the size of the array\n");
scanf("%d",&n);
printf("\n enter the array \n");
for(i=0;i<n;i++)
{
scanf("%d",&A[i]);
}
/*** calling merge sort ***/
merge_sort(A,n,0,n-1);
/** printing the sorted array **/
for(i=0;i<10;i++)
{
printf("\n\t%d",A[i]);
}
getch();
return 0;
}