I have been going through Introduction to Algorithms, and have been trying to implement the MERGE-SORT algorithm in C programming language to gain a better understanding of it.
The book presents two pseudo-codes:
and
While I do understand the above procedures, I must be missing something during the implementation.
I must be missing something from the pseudo-code but cannot figure it out yet. Any suggestions as to why this is happening would be appreciated.
EDIT: Updated Code and Output
/* C program for Merge Sort */
#include<stdlib.h>
#include<stdio.h>
void MERGE(int [], int , int , int );
void printArray(int [], int );
void MERGE_SORT(int [], int , int );
int main(void)
{
int A[] = { 12, 11, 13, 5, 6, 7, 2, 9 };
int arr_size = sizeof(A) / sizeof(A[0]);
printf("Given array is \n");
printArray(A, arr_size);
MERGE_SORT(A, 0, arr_size); //Fixed: Index to start from zero
printf("\nSorted array is \n");
printArray(A, arr_size);
return 0;
}
void MERGE(int A[], int p, int q, int r)
{
int i = 0;
int j = 0;
int n1 = q - p + 1; //Computing length of sub-array 1
int n2 = r - q; //Computing length of sub-array 2
int *L = malloc((n1 + 2) * sizeof(*L + 1)); //Creating Left array
int *R = malloc((n2 + 2) * sizeof(*R + 1)); //Creating Right array
for (int i = 0; i <= n1; i++) { //Fixed: <=, i start from 0
L[i] = A[p + i - 1];
}
for (int j = 0; j <= n2; j++) { //Fixed: <=, i start from 0
R[j] = A[q + j];
}
L[n1 + 1] = 99; //Placing Sentinel at the end of array
R[n2 + 1] = 99;
i = 1;
j = 1;
/*Prior to the first iteration k = p, so the subarray is empty.
Both L[i] and R[j] are the smallest elements of their arrays and have not
been copied back to A*/
for (int k = p; k <= r; k++) { //Fixed: <=
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
}
else { //Fixed: Assignment and not condition check for A[k]
A[k] = R[j];
j++;
}
}
free(L);
free(R);
}
void MERGE_SORT(int A[], int p, int r)
{
//During first iteration p = 1 & r = 8
if (p < r) {
int q = (p + r) / 2;
MERGE_SORT(A, p, q);
MERGE_SORT(A, q + 1, r);
MERGE(A, p, q, r);
}
}
/* Function to print an array */
void printArray(int Arr[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", Arr[i]);
printf("\n");
}
Looked in the pseudo code and found out that some things have been mistakenly written wrong.
1. You need to be careful with the array index to start from 0 or 1
2. Merge last part in for loop is actually an assignment instead for conditional check.
Edit: Have updated the code to fix for the error Stack around the variable A was corrupted
Please find the corrected code here(Lookout for //Fixed for fixes)
/* C program for Merge Sort */
#include<stdlib.h>
#include<stdio.h>
void MERGE(A, p, q, r);
void printArray(Arr, size);
void MERGE_SORT(A, p, r);
int main(void)
{
int A[] = { 12, 11, 13, 5, 6, 7, 2, 9 };
int arr_size = sizeof(A) / sizeof(A[0]);
printf("Given array is \n");
printArray(A, arr_size);
MERGE_SORT(A, 0, arr_size - 1); //Fixed: Index to start from zero, arr_size - 1
printf("\nSorted array is \n");
printArray(A, arr_size);
return 0;
}
void MERGE(int A[], int p, int q, int r)
{
int i = 0;
int j = 0;
int n1 = q - p + 1; //Computing length of sub-array 1
int n2 = r - q; //Computing length of sub-array 2
int *L = malloc((n1+1) * sizeof(*L+1)); //Creating Left array
int *R = malloc((n2+1) * sizeof(*R+1)); //Creating Right array
for (int i = 0; i < n1; i++) { //Fixed: i start from 0
L[i] = A[p + i];
}
// int arr_size = sizeof(A) / sizeof(A[0]);
for (int j = 0; j < n2; j++) { //Fixed: j start from 0
R[j] = A[q + j + 1];
}
L[n1] = 99; //Placing Sentinel at the end of array
R[n2] = 99;
i = 0; //Fixed: i and j to start from 0
j = 0;
/*Prior to the first iteration k = p, so the subarray is empty.
Both L[i] and R[j] are the smallest elements of their arrays and have not
been copied back to A*/
for (int k = p; k <= r; k++) { //Fixed: <=
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
}
else { //Fixed: Assignment and not condition check for A[k]
A[k] = R[j];
j++;
}
}
free(L);
free(R);
}
void MERGE_SORT(int A[], int p, int r)
{
//During first iteration p = 1 & r = 8
if (p < r) {
int q = (p + r) / 2;
MERGE_SORT(A, p, q);
MERGE_SORT(A, q + 1, r);
MERGE(A, p, q, r);
}
}
/* Function to print an array */
void printArray(int Arr[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", Arr[i]);
printf("\n", size);
}
Hope it helps.
Revert for any doubts.
here are some changes i have done to your code `
#include<stdlib.h>
#include<stdio.h>
void MERGE(int *A,int p,int q,int r);
void printArray(int *Arr,int size);
void MERGE_SORT(int *A,int p,int r);
int main(void){
int A[] = { 12, 11, 13, 5, 6, 7, 2, 9 };
int arr_size = sizeof(A) / sizeof(A[0]);
printf("Given array is \n");
printArray(A, arr_size);
MERGE_SORT(A, 0, arr_size -1); // pass the indices of the array
printf("\nSorted array is \n");
printArray(A, arr_size);
return 0;
}
void MERGE(int A[], int p, int q, int r){
int i = 0;
int j = 0;
int k; //declair it here
int n1 = q - p + 1; //Computing length of sub-array 1
int n2 = r - q; //Computing length of sub-array 2
int *L = malloc((n1) * sizeof(*L+1)); //Creating Left array
int *R = malloc((n2) * sizeof(*R+1)); //Creating Right array
for (int i = 0; i < n1; i++) { //start coping from zero
L[i] = A[p + i];
}
for (int j = 0; j < n2; j++) {
R[j] = A[q +1 + j];
}
// L[n1] = 99; we won't be needing these as to mark the end we already know the size of arrays
// R[n2] = 99;
// i = 1;
// j = 1;
/*Prior to the first iteration k = p, so the subarray is empty.
Both L[i] and R[j] are the smallest elements of their arrays and have not
been copied back to A*/
for (k = p; k < r+1 && i < n1 && j<n2; k++) {
//i & j checks weather the array has completed or not
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
}
else {
A[k]=R[j];
j++;
}
}
// when one of the array is empty u can copy the rest of the array with out compairing
while(i<n1)
A[k++]=L[i++];
while(j<n2)
A[k++]=R[j++];
free(L);
free(R);
}
void MERGE_SORT(int A[], int p, int r)
{
//During first iteration p = 1 & r = 8
if (p < r) {
int q = (p + r) / 2;
MERGE_SORT(A, p, q);
MERGE_SORT(A, q + 1, r);
MERGE(A, p, q, r);
}
}
/* Function to print an array */
void printArray(int Arr[], int size){
int i;
for (i = 0; i < size; i++)
printf("%d ", Arr[i]);
printf("\n");
}`
first of all you were not passing the right parameters to the function.
then the concept of using infinity to indicate is not good as one can want to sort bigger number than that in that case you would have to increase infinity an alternative approach is given above.
Mean while i also solved the problem with your code here it was again with the array index were not rightly used check it out now its working:`
#include<stdlib.h>
#include<stdio.h>
void MERGE(A, p, q, r);
void printArray(Arr, size);
void MERGE_SORT(A, p, r);
int main(void)
{
int A[] = { 12, 11, 13, 5, 6, 7, 2, 9 };
int arr_size = sizeof(A) / sizeof(A[0]);
printf("Given array is \n");
printArray(A, arr_size);
MERGE_SORT(A, 1, arr_size);
printf("\nSorted array is \n");
printArray(A, arr_size);
return 0;
}
void MERGE(int A[], int p, int q, int r)
{
int i = 0;
int j = 0;
int n1 = q - p + 1; //Computing length of sub-array 1
int n2 = r - q; //Computing length of sub-array 2
int *L = malloc((n1+1) * sizeof(*L+1)); //Creating Left array
int *R = malloc((n2+1) * sizeof(*R+1)); //Creating Right array
for (int i = 1; i < n1; i++) {
L[i] = A[p + i - 1];
}
for (int j = 1; j < n2; j++) {
R[j] = A[q + j];
}
L[n1] = 99; //Placing Sentinel at the end of array
R[n2] = 99;
i = 1;
j = 1;
/*Prior to the first iteration k = p, so the subarray is empty.
Both L[i] and R[j] are the smallest elements of their arrays and have not
been copied back to A*/
for (int k = p; k < r; k++) {
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
}
else if (A[k] == L[i])
j++;
}
free(L);
free(R);
}
void MERGE_SORT(int A[], int p, int r)
{
//During first iteration p = 1 & r = 8
if (p < r) {
int q = (p + r) / 2;
MERGE_SORT(A, p, q);
MERGE_SORT(A, q + 1, r);
MERGE(A, p, q, r);
}
}
/* Function to print an array */
void printArray(int Arr[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", Arr[i]);
printf("\n");
}
Related
I have implemented quicksort algorithm in C but I don't know how q and r work in quick_sort function. When the partitioning function returns i which is 1 it assigns this value to q but then for some reason, q becomes 7 and r becomes 0.
int partitioning(int A[10], int p, int r);
void quick_sort(int A[10], int p, int r);
int main() {
int A[10] = { 8, 7, 0, 20, 60, 5, 3, 7, 45, 1}, i;
for (i = 0; i <= 9; i++) {
printf(" %d ", A[i]);
}
printf("\n\nFinal Array\n\n");
quick_sort(A, 0, 9);
for (i = 0; i <= 9; i++) {
printf(" %d ", A[i]);
}
return 0;
}
int partitioning(int A[10], int p, int r) {
int tmp, i, x, j;
x = A[r];
i = p - 1;
for (j = p; j <= r; j++) {
if (A[j] < x) {
i++;
tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
}
i++;
tmp = A[i];
A[i] = A[r];
A[r] = tmp;
return i;
}
void quick_sort(int A[10], int p, int r) {
int q;
printf("%d\n", q);
if (p < r) {
q = partitioning(A, p, r);
quick_sort(A, p, q - 1);
quick_sort(A, q + 1, r);
}
}
I'm getting an error Segmentation Fault:11, please help.
variable info:(s:start, e:end, m:mid, n:array), testing for a sample array n[] = {4,3,2,1}. a1 and a2 are temporary arrays. I am guessing there's something with the calculation of m:mid and passing it.
#include <stdio.h>
void merge(int s, int e, int m, int n[]) {
int l1 = m - s;
int l2 = e - m + 1;
int a1[l1];
int a2[l2];
for (int i = 0; i < l1; i++) {
a1[i] = n[s + i];
}
for (int j = 0; j < l2; j++) {
a2[j] = n[s + m + j];
}
int i = 0, j = 0;
for (int k = 0; k < l1 + l2; k++) {
if (a1[i] <= a2[j] && i != l1 && j != l2) {
n[k] = a1[i];
i++;
} else if (a2[j] <= a1[i] && i != l1 && j != l2) {
n[k] = a2[j];
j++;
} else if (j == l2 && i != l1) {
n[k] = a1[i];
i++;
} else if(i == l1 && j != l2) {
n[k] = a2[j];
j++;
}
}
}
void mergeSort(int s, int e, int n[]) {
if (s < e) {
int m = (e - s) / 2;
mergeSort(s, m - 1, n);
mergeSort(m, e, n);
merge(s, e, m, n);
}
}
int main(void) {
int n[] = { 4, 3, 2, 1 };
int r = 4;
mergeSort(0, r - 1, n);
for(int i = 0; i < r; i++) {
printf("%i\n", n[i]);
}
}
The computation of m for the middle element is bogus: you get the offset of m from s, not its index into the array.
Here is a corrected version:
void mergeSort(int s, int e, int n[]) {
if (s < e) {
int m = s + (e - s + 1) / 2;
mergeSort(s, m - 1, n);
mergeSort(m, e, n);
merge(s, e, m, n);
}
}
There are other issues in your code, notably:
you should check the offsets i and j beforedereferencinga1[i]anda2[j]`.
the offset k should not be used directly in the merge phase, you should store to n[s + k].
in the initialization loop for a2, you should use a2[j] = n[m + j]; instead of a2[j] = n[s + m + j];
Note also that it is idiomatic to pass ranges in C with the first index included and the last index excluded. This allows for passing empty ranges, which your current method does not. It also makes the code much simpler and easier to read.
Here is a modified version:
#include <stdio.h>
void merge(int s, int e, int m, int n[]) {
int l1 = m - s;
int l2 = e - m;
int a1[l1];
int a2[l2];
for (int i = 0; i < l1; i++) {
a1[i] = n[s + i];
}
for (int j = 0; j < l2; j++) {
a2[j] = n[m + j];
}
for (int i = 0, j = 0, k = 0; k < l1 + l2; k++) {
if (i < l1 && (j >= l2 || a1[i] <= a2[j])) {
n[s + k] = a1[i];
i++;
} else {
n[s + k] = a2[j];
j++;
}
}
}
void mergeSort(int s, int e, int n[]) {
if (e > s + 1) {
int m = s + (e - s) / 2;
mergeSort(s, m, n);
mergeSort(m, e, n);
merge(s, e, m, n);
}
}
int main(void) {
int n[] = { 4, 3, 2, 1 };
int r = sizeof(n) / sizeof(n[0]);
mergeSort(0, r, n);
for(int i = 0; i < r; i++) {
printf("%i\n", n[i]);
}
return 0;
}
I've modified your code in several places. Try to use your debugger or pen & paper to understand what's going on under the hood.
void merge(int s, int e, int m, int n[]){
int l1 = m-s + 1;
int l2 = e - m;
int a1[l1];
int a2[l2];
for(int i = 0; i < l1; i++){
a1[i] = n[s+i];
}
for(int j = 0; j < l2; j++){
a2[j] = n[m+j + 1];
}
int i = 0, j = 0;
for(int k = 0; k < l1+l2; k++){
if(a1[i] <= a2[j] && i != l1 && j != l2){
n[k] = a1[i];
i++;
}else if(a2[j] <= a1[i] && i != l1 && j != l2){
n[k] = a2[j];
j++;
}else if(j == l2 && i != l1){
n[k] = a1[i];
i++;
}else if(i == l1 && j != l2){
n[k] = a2[j];
j++;
}
}
}
void mergeSort(int s, int e, int n[]){
if(s<e){
int m = s + (e-s)/2;
mergeSort(s, m, n);
mergeSort(m + 1, e, n);
merge(s,e,m, n);
}
You will be fine I guess.
I think you have a stack overflow problem because of infinite recursive calls. Look
void mergeSort(int s, int e, int n[]){
if(s<e){
int m = (e-s)/2;
mergeSort(s, m-1, n);
mergeSort(m, e, n);
merge(s,e,m, n);
}
}
You pass these values of s and e:
s e function
-------------
0 3 mergeSort
0 0 mergeSort -> end
1 3 mergeSort
0 0 mergeSort -> end
1 3 mergeSort
... (infinite calls)
Then the stack grows and grows while new functions called until in the end it exceeds the maximum possible size, which leads to SEGFAULT.
So I was looking at the C example of merge sort on Rosetta Code and I'm a bit confused about how the merge() function works. I think it is the syntax they use that throws me off with the colons and ?'s.
void merge (int *a, int n, int m) {
int i, j, k;
int *x = malloc(n * sizeof (int));
for (i = 0, j = m, k = 0; k < n; k++) {
x[k] = j == n ? a[i++]
: i == m ? a[j++]
: a[j] < a[i] ? a[j++]
: a[i++];
}
for (i = 0; i < n; i++) {
a[i] = x[i];
}
free(x);
}
void merge_sort (int *a, int n) {
if (n < 2)
return;
int m = n / 2;
merge_sort(a, m);
merge_sort(a + m, n - m);
merge(a, n, m);
}
What exactly is happening in the for loop of the merge() function? Can someone explain it please?
Read the comments:
void merge (int *a, int n, int m) {
int i, j, k;
// inefficient: allocating a temporary array with malloc
// once per merge phase!
int *x = malloc(n * sizeof (int));
// merging left and right halfs of a into temporary array x
for (i = 0, j = m, k = 0; k < n; k++) {
x[k] = j == n ? a[i++] // right half exhausted, take from left
: i == m ? a[j++] // left half exhausted, take from right
: a[j] < a[i] ? a[j++] // right element smaller, take that
: a[i++]; // otherwise take left element
}
// copy temporary array back to original array.
for (i = 0; i < n; i++) {
a[i] = x[i];
}
free(x); // free temporary array
}
void merge_sort (int *a, int n) {
if (n < 2)
return;
int m = n / 2;
// inefficient: should not recurse if n == 2
// recurse to sort left half
merge_sort(a, m);
// recurse to sort right half
merge_sort(a + m, n - m);
// merge left half and right half in place (via temp array)
merge(a, n, m);
}
A simpler and more efficient version of the merge function, using only half as much temporary space:
static void merge(int *a, int n, int m) {
int i, j, k;
int *x = malloc(m * sizeof (int));
// copy left half to temporary array
for (i = 0; i < m; i++) {
x[i] = a[i];
}
// merge left and right half
for (i = 0, j = m, k = 0; i < m && j < n; k++) {
a[k] = a[j] < x[i] ? a[j++] : x[i++];
}
// finish copying left half
while (i < m) {
a[k++] = x[i++];
}
}
A faster version of merge_sort involves allocating a temporary array x of size n * sizeof(*a) and passing it to a recursive function merge_sort1 that calls merge with as extra parameter as well. The logic in merge is also improved here with half as many comparisons on i and j:
static void merge(int *a, int n, int m, int *x) {
int i, j, k;
for (i = 0; i < m; i++) {
x[i] = a[i];
}
for (i = 0, j = m, k = 0;;) {
if (a[j] < x[i]) {
a[k++] = a[j++];
if (j >= n) break;
} else {
a[k++] = x[i++];
if (i >= m) return;
}
}
while (i < m) {
a[k++] = x[i++];
}
}
static void merge_sort1(int *a, int n, int *x) {
if (n >= 2) {
int m = n / 2;
if (n > 2) {
merge_sort1(a, m, x);
merge_sort1(a + m, n - m, x);
}
merge(a, n, m, x);
}
}
void merge_sort(int *a, int n) {
if (n < 2)
return;
int *x = malloc(n / 2 * sizeof (int));
merge_sort1(a, n, x);
free(x);
}
i've already sought information for the quick-sort algorithm. But i still can not realize it on C. I'm trying but the Quicksort function doesn't work at all. I Can't find errors in my code. Please, help me to understand what's going on.
#include <stdio.h>
#include <stdlib.h>
void swap(int a, int b)
{
int temp = 0;
temp = a;
a = b;
b = temp;
}
int Partition(int p , int r, int A[r - p + 1])
{
int j = 0;
int x = A[r - 1];
int i = p - 1;
for(j = p - 1; j < r - 1; j++) {
if(A[j] <= x) {
i = i + 1;
swap(A[i], A[j]);
}
}
swap(A[i], A[r - 1]);
return i + 1;
}
void Quicksort(int p, int r, int A[r - p + 1])
{
int q = 0;
if((p - 1) < (r - 1)) {
q = Partition(p ,r , A);
Quicksort(p, q - 1, A);
Quicksort(q + 1, r, A);
}
}
int main(int argc, char *argv[])
{
int A[] = {10, 5, 1, 3, 9, 2, 4, 8, 7, 6};
int i = 0;
int length = sizeof(A) / sizeof(int);
Quicksort(1, length , A);
for(i = 0; i < length; i ++) {
printf("%d ", A[i]);
}
printf("\n");
return 0;
}
You have to pass the values as pointers to the swap function
void swap(int *a, int *b)
{
int temp = 0;
temp = *a;
*a = *b;
*b = temp;
}
and then change
swap(A[i], A[j]);
to
swap(&A[i], &A[j]);
and
swap(A[i], A[r - 1]);
to
swap(&A[i], &A[r - 1]);
So my problem is, when I try to run my merge sort algorithm, it writes the random array on screen but when it tries to write the sorted array, the program stops working. I've been trying find my error but no hope so far. Appreciate any help.
Here is my code;
#include <stdio.h>
#include <stdlib.h>
#define LEN 300
#define INF 30000
void merge (int *A, int p, int q, int r){
int i, j, k, n1 , n2 , *L, *R;
n1 = q - p + 1;
n2 = r - q;
L = (int *) malloc (n1* sizeof (int ) + 1);
R = (int *) malloc (n2* sizeof (int )) ;
for (i = 0; i < n1; i++) {
L[i] = A[p + i];
}
for (j = 0; j < n2; j++) {
R[j] = A[q + 1 + j];
}
i = j = 0;
L[n1] = R[n2] = INF ;
for (k = p; k < r; k++) {
if(L[i] <= R[j]){
A[k] = L[i];
i ++;
}
else{
A[k] = R[j];
j ++;
}
}
free(L);
free(R);
}
void mergesort (int *A, int p, int r){
int q;
if(r > (p + 1)){
q = (p + r)/2;
mergesort(A, p, q);
mergesort(A, q + 1, r);
merge(A, p, q, r);
}
}
void sorting_merge(int *A, int n){
mergesort (A, 0, LEN);
}
int main (){
int i, *n;
n = malloc ( sizeof (int )*LEN );
srand (666) ;
for (i = 0; i < LEN ; i++) {
n[i] = rand() % 1000;
printf ("%d ", n[i]);
}
printf ("\n");
sorting_merge(n, LEN);
for (i = 0; i < LEN ; i++) {
printf ("%d ", n[i]);
}
printf ("\n");
free (n);
system("PAUSE");
return 1;
}
change to
L = (int *) malloc((n1+1)* sizeof(int));
R = (int *) malloc((n2+1)* sizeof(int));
for (k = p; k <= r; k++) {//include r
if(r > p){
void sorting_merge(int *A, int n){//call sorting_merge(n, LEN); note LEN is out range
mergesort (A, 0, n-1);
}
L[n1] = R[n2] = INF ; accesses beyond the allocated memory. Your allocation should read
L = malloc((n1 + 1) * sizeof (int));
R = malloc((n2 + 1) * sizeof (int));
if you really want to access index n1 and n2.
I haven't checked anything else, that was the first thing that sprang in my eyes.