Why this program to sort array doesnt work? - arrays

Im trying to learn C and I'm doing this program to sort an array but It doesn't work and I'm not sure why, I tested each function and works well, someone knows if its a problem of variables or something?
#include <stdio.h>
#include <stdlib.h>
#define N 5
int V[5] = { -383, 386, 277, 415, 293 };
void displayArray(int arr[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", arr[i]);
}
int maxim(int v[], int n)
{
int i, m;
m = v[0];
/*
Find maxim element
*/
for (i = 1; i < n; i++)
if (v[i] > m)
m = v[i];
/*
Search element position
*/
for (i = 0; i < N; i++)
if (v[i] == m)
return i;
}
void sort(int v[], int n)
{
int i, pos, t;
for (i = 0; i < n; i++)
pos = maxim(v, n - i);
/*
Swap elements
*/
t = v[n - 1 - i];
v[n - 1 - i] = v[pos];
v[pos] = t;
}
int main()
{
displayArray(V, N);
sort(V, N);
printf("\n");
displayArray(V, N);
return 0;
}
The output is
-383 386 277 415 293 - Original Array
21900 386 277 415 293 - 'Sorted' Array

First fix your maxim function. Its purpose is to find the maximum index of a sequence v of magnitude n. Therefore, remembering the maximum value in m is irrelevant; you want to remember where it resides :
int maxim(int v[], int n)
{
int m=0;
for (int i=1; i<n; ++i)
{
if (v[m] < v[i])
m = i; // save new max location
}
return m;
}
After that, the sort, which is completely wrong. This:
int i, pos, t;
for (i = 0; i < n; i++)
pos = maxim(v, n - i);
is pointless. It calculates, and overwrites, pos repeatedly until the last iteration, which is the only one that is processed with:
t = v[n - 1 - i];
v[n - 1 - i] = v[pos];
v[pos] = t;
E..g, you sort one element, and then exit your sort. You need to sort them all, starting with the full segment, then reducing the size of the segment by one with each iteration after you swap the most-maximum element into position for that segment.
void sort(int v[], int n)
{
for (int i=0; i<(n-1); ++i)
{
int m = maxim(v, (n-i)); // max of this segment
int tmp = v[m];
v[m] = v[n-i-1];
v[n-i-1] = tmp;
}
}

Your program is inefficient, but almost correct. The only place where you must focus is:
void sort(int v[], int n)
{
int i, pos, t;
for (i = 0; i < n; i++)
pos = maxim(v, n - i);
/*
Swap elements
*/
t = v[n - 1 - i];
v[n - 1 - i] = v[pos];
v[pos] = t;
}
Well, C is not Python, so if, after getting pos you want to swap the elements of your array, then you need to group all of the for loop in braces, as in:
void sort(int v[], int n)
{
int i, pos, t;
for (i = 0; i < n; i++) {
pos = maxim(v, n - i);
/*
Swap elements
*/
t = v[n - 1 - i];
v[n - 1 - i] = v[pos];
v[pos] = t;
}
}

pos = maxim(v, n - i);
should be
pos = maxim(v, n);

Related

Implementing Selection Sort in C

I am trying to implement the Selection Sort Algorithm and here is my attempt:
int select(int arr[], int i)
{
int j, minIndex;
minIndex = i;
for (j = i + 1; arr[j]; j++)
{
if (arr[j] < arr[minIndex])
minIndex = j;
}
return minIndex;
}
void selectionSort(int arr[], int n)
{
int i, iMin;
for (i = 0; i < n - 1; i++)
{
iMin = select(arr, i);
if (iMin != i)
{
int temp = arr[i];
arr[i] = arr[iMin];
arr[iMin] = temp;
}
}
}
Even though my code works fine, if there is an element in the array with value zero it fails. Here is an example case:
4 1 3 9 0
Output:
1 3 4 9 0
I know that my logic is correct, because it works with other cases, but why is it failing if there is a 0 in the array element?
Your loop condition is wrong:
for (j = i + 1; arr[j]; j++)
instead of arr[j] you need j < n.
Renamed select() to selectMin() to avoid conflict with existing function with that name. If you specify the length n before the array arr your can document how the two are related with current compilers.
Extracted the swap() function.
Minimized scope of variables.
size_t instead of int for indices as they are non-negative. The type difference also helps you distinguish between the indices of the array (size_t) the values of the array (int) which was the root cause of your troubles.
Hard-coded your test case and implemented a print() functions to verify correct result.
#include <stdio.h>
#include <stdlib.h>
void print(size_t n, int a[n]) {
for(size_t i = 0; i < n; i++)
printf("%d%s", a[i], i + 1 < n ? ", " : "\n");
}
size_t selectMin(size_t n, int arr[n], int i) {
size_t minIndex = i;
for (size_t j = i + 1; j < n; j++)
if (arr[j] < arr[minIndex])
minIndex = j;
return minIndex;
}
void selectionSort(size_t n, int arr[n]) {
for (size_t i = 0; i < n - 1; i++) {
size_t iMin = selectMin(n, arr, i);
if (iMin != i)
swap(arr + i, arr + iMin);
}
}
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int main(void) {
int a[] = {4, 1, 3, 9, 0};
selectionSort(sizeof a / sizeof *a, a);
print(sizeof a / sizeof *a, a);
}
and the output is:
0, 1, 3, 4, 9
The loop
for (j = i + 1; arr[j]; j++)
is problematic because of the loop condition arr[j]. As a condition it's equivalent to arr[j] != 0. C doesn't have any concept of "null values" like e.g. C# or Java.
You need to pass the array length to the select function, you can't rely on the array data itself to know when and where the array ends.
Using the array data itself will either lead to premature loop end if the data contains zeros. Or will go out of bounds if the array data doesn't contain any zeros.

Recursive mergesort in C not modifying the original array

I am implementing merge sort in C. I have a merge function - merge(int array[], int start, int middle, int end) and a mergeSort function - mergeSort(int *array, unsigned int size).
The merge sort works perfectly if the first half of the original array and the second half of the original array are sorted (ex: 5,6,7,8,1,2,3,4). This is because my merge function is getting passed the original array no matter what, and it works when it is given 2 sorted arrays (as expected). My issue is when they aren't. Every time I call merge, my original array isn't being modified, even though I have programmed it to do so. Can anyone figure out where my issue is? The code is below.
When I run this code on input {10,9,8,7,6,5,4,3,2,1} it returns {5,4,3,2,1,0,10,9,8,7,6}.
void merge(int arr[], int l, int m, int r) {
int size1 = m - l + 1;
int size2 = r - m;
int arr1[size1];
int arr2[size2];
int i;
for ( i = 0; i < size1; i++ ) {
arr1[i] = arr[l + i];
}
for ( i = 0; i < size2; i++ ) {
arr2[i] = arr[m + i + 1];
}
i = 0;
int j = 0;
int k = 0;
while ( i < size1 && j < size2 ) {
if ( arr1[i] < arr2[j] ) {
arr[k] = arr1[i];
i++;
k++;
} else {
arr[k] = arr2[j];
j++;
k++;
}
}
while ( i < size1 ) {
arr[k] = arr1[i];
i++;
k++;
}
while ( j < size2 ) {
arr[k] = arr2[j];
j++;
k++;
}
}
void mergeSort(int *array, unsigned int size) {
int start = 0;
int middle = (size / 2) - 1;
int end = size - 1;
if ( size < 2 ) {
return;
}
int m = ( size / 2 );
int arr1[m];
int arr2[size - m];
int i;
for ( i = 0; i < middle + 1; i++ ) {
arr1[i] = array[i];
printf("%d\n", arr1[i]);
}
for ( i = middle + 1; i < size; i++ ) {
arr2[i - (middle + 1)] = array[i];
}
mergeSort(arr1, m);
mergeSort(arr2, size - m);
merge(array, start, middle, end);
}
In mergeSort, after doing mergeSort(arr1, m) and mergeSort(arr2, size - m), you are not actually doing anything with arr1 and arr2.
For a simple fix, I suggest not using the variables arr1 and arr2 and calling mergeSort directly on parts of array, like so:
void mergeSort(int* array, unsigned int size) {
int start = 0;
int middle = (size / 2);
int end = size - 1;
if ( size < 2 ) {
return;
}
mergeSort(array, middle);
mergeSort(array + middle, size - middle);
merge(array, start, middle - 1, end);
}
There are multiple issues in your code:
the mergeSort function splits the array into 2 local arrays and calls itself recursively to sort them, but the merge phase does not take these sorted arrays as inputs. You should instead use portions of the argument array directly.
the size computations are cumbersome, with many adjustments that would pose problems for small values of size. Use a simple convention: pass end as the offset of the first element past the end of the array. This way the size is computing simply by subtracting start from end.
the merge function initializes k to 0 instead of l.
Here is a corrected version:
void merge(int arr[], int start, int m, int end) {
int size1 = m - start;
int size2 = end - m;
int arr1[size1];
int arr2[size2];
int i, j, k;
for (i = 0; i < size1; i++) {
arr1[i] = arr[start + i];
}
for (i = 0; i < size2; i++) {
arr2[i] = arr[m + i];
}
i = j = 0;
k = start;
while (i < size1 && j < size2) {
if (arr1[i] < arr2[j]) {
arr[k++] = arr1[i++];
} else {
arr[k++] = arr2[j++];
}
}
while (i < size1) {
arr[k++] = arr1[i++];
}
while (j < size2) {
arr[k++] = arr2[j++];
}
}
void mergeSort(int *array, unsigned int size) {
if (size >= 2) {
int m = size / 2;
mergeSort(array, m);
mergeSort(array + m, size - m);
merge(array, 0, m, size);
}
Bob__ suggested a simplification, saving only the first half of the array to arr1 and removing the need for arr2. Here is a modified version, also removing start which is always 0 and some other simplifications:
void merge(int arr[], size_t m, size_t size) {
int arr1[m];
size_t i, j, k;
for (i = j = k = 0; j < m; j++) {
arr1[j] = arr[j];
}
while (i < m && j < size) {
if (arr1[i] < arr[j]) {
arr[k++] = arr1[i++];
} else {
arr[k++] = arr[j++];
}
}
while (i < m) {
arr[k++] = arr1[i++];
}
}
void mergeSort(int *array, size_t size) {
if (size >= 2) {
size_t m = size / 2;
mergeSort(array, m);
mergeSort(array + m, size - m);
merge(array, m, size);
}
Note however that allocating arr1 with automatic storage, aka on the stack, may cause undefined behavior for large arrays, typically larger than a few hundreds of thousand of elements. Allocating a temporary array from the heap avoid this problem at the cost of extra overhead and the possibility for allocation failure.
Sorted merge on every recursive is done on local array created on stack and it is not carry forwarded to previous function call. End result of entire recursive call is nothing but merge of {10,9,8,7,6} and {5,4,3,2,1}.
You can find the debug verification here.
Note: output has variation in my debug code as caller of mergeSort can have different implementation
Updated snippet as follows,
#include <stdio.h>
void merge(int arr[], int l, int m, int r) {
int size1 = m - l;
int size2 = r - m;
int arr1[size1];
int arr2[size2];
int i;
for ( i = 0; i < m; i++ ) {
arr1[i] = arr[l + i];
}
for ( i = 0; i+m < r; i++ ) {
arr2[i] = arr[m + i ];
}
i = 0;
int j = 0;
int k = 0;
while ( i < size1 && j < size2 ) {
if ( arr1[i] < arr2[j] ) {
arr[k++] = arr1[i++];
} else {
arr[k++] = arr2[j++];
}
}
while ( i < size1 ) {
arr[k++] = arr1[i++];
}
while ( j < size2 ) {
arr[k++] = arr2[j++];
}
}
void mergeSort(int* array, unsigned int size) {
if ( size < 2 ) {
return;
}
int start = 0;
int middle = (size / 2);
int end = size;
mergeSort(array, middle);
mergeSort(&array[middle], end-middle);
merge(array, start, middle, end);
}
int main()
{
int a[] = {10,9,8,7,6,5,4,3,2,1};
const int size = sizeof(a)/sizeof(a[0]);
mergeSort(a,size);
for(int i=0;i<size;i++)
printf("%d ", a[i]);
}
output : 1 2 3 4 5 6 7 8 9 10

Get the sorted indices of an array using quicksort

I have changed to quicksort code to sort an array of floats which I got from tutorialgatway.org. However I need the sorted indices. I am aware of the qsort library function that can be used to get the sorted indices and I can implement that. However, I want to avoid standard library (I know this is not recommendation). The reason for not using a standard library is that I need to sort large number of arrays in a loop, which I need to parallelize using openMP, therefore writing function explicitly would allow me to parallelize quicksort function in a loop.
/* C Program for Quick Sort */
#include <stdio.h>
void Swap(float *x, float *y) {
float Temp;
Temp = *x;
*x = *y;
*y = Temp;
}
void quickSort(float a[], int first, int last) {
int i, j;
int pivot;
if (first < last) {
pivot = first;
i = first;
j = last;
while (i < j) {
while (a[i] <= a[pivot] && i < last)
i++;
while (a[j] > a[pivot])
j--;
if (i < j) {
Swap(&a[i], &a[j]);
}
}
Swap(&a[pivot], &a[j]);
quickSort(a, first, j - 1);
quickSort(a, j + 1, last);
}
}
int main() {
int number, i;
float a[100];
printf("\n Please Enter the total Number of Elements : ");
scanf("%d", &number);
printf("\n Please Enter the Array Elements : ");
for (i = 0; i < number; i++)
scanf("%f", &a[i]);
quickSort(a, 0, number - 1);
printf("\n Selection Sort Result : ");
for (i = 0; i < number; i++) {
printf(" %f \t", a[i]);
}
printf("\n");
return 0;
}
How can I return the sorted indices in the code ?
You need to generate an array of indexes from 0 to size-1, then sort the array of indexes according to the array values. So the code does compares using array[index[...]], and does swaps on index[...].
An alternative is to generate an array of pointers from &array[0] to &array[size-1]. When the pointers are sorted, you can convert them to indexes by using: index[i] = pointer[i] - &array[0] (could use a union for the indexes and pointers).
Example program with standard version of Hoare partition scheme to sort array of indexes in I[] according to floats in A[]:
#include <stdio.h>
#include <stdlib.h>
void QuickSort(float A[], size_t I[], size_t lo, size_t hi)
{
if (lo < hi)
{
float pivot = A[I[lo + (hi - lo) / 2]];
size_t t;
size_t i = lo - 1;
size_t j = hi + 1;
while (1)
{
while (A[I[++i]] < pivot);
while (A[I[--j]] > pivot);
if (i >= j)
break;
t = I[i];
I[i] = I[j];
I[j] = t;
}
QuickSort(A, I, lo, j);
QuickSort(A, I, j + 1, hi);
}
}
#define COUNT (4*1024*1024) // number of values to sort
int main(int argc, char**argv)
{
int r; // random number
size_t i;
float * A = (float *) malloc(COUNT*sizeof(float));
size_t * I = (size_t *) malloc(COUNT*sizeof(size_t));
for(i = 0; i < COUNT; i++){ // random floats
r = (((rand()>>4) & 0xff)<< 0);
r += (((rand()>>4) & 0xff)<< 8);
r += (((rand()>>4) & 0xff)<<16);
r += (((rand()>>4) & 0xff)<<24);
A[i] = (float)r;
}
for(i = 0; i < COUNT; i++) // array of indexes
I[i] = i;
QuickSort(A, I, 0, COUNT-1);
for(i = 1; i < COUNT; i++){
if(A[I[i-1]] > A[I[i]]){
printf("error\n");
break;
}
}
free(I);
free(A);
return(0);
}
This version of quicksort avoids stack overflow by only using recursion of the smaller side of the partition. Worst case time complexity will still be O(n^2), but the stack space complexity is limited to O(log(n)).
void QuickSort(float A[], size_t I[], size_t lo, size_t hi)
{
while (lo < hi)
{
float pivot = A[I[lo + (hi - lo) / 2]];
size_t t;
size_t i = lo - 1;
size_t j = hi + 1;
while (1)
{
while (A[I[++i]] < pivot);
while (A[I[--j]] > pivot);
if (i >= j)
break;
t = I[i];
I[i] = I[j];
I[j] = t;
}
/* avoid stack overflow */
if((j - lo) < (hi - j)){
QuickSort(A, I, lo, j);
lo = j+1;
} else {
QuickSort(A, I, j + 1, hi);
hi = j;
}
}
}

Trouble using pointers to sort array in C

I'm working on a program for class. We are using pointers. We had to generate an array with the number of elements being determined by the user (using malloc). I got that part all working. Second we had to sort the array in descending order. I have no clue why I cant get this to work. This code flips the whole array, so that 3 4 5 12 5 becomes 5 12 5 4 3, but that is not what I want. I'm sure it's something small, but for the life of me I cant figure out what I'm doing wrong.
void main()
{
int *p, *sizearray, *q;
int i, siz;
printf("How large do you want the array? Enter a number between 0 and 50\n");
scanf("%d", &siz);
if (siz <= 50)
{
p = genarr(siz);
for (i = 0; i <siz; i++)
printf("%i\n", *(p + i));
arrsort(p,siz);
for (i = 0; i <siz; i++)
printf("%i\n", *(p + i));
}
else
printf("That number was not in the given range");
while(1);
}
#include "stdafx.h"
#include <time.h> // required for the time_t structure
#include <stdlib.h> // Reqwuired for the srand() and rand() functions
#include "ArrEdit.h"
int* genarr(int size)
{
time_t t;
int i, m;
int *sizearr;
sizearr = (int*)malloc(sizeof(int)*size);
srand((unsigned)time(&t));
for (i = 0; i<size; i++)
*(sizearr + i) = rand() % 50;
return sizearr;
free(sizearr);
}
int *arrsort(int*prt, int si)
{
int k, j;
int temp; // holding variable
for (k = 0; k< (si - 1); k++) // element to be compared
for (j = (k + 1); j < si; j++) // rest of the elements
{
swap(&prt[k], &prt[j]);
}
return prt;
}
void swap(int *s, int *r)
{
int pSwap = *r;
*r = *s;
*s = pSwap;
}
for (j = (k + 1); j < si; j++) // rest of the elements
{
swap(&prt[k], &prt[j]);
}
This should only swap if k > j, so you need an if statement:
for (j = (k + 1); j < si; j++) // rest of the elements
{
if (prt[k] > prt[j])
swap(&prt[k], &prt[j]);
}

Quick sort runtime speed concerns

I am having something that troubles me. I have my implementation of a quick sort algorithm, but when I test it on an array of integers that has over 30 elements, sorting takes, in my opinion to long. Sometimes even more than 10 seconds, unlike with selection sort, insertion sort and bubble sort, which are faster on 10000 elements than quick sort on 100 elements.
Here is my solution, please give advice :)
void kvikSort(int a[], int l, int d) {
int i, k;
if (l >= d)
return;
k = l;
swap(&a[l], &a[(l + d) / 2]);
for (i = l + 1; i <= d; i++)
if (a[i] < a[l])
swap(&a[++k], &a[i]);
swap(&a[l], &a[k]);
kvikSort(a, 0, k-1);
kvikSort(a, k+1, d);
}
EDIT: I am using GCC v 4.7.2 on my Linux Mint 14, proc: intel core2duo e7400
EDIT: My other algorithms:
void selectionSort(int a[], int n) {
int i, j, min;
for (i = 0; i < n - 1; i++) {
min = i;
for (j = i + 1; j < n; j++)
if (a[j] < a[min])
min = j;
if (min != i)
swap(&a[min], &a[i]);
}
}
void insertionSort(int a[], int n) {
int i, j;
for (i = 0; i < n - 1; i++)
for (j = i + 1; j > 0 && a[j] < a[j-1]; j--)
swap(&a[j], &a[j-1]);
}
void bubbleSort(int a[], int n) {
int i, j;
for (i = n - 1; i > 0; i--)
for (j = 0; j < i; j++)
if (a[j] > a[j+1])
swap(&a[j], &a[j+1]);
}
void swap(int *i, int *j) {
int tmp;
tmp = *i;
*i = *j;
*j = tmp;
}
EDIT: Maybe I should mention that in my test program I am first outputing randomly generated array to a text file, then sorted array to another text file. So it is certainly running slow, but that's not the problem, the problem is that quick sort runs a lot slower than the rest.
Your first recursive call
kvikSort(a, 0, k-1);
has the wrong lower bound, it should be
kvikSort(a, l, k-1);
With a lower bound of 0, you re-sort the initial part of the array again and again.
Here's the problem:
void kvikSort(int a[], int l, int d) {
int i, k;
if (l >= d)
return;
k = l;
swap(&a[l], &a[(l + d) / 2]);
for (i = l + 1; i <= d; i++)
if (a[i] < a[l])
swap(&a[++k], &a[i]);
swap(&a[l], &a[k]);
>>> kvikSort(a, 0, k-1);
kvikSort(a, l, k-1);
kvikSort(a, k+1, d);

Resources