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.
Related
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);
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
I previously tested the same variable called "swaps" for bubble sort algorithm and it worked perfectly. Now, with selection sorting, variable loses its value even after incrementing it.
Any help will be very much appreciated.
int list[] = {10, 5, 6, 3, 4, 11, 9, 7, 2};
int min = list[0], pos = 0, temp_max = 0;
// Loop until no swap is needed
for (int j = 0, n = sizeof(list) / sizeof(int); j < n; j++)
{
int swaps = 0,
// Iterate through array to find min value
for (int i = j, y = sizeof(list) / sizeof(int); i < y; i++)
{
if (list[i] < min)
{
min = list[i];
pos = i;
}
}
// Insert min value in left most position and add 1 to swaps, meaning array is not yet sorted
if (pos > j)
{
temp_max = list[j];
list[j] = min;
list[pos] = temp_max;
swaps++;
}
// The error might occur here: "swaps" keeping value 0 after previous if statement ends
printf ("swaps = %d\n", swaps);
// If no swaps ocurred, array is sorted
if (swaps == 0)
{
// Print sorted array and return
}
}
Move the declaration int swaps = 0 outside the for loop.
In other words, change this:
for (int j = 0, n = sizeof(list) / sizeof(int); j < n; j++)
{
int swaps = 0;
...
}
To this:
int swaps = 0;
for (int j = 0, n = sizeof(list) / sizeof(int); j < n; j++)
{
...
}
I want to thank you all very much. I have solved the problem with your help. Turns out the error had to do with the variable scope (where it was declared). Follow below the working code.
int main (void)
{
//Declare list to be sorted and other variables
int list[] = {9, 5, 7, 8, 4, 3, 2, 1, 6};
int minValPos = 0, maxTempVal = list[0];
for (int j = 0, siz = sizeof (list) / sizeof (int); j < siz; j++)
{
int swaps = 0, minVal = list[j];
// Look for min value after each j iteration
for (int i = j; i < siz; i++)
{
// Find minimum value (minVal) and store its position (minValPos)
if (list[i] < minVal)
{
minVal = list[i];
minValPos = i;
}
}
// Once with MinVal pinpointed, proceed to swap with jth item
if (minValPos > j)
{
maxTempVal = list[j];
list[j] = minVal;
list[minValPos] = maxTempVal;
swaps++;
}
// When array did not need any swaps, it means it is sorted
if (swaps == 0)
{
for (int r = 0; r < siz; r++)
{
printf ("Position [%d] = %d\n", r, list[r]);
}
}
}
}
That means your if statement is not becoming true in the meantime.
min should be set in each loop of j.
min=list[j] in for(j=...){min=list[j]; ... }
And also pos=j
Adding to the other answers, which will fix the problem specifically with your code, you can also approach the selection sort algorithm like this.
Steps to writing this algorithm for an array:
1. Write a helper function to find the index of the biggest element in the array:
size_t index_of_largest(int list[], size_t n) {
size_t i, biggest;
biggest = 0;
for (i = 0; i < n; i++) {
if (list[i] > list[biggest]) {
biggest = i;
}
}
return biggest;
}
2. Iterate over i=n to i=1, and find the biggest value between list[0] and list[i-1]. After this element is found, swap it into the last position. The function could look like this:
void sort_list(int list[], size_t n) {
size_t i, biggest;
for (i = n; i > 0; i--) {
biggest = index_of_largest(list, i);
int_swap(&list[biggest], &list[i-1]); /* swapping function */
}
}
3. Considering these ideas, you can write a simple version of the algorithm like this:
#include <stdio.h>
void sort_list(int list[], size_t n);
size_t index_of_largest(int list[], size_t n);
void print_array(int list[], size_t n);
void int_swap(int *x, int *y);
int main(void) {
int list[] = {10, 5, 6, 3, 4, 11, 9, 7, 2};
size_t n = sizeof list / sizeof *list;
printf("Before: ");
print_array(list, n);
sort_list(list, n);
printf("After: ");
print_array(list, n);
return 0;
}
void sort_list(int list[], size_t n) {
size_t i, biggest;
for (i = n; i > 0; i--) {
biggest = index_of_largest(list, i);
int_swap(&list[biggest], &list[i-1]);
}
}
size_t index_of_largest(int list[], size_t n) {
size_t i, biggest;
biggest = 0;
for (i = 0; i < n; i++) {
if (list[i] > list[biggest]) {
biggest = i;
}
}
return biggest;
}
void print_array(int list[], size_t n) {
size_t i;
for (i = 0; i < n; i++) {
printf("%d ", list[i]);
}
printf("\n");
}
void int_swap(int *x, int *y) {
int temp;
temp = *x;
*x = *y;
*y = temp;
}
Output:
Before: 10 5 6 3 4 11 9 7 2
After: 2 3 4 5 6 7 9 10 11
Compiled with:
gcc -Wall -Wextra -o progname progname.c
I'm trying to sort an array using this function findMinimumIndex in a for loop, but I can't seem find where it's not sorting correctly. Any suggestions? The function itself works fine, but when I try to use it in a loop, it doesn't work. Any suggestions? Thanks!
int findMinimumIndex(A[], int a, int b); //Finds smallest index of portion of array (A[i] ... A[j])
int main(){
int A[5] = {4,6,7,4,3};
int smallest_index;
for (int j = 0; j < count; j++){
smallest_index = findMinimumIndex(A, j, 4);
printf("Sorted: %d\n", A[smallest_index]);
}
}
int findMinimumIndex(int A[], int a, int b){
int smallest_value = A[a];
int index = 0;
for (int k = a; k < j - 1; k++){
if (A[k + 1] < smallest_value){
smallest_value = A[k+1];
index = k + 1;
}
}
return index;
}
If you find the minimum value and its index, you should switch values:
Look at this example:
You have got array:
{4,6,7,4,3}
At first, you will find value 3 at index 4, but you have to move the smallest value (switch with value on j=0 index):
{3,6,7,4,4}
Then you will find 4 on index 3, then, switch it with j=1:
{3,4,7,6,4}
etc.
Modification of your code:
for (int j = 0; j < count; j++){
smallest_index = findMinimumIndex(A, j, 4);
int tmp = A[smallest_index];
A[smallest_index] = A[j];
A[j] = tmp;
printf("Sorted: %d\n", A[j]);
}
EDIT: correction:
length of the array is 5:
smallest_index = findMinimumIndex(A, j, 5);
and index should be set to a
int findMinimumIndex(int A[], int a, int b){
int smallest_value = A[a];
int index = a;
/* code */
}
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]);
}