This is my quicksort algorithm, including partition and swap. Works well, when I'm choosing as a pivot the last element of the array (in function quicksort: int r = partition(a, n, n);), but fails when taking the first: int r = partition(a, n, s);
void Swap(int a[], int l, int r){
int tmp = a[l];
a[l] = a[r];
a[r] = tmp;
}
int partition(int a[], int n, int p) {
Swap(a, p, n);
int l = 0;
for (int i = 1; i <= n - 1; i++) {
if (a[i] <= a[n]) {
l += 1;
Swap(a, l, i);
}
}
Swap(a, p, l + 1);
return l + 1;
}
void quicksort(int a[], int s, int n) {
if (s < n) {
int r = partition(a, n, n);
quicksort(a, s, r - 1);
quicksort(a, r + 1, n);
}
}
Yes, the problem was with the partition procedure, this one is correct:
int partition(int a[], int p, int r) {
int t = a[r];
int i = p - 1;
for (int j = p; j < r;j++){
if (a[j] <= t) {
i += 1;
std::swap(a[i], a[j]);
}
}
std::swap(a[i + 1], a[r]);
return i + 1;
}
Related
I am working on a parallelized algorithm finding the k-th smallest number in an array using OpenMP. Basically, I have a sequential algorithm that is based on quicksort and it works just fine.
//K'th smallest element in arr[l..r]
int kthSmallest(int arr[], int l, int r, int k)
{
if (k > 0 && k <= r - l + 1) {
int pos = partition(arr, l, r);
if (pos - l == k - 1)
return arr[pos];
if (pos - l > k - 1) {
return kthSmallest(arr, l, pos - 1, k);
} else {
return kthSmallest(arr, pos + 1, r, k - pos + l - 1);
}
}
return INT_MAX;
}
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int partition(int arr[], int l, int r)
{
int x = arr[r], i = l;
for (int j = l; j <= r - 1; j++) {
if (arr[j] <= x) {
swap(&arr[i], &arr[j]);
i++;
}
}
swap(&arr[i], &arr[r]);
return i;
}
I am new to OpenMP. At first, I tried to parallelize the area of the function call itself in driver, unfortunately, it didn't work. The number drawn was correct, but it wasn't faster than sequential.
int main()
{
omp_set_num_threads(8);
double start_time, run_time;
int *data = (int *)malloc(N * sizeof(int));
clock_t start, end;
printf("Creating the array.......\n");
randomArray(data, N);
printf("Created the array........\n");
//start = clock();
start_time = omp_get_wtime();
#pragma omp parallel
{
#pragma omp single nowait
printf("\nKth [%d] value is %d\n", K,
kthSmallest(data, 0, N - 1, K));
}
//end = clock();
run_time = omp_get_wtime() - start_time;
When trying to parallelize the partition function itself, the timing improves, but the selected number is different each time.
int partition(int arr[], int l, int r)
{
int j;
int x = arr[r], i = l;
#pragma omp parallel for shared(arr, l, r) private(j) schedule(static)
for ( j = l; j <= r - 1; j++) {
if (arr[j] <= x) {
swap(&arr[i], &arr[j]);
i++;
}
}
swap(&arr[i], &arr[r]);
return i;
}
What's wrong with my idea, how could I parallelize this algorithm correctly?
Hello I am working on an application of the merge sort algorithm however after a few hours I am unable to find a solution. Any help or hint would be appreciated. I have tried to debug my code but after many attempts I have not been successful in seeing what the mistake is.
The problem is that the algorithm gives back a wrong result. Example:
input: (10, 5, 16, 2)
output: (2, 5, 5, 10)
#include <stdio.h>
void mergesort(int A[], int l, int r);
void merge(int A[], int l, int q, int r);
int main() {
int n;
scanf("%d", &n);
int tablica[n];
for (int i = 0; i < n; i++)
scanf("%d", &tablica[i]);
mergesort(tablica, 0, n - 1);
for (int i = 0; i < n; i++)
printf("%d ", tablica[i]);
return 0;
}
void mergesort(int A[], int l, int r) {
if (l < r) {
int q = (l + r) / 2;
mergesort(A, l, q);
mergesort(A, q + 1, r);
merge(A, l, q, r);
}
}
void merge(int A[], int l, int q, int r) {
int n = q - l + 1;
int m = r - q;
int B[n];
int C[m];
for (int i = 0; i < n; i++)
B[i] = A[i];
for (int i = 0; i < m; i++)
C[i] = A[q + 1 + i];
int i = 0;
int j = 0;
for (int k = l; k <= r; k++) {
if (B[i] <= C[j] || j >= m) {
A[k] = B[i];
i++;
} else {
A[k] = C[j];
j++;
}
}
}
Without knowing what exactly doesn't work (Does it not compile? Do you get wrong output for some inputs?) it's hard to help. At least one error is here:
if(B[i] <= C[j] || j >= m)
Should be
if(j >= m || i < n && B[i] <= C[j])
It is both important to check j >= m before you check the inequality, and add the i < n check.
Without the latter once you fully consume the B array, B[i] will go beyond the array boundaries, and you will get undefined behavior.
Without the former once j >= m the condition B[i] <= C[j] will be checked before j >= m, also triggering undefined behavior.
UPDATE: with the actual example you provided, the second error narrows down to replacing B[i] = A[i] with B[i] = A[l + i]. With these two changes the example you provided works.
The function merge has several bugs.
For example the size of the array C shall be calculated like
int m = r - q + 1;
instead of
int m = r - q;
Instead of this for loop
for(int i = 0; i < n; i++)
B[i] = A[i];
you have to write
for(int i = 0; i < n; i++)
B[i] = A[l + i];
This if statement
if(B[i] <= C[j] || j >= m)
can result in undefined behavior because there is no check of the validity of the used indices i and j whether they belong to the valid ranges.
The functions can be defined the following way as it is shown in the demonstrative program below.
#include <stdio.h>
void merge( int a[], size_t left, size_t middle, size_t right )
{
size_t n1 = middle - left;
size_t n2 = right - middle;
int a1[n1];
int a2[n2];
for ( size_t i = 0; i < n1; i++ )
{
a1[i] = a[left + i];
}
for ( size_t i = 0; i < n2; i++ )
{
a2[i] = a[middle + i];
}
size_t i = left, i1 = 0, i2 = 0;
while ( i1 < n1 && i2 < n2 )
{
a[i++] = a2[i2] < a1[i1] ? a2[i2++] : a1[i1++];
}
while ( i1 < n1 ) a[i++] = a1[i1++];
while ( i2 < n2 ) a[i++] = a2[i2++];
}
void mergesort( int a[], size_t left, size_t right )
{
if ( left + 1 < right )
{
size_t middle = ( left + right ) / 2;
mergesort( a, left, middle );
mergesort( a, middle, right );
merge( a, left, middle, right );
}
}
int main(void)
{
size_t n;
if ( scanf( "%zu", &n ) == 1 && n != 0 )
{
int a[n];
for ( size_t i = 0; i < n; i++ ) scanf( "%d", a + i );
mergesort( a, 0, n );
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
}
return 0;
}
If the input is
4
10 5 16 2
then the output will be
2 5 10 16
There is a bug in the merge function:
if (B[i] <= C[j] || j >= m) accesses B[i] and C[j] before testing if i and j are below their respective boundaries. The test should be:
if (i < n && (j >= m || B[i] <= C[j])) {
A[k] = B[i++];
} else {
A[k] = C[j++];
}
Note also these remarks:
you do not need to save the second half of the array because its elements are copied before they get overwritten.
in void mergesort(int A[], int l, int r) r should be excluded, to avoid confusing and error prone +1/-1 adjustments.
similarly, in void merge(int A[], int l, int q, int r), q should be the start of the second half and r the index of the element after the end of the slice.
l looks confusingly similar to 1
Here is a modified version:
#include <stdio.h>
void mergesort(int A[], int low, int high);
void merge(int A[], int low, int mid, int high);
int main() {
int n;
if (scanf("%d", &n) != 1 || n <= 0)
return 1;
int tablica[n];
for (int i = 0; i < n; i++) {
if (scanf("%d", &tablica[i]) != 1)
return 1;
}
mergesort(tablica, 0, n);
for (int i = 0; i < n; i++)
printf("%d ", tablica[i]);
printf("\n");
return 0;
}
void mergesort(int A[], int low, int high) {
if (high - low >= 2) {
int mid = low + (high - low) / 2;
mergesort(A, low, mid);
mergesort(A, mid, high);
merge(A, low, mid, high);
}
}
void merge(int A[], int low, int mid, int high) {
int n = mid - low;
int B[n];
for (int i = 0; i < n; i++)
B[i] = A[low + i];
int i = 0;
int j = mid;
int k = low;
while (i < n) {
if (j >= high || B[i] <= A[j]) {
A[k++] = B[i++];
} else {
A[k++] = C[j++];
}
}
}
I have this code for quicksort
int sum = 0;
int partition(int *L, int left, int right) {
int pivot = left;
int p_val = L[pivot];
while (left < right) {
while (L[left] <= p_val)
left++;
while (L[right] > p_val)
right--;
if (left < right) {
swap(&L[left], &L[right]);
sum++;
}
}
swap(&L[pivot], &L[right]);
sum++;
return right;
}
void quicksort(int *L, int start, int end) {
if (start >= end)
return;
int splitPoint = partition(L, start, end);
quicksort(L, start, splitPoint - 1);
quicksort(L, splitPoint + 1, end);
}
And it works fine, I think. For given array {8,4,2,1} I get that 3 swaps have been made. BUT, I need to modify the code so that function RETURNS number of swaps. Is this possible, and if so, how? Please explain as simply as you can because I'm a novice in this. I need to do the same with mergeSort but I still haven't found working code that isn't too complicated. When I do, I'll update the question. Thank you.
You can use the int pointer as the argument of partition and quicksort functions:
int partition(int *num, int *L, int left, int right) {
...
if (left < right) {
swap(&L[left], &L[right]);
(*num)++; // increment number of swap
sum++;
}
}
...
swap(&L[pivot], &L[right]);
(*num)++;
sum++;
return right;
}
And in the quicksort function:
void quicksort(int *num, int *L, int start, int end) {
if (start >= end)
return;
int splitPoint = partition(num, L, start, end);
quicksort(num, L, start, splitPoint - 1);
quicksort(num, L, splitPoint + 1, end);
}
Then in main function:
int main()
{
int arr[] = {8, 4, 2, 4, 5, 7, 8, 9, 1};
int n = sizeof(arr)/sizeof(arr[0]);
int num = 0;
quicksort(&num, arr, 0, n-1);
printf("sum = %d num = %d\n", sum, num);
return 0;
}
Okay now I have this:
int sum = 0;
int partition(int *L, int left, int right) {
int pivot = left;
int p_val = L[pivot];
while (left < right) {
while (L[left] <= p_val)
left++;
while (L[right] > p_val)
right--;
if (left < right) {
swap(&L[left], &L[right]);
sum++;
}
}
swap(&L[pivot], &L[right]);
sum++;
return right;
}
int quicksort(int *L, int start, int end) {
if (start >= end)
return;
int splitPoint = partition(L, start, end);
quicksort(L, start, splitPoint - 1);
quicksort(L, splitPoint + 1, end);
return sum;
}
for QuickSort, and this:
int sumMerge = 0;
void merge(int arr[], int l, int m, int r) {
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
int L[n1], R[n2];
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
}
else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
int mergeSort(int arr[], int l, int r){
if (l < r) {
int m = l + (r - l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
return sumMerge;
}
for MergeSort. Is this correct? I mean, if I put sumMerge++ somewhere in the code, will this be ok?
Also, what part of code actually swaps the values in merge? In quicksort I figured it was kind of obvious, wherever swap gets called, that's where I increase the counter. But what about merge?
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");
}
I need help to write this code into pseudocode
public void quickSort(int[] A, int p, int r) {
if (p < r) {
int q = partition(A, p, r);
quickSort(A, p, q);
quickSort(A, q + 1, r);
}
}
private int partition(int[] A, int p, int r) {
int x = A[p]; // pivot element x
int i = p - 1;
int j = r + 1;
// partition
while (true) {
do {
j--;
} while (A[j] > x);
do {
i++;
} while (A[i] < x);
if (i < j)
swap(A, i, j);
else
return j;
}
}
private void swap(int[] A, int i, int j) {
int tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
}
for each (unsorted) partition
set first element as pivot
storeIndex = pivotIndex + 1
for i = pivotIndex + 1 to rightmostIndex
if element[i] < element[pivot]
swap(i, storeIndex); storeIndex++
swap(pivot, storeIndex - 1)