Revision as of 21:41, 13 May 2024 by Admin (Created page with "One possible solution , after reading online descriptions of recursive merge sort, e.g. Dasgupta : <syntaxhighlight lang="C"> // to compile: gcc -Wall rmergesort.c -lm -o rmergesort /* ============================================================================ Name : rmergesort.c Author : Anon Version : 0.1 Copyright : (C)2013 under CC-By-SA 3.0 License Description : Recursive Merge Sort, Ansi-style =============================================...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Exercise


May 13'24

Answer

One possible solution , after reading online descriptions of recursive merge sort, e.g. Dasgupta : // to compile: gcc -Wall rmergesort.c -lm -o rmergesort

/*

============================================================================
Name        : rmergesort.c
Author      : Anon
Version     : 0.1
Copyright   : (C)2013 under CC-By-SA 3.0 License
Description : Recursive Merge Sort, Ansi-style
============================================================================
*/
  1. include
  2. include
  3. include

//const int MAX = 200; const int MAX = 20000000;

int *b;

int printOff = 0;

// this debugging print out of the array helps to show // what is going on. void printArray(char* label, int* a, int sz) { int h = sz/ 2; int i;

if (printOff) return;

printf("\n%s:\n", label);

for (i = 0; i < h; ++i ) {

printf("%d%c", a[i], // add in a newline every 20 numbers ( ( i != 0 && i % 20 == 0 )? '\n': ' ' ) ); }

printf(" | "); for (;i < sz; ++i) { printf("%d%c", a[i], ( ( i != 0 && i % 20 == 0 )? '\n': ' ' ) ); }

putchar('\n');


}

void mergesort(int* a, int m ) {

printArray("BEFORE", a, m);

if (m > 2) { // if greater than 2 elements, then recursive mergesort(a, m / 2); mergesort(a + m / 2, m - m / 2);


} else if (m == 2 && a[0] > a[1]) { // if exactly 2 elements and need swapping, swap int t = a[1]; a[1] = a[0]; a[0] = t; goto end;

}

// 1 or greater than 2 elements which have been recursively sorted

// divide the array into a left and right array // merge into the array b with index l.

int n = m/2; int o = m - n;

int i = 0, j = n; int l = 0; // i is left, j is right ; // l should equal m the size of the array while (i < n) { if ( j >= m) { // the right array has finished, so copy the remaining left array for(; i < n; ++i) { b[l++] = a[i]; }

// the merge operation is to copy the smaller current element and // increment the index of the parent sub-array. } else if( a[i] < a[j] ) { b[l++] = a[i++]; } else { b[l++] = a[j++]; } }

while ( j < m) { // copy the remaining right array , if any b[l++] = a[j++]; }

memcpy(a, b, sizeof(int) * l );

end: printArray("AFTER", a, m);

return;

}

void rand_init(int* a, int n) { int i; for (i = 0; i < n; ++i ) {

a[i] = rand() % MAX;

} }

int main(void) { puts("!!!Hello World!!!"); /* prints !!!Hello World!!! */

// int N = 20; // int N = 1000; // int N = 1000000; int N = 100000000; // still can't make a stack overflow on ubuntu,4GB, phenom printOff = 1;

int *a;

b = calloc( N, sizeof(int));

a = calloc( N, sizeof(int));

rand_init(a, N);

mergesort(a, N);

printOff = 0;

printArray("LAST", a, N);

free(a); free(b);

return EXIT_SUCCESS; }


/* Having failed to translate my concept of non-recursive merge sort,

* I tackled the easier case of recursive merge sort.
* The next task is to translate the recursive version to a non-recursive
* version. This could be done by replacing calls to mergesort, with
* pushes onto a stack of
* tuples of ( ,  )
*/

/* The central idea of merging, is that two sorted lists can be

* merged into one sorted list, by comparing the top of each list and
* moving the lowest valued element onto the end of the new list.
*  The other list which has the higher valued element keeps its top
*  element unchanged. When a list is exhausted, copy the remaining other list
*  onto the end of the new list.
*/

/* The recursive part, is to defer any work in sorting an unsorted list,

* by dividing it into two lists until there is only 1 or two elements,
* and if there are two elements, sort them directly by swapping if
* the first element is larger than the second element.
*
* After returning from a recursive call, merge the lists, which will
* begin with one or two element sorted lists. The result is a sorted list
* which will be returned to the parent of the recursive call, and can
* be used for merging.
*/

/* The following is an imaginary discussion about what a programmer

* might be thinking about when programming:
*
* Visualising recursion in terms of a Z80 assembly language, which
* is similar to most assembly languages, there is a data stack (DS) and
* a call stack (CS) pointer, and each recursive call to mergesort
* pushes the return address , which is the program address of the instruction
* after the call , onto the stack pointed to by CS and CS is incremented,
* and the address of the array start and integer which is the subarray length
* onto the data stack pointed to by DS, which will be incremented twice.
*
* If the number of recursive , active calls exceed the allowable space for either the call stack
* or the data stack, then the program will crash , or a process space protection
* violation interrupt signal will be sent by the CPU, and the interrupt vector
* for that signal will jump the processor's current instruction pointer to the
* interrupt handling routine.
*/
00