Radix sort gives wrong answer by changing just one loop of count subroutine - c

It seems a very trivial problem but after a lot of thinking I still can't figure it out. I worte these two codes for Radix sort.
Code 1
#include <stdio.h>
#include <malloc.h>
#define BUCKET_SIZE 10
void prin(int* arr,int n)
{
int i;
for(i=0;i<n;i++)
printf("%d ",*(arr+i));
printf("\n");
}
int maxi(int* arr,int n)
{
int i,max=0;
for(i=0;i<n;i++)
{
if(arr[i]>max)
max=arr[i];
}
return max;
}
int* count(int *arr,int n,int k)
{
int* count,i,index;
int* output;
count=(int*)calloc(BUCKET_SIZE-1,sizeof(int));
output=(int*)malloc(n*sizeof(int));
for(i=0;i<n;i++)
{
index=(arr[i]/k)%10;
count[index]++;
}
for(i=0;i<BUCKET_SIZE;i++)
count[i]+=count[i-1];
for(i=n-1;i>=0;i--)
{
index=(arr[i]/k)%10;
output[count[index]-1]=arr[i];
count[index]--;
}
return output;
}
int* radixsort(int* arr,int n)
{
int i,max,k=1;
max=maxi(arr,n);
while(max>0)
{
max/=10;
arr=count(arr,n,k);
k=k*10;
}
return arr;
}
void main()
{
int n,i;
scanf("%d",&n);
int* arr;
arr=(int*)malloc(n*sizeof(int));
for(i=0;i<n;i++)
scanf("%d",(arr+i));
arr=radixsort(arr,n);
prin(arr,n);
}
Now if I change the sort subroutine like below, this code will not sort the given array and I can't figure why this happened, I am still traversing the whole array so and I am still calculating the right index so my elements should be filled in the right place and I should have a sorted array.
Code 2
Only count function last loop changed.
int* count(int *arr,int n,int k)
{
int* count,i,index;
int* output;
count=(int*)calloc(BUCKET_SIZE-1,sizeof(int));
output=(int*)malloc(n*sizeof(int));
for(i=0;i<n;i++)
{
index=(arr[i]/k)%10;
count[index]++;
}
for(i=0;i<BUCKET_SIZE;i++)
count[i]+=count[i-1];
for(i=0;i<n;i++)
{
index=(arr[i]/k)%10;
output[count[index]-1]=arr[i];
count[index]--;
}
return output;
}
When I am doing just counting sort both functions work well. Can someone point me out where I am going wrong with radix sort, or what is the thing I am missing, and how both well in counting sort.
Thanks.

In your final loop in your count function,
when these lines copy the contents of each "bucket",
they write the last element of the output "bucket" first,
followed by the next-to-last, ending with the first element:
output[count[index]-1]=arr[i];
count[index]--;
In the first version of your program, since you visit the elements of the input array starting at the end of the array and working your way back toward the beginning,
you encounter the last element of each bucket first (and therefore put it in the last position in the output bucket), then the next-to-last element
(which you put in the next-to-last position in the output),
and so forth. The first element of each bucket is the last copied
and is copied to the first position in the bucket.
In the second version of your program, you continue to fill in the spaces in each output bucket from back to front, but you read the input from front to back. This has the result of putting the first element of each bucket in the last position within that bucket, and the last element of the bucket in the first position.
That is, each time you run the count function it reverses the order of elements within each bucket.
If you want to copy the input array reading it from front to back,
you need to fill in each output bucket from front to back
by using ++count[index] instead of --count[index].
You also have to start each entry of count[index] at a lower number so that you write to the correct locations.
Aside: your program does a lot more allocation than it needs to, and doesn't free any memory, so you have a potentially massive memory leak.
You might consider passing already-allocated arrays into count instead of always allocating new ones.

Here is a front to back example, that also replaces the original array with a sorted array, freeing the original array. An alternative would be to do a one time allocation of a second working array, radix sort back and forth between original and working arrays, then keep the sorted array, and free the "other" array.
#include <stdio.h>
#include <stdlib.h>
#define BUCKET_SIZE 10
void prin(int* arr, int n)
{
int i;
for(i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
int maxi(int* arr, int n)
{
int i,max = 0;
for(i = 0; i < n; i++)
{
if(arr[i] > max)
max = arr[i];
}
return max;
}
/* replaces array with sorted array, frees original array */
void count(int** parr, int n, int k)
{
int* count, i, index;
int* arr = *parr;
int* output;
int sum, cur;
count=calloc(BUCKET_SIZE, sizeof(int));
output=malloc(n*sizeof(int));
for(i = 0; i < n; i++){
index = (arr[i]/k)%10;
count[index]++;
}
sum = 0;
for(i = 0; i < BUCKET_SIZE; i++){
cur = count[i];
count[i] = sum;
sum += cur;
}
for(i = 0; i < n; i++){
index = (arr[i]/k)%10;
output[count[index]++] = arr[i];
}
free(arr);
free(count);
*parr = output;
}
void radixsort(int** parr,int n)
{
int max,k=1;
max=maxi(*parr,n);
while(max>0)
{
max/=10;
count(parr,n,k);
k=k*10;
}
}
int main()
{
int n,i;
int* arr;
scanf("%d",&n);
arr = malloc(n*sizeof(int));
for(i = 0; i < n; i++)
scanf("%d",&arr[i]);
radixsort(&arr,n);
prin(arr,n);
free(arr);
return 0;
}

Related

Left Shift/ Right Shift an array using two pointers in C

I am trying to implement a Left shift/ Right Shift on arrays.
I was able to accomplish this using double loops.
Can I get some help to improve the efficiency?
This is the working code for LeftShift/RightShift which is using 2 loops.
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
struct Array
{
int A[10];
int size;
int length;
};
void Display(struct Array arr)
{
printf("\nElements are : \n");
for(int i = 0;i<arr.length;i++)
printf("%d ", arr.A[i]);
}
// Left Shift-------------------------------------------------------------------------------------------------------
void LeftShift1(struct Array *arr, int n) //n is the number of shifts
{
int temp = arr->A[0];
for(int i=0; i<n; i++)
{
for(int j=0; j<arr->length-1; j++)
{
arr->A[j] = arr->A[j+1];
}
arr->A[arr->length-1] = 0;
}
}
//Right Shift-------------------------------------------------------------------------------------------------------
void RightShift(struct Array *arr, int n) //n is the number of shifts
{
for(int i = 0; i<n; i++)
{
for(int j=arr->length-1; j>0; j--)
{
arr->A[j] = arr->A[j-1];
}
arr->A[0] = 0;
}
}
int main()
{
struct Array arr={{1,2,3,4,5},10,5};
LeftShift1(&arr, 2);
//RightShift(&arr, 1);
Display(arr);
return 0;
}
I'm trying something like this which uses 2 iterators to solve this problem!
This is also working!
void LeftShift2(struct Array *arr, int n)
{
for(int k=0; k<n; k++)
{
int i,j;
for(i=0, j=0; j<arr->length-1; i++, j++)
{
arr->A[j] = arr->A[j+1];
}
arr->A[arr->length-1] = 0;
}
}
But can this be solved without loops? OR with a single loop?
Can this be made more efficient?
some help to improve the efficiency?
Shift: Shift once. Go from O(n*length) to O(length).
Rotate: Shift once into a temporary. Go from O(n*length) to O(length).
Qualify n first.
void LeftShift_alt(struct Array *arr, int n) {
if (n > arr->length) {
n = arr->length;
}
memmove(&arr->A[0], &arr->A[n], (arr->length - n)*sizeof arr->A[0]);
memset(&arr->A[arr->length - n], 0, n * sizeof arr->A[0]);
}
void LeftRotate_alt(struct Array *arr, int n) {
if (arr->length > 0) {
n %= arr->length;
if (n > 0) {
int temp[n];
memcpy(temp, arr->A, sizeof temp);
memmove(arr->A, arr->A + n, sizeof arr->A[0] * (arr->length - n));
memcpy(arr->A + n, temp, sizeof temp);
}
}
}
Replace mem...() with pointer code if desired.
Rather than actually moving the contents of the array around, you could provide all the common accessor operators (<<, >>, [], etc.) in the struct. (Assuming you're using a compiler that supports this. Otherwise, you'll need to create these functions C-style.) If someone did this:
my_array <<= 5;
my_array >>= 2;
...you'd simply keep track of how much the array has been shifted. In this case, they've shifted a total of 3 positions to the left. When someone indexes into the array, you add the accumulated offset to their index (modulo the size of the array) to get the actual location of the entry they're looking for. This makes shifts O(1) instead of O(n). If you're looking for an efficient solution, this is about as good as it gets.
After CODE REVIEW:
In C, efficiency can be improved by using a single loop. Instead of shifting elements one position at a time we can move them n positions!
Something like this:
void LeftShift1(struct Array* arr, unsigned int n) {
if (n > arr->length) {
n = arr->length;
}
for (unsigned int i = 0; i < arr->length; i++) {
if (i + n < arr->length)
arr->A[i] = arr->A[i + n];
else
arr->A[i] = 0;
}
}
In practical usage, we would want to consider doing this array shifting with element types other than a plain int. In fact, it may be a complex type like a string and we should not do raw memcpy on string.
In my code, I was setting the shifted-out elements to 0 which was OK for an integer and related types, but it won't work similarly in string.
As of C++20, there is a standard std::shift_left and std::shift_right ready to use.
There also exists std::rotate which can be used to rotate the elements.
int arr[] = {1,2,3,4,5};
using std::ranges::begin;
using std::ranges::end;
std::shift_left (begin(arr),end(arr),2);
Display(arr);
Also in C++, we should use flexible container like vector in place of struct!
Also If we are doing a lot of adding and removing elements from both ends then there is a container specifically designed for that called deque ("doubly ended queue").

Code stops after reaching swap function, it works perfectly if I comment it out

The code breaks and doesn't run further after reaching the swap function, even though it works if I comment it out, and I don't see the problem of why it stops working.
#include <stdio.h>
#define size 10
void swap(int *max,int *minimum);//swaps maximum value location with minimum value location
void max_min(int arr[],int *max,int *min,int *locmin,int *locmax);
int main()
{
int grades[10]={40,52,77, 80, 85, 88, 90, 66,55,99};
int max=0,min=0,locmax,locmin;
max_min(grades,&max,&min,&locmin,&locmax);//Gets maximum-minimum values and their location
printf("Largest grade %d\n smallest grade %d\n",max,min);
swap(&grades[locmax],&grades[locmin]);// only swaps smallest-greatest value
}
void swap(int *max,int *minimum)
{
int temp=*max;
*max=*minimum;
*minimum=temp;
}
void max_min(int arr[],int *max,int *min,int *locmin,int *locmax)
{
int maxx,minx;
maxx=arr[0];
minx=arr[0];
for (int k = 0; k <size; k++)
{
for(int i=1; i<size; i++)
{
/* If current element is greater than max */
if(arr[i] > maxx)
{
maxx= arr[i];
*locmax=i;
}
/* If current element is smaller than min */
if(arr[i] < minx)
{
minx= arr[i];
*locmin=i;
}
}
}
*max=maxx;
*min=minx;
}
locmin and locmax are never initialized, neither by main nor by max_min. The result is they will contain whatever garbage was in memory at the time. If you're lucky that will be 0, but it could be anything. This can result in locmin or locmax being out out of bounds for the grades array. They're less then 0 or greater than 9. So grades[locmin] and grades[locmax] try to access memory your process does not own and results in a memory violation.
Looking at max_min(), notice that locmax and locmin are only assigned to conditionally. It may happen that they are never assigned to. Specifically if the first element of grades is also the smallest element locmin will never be assigned. It will contain whatever value it started with. If it was never initialized that will be garbage. That is what's happened.
To fix this, initialize them inside max_min. Don't make it the caller's responsibility, that is error prone. Also pass in size, don't use a global. And probably get rid of the max and min arguments, the caller can get them from locmin and locmax.
void max_min(int arr[], size_t size, int *locmin, int *locmax) {
// At the start, the first element is both the max and min.
int maxx = arr[0];
int minx = arr[0];
*locmax = 0; // <<<--- initialize to the first index
*locmim = 0; // <<<--- initialize to the first index
for (int k = 0; k < size; k++) {
for(int i=1; i< size; i++) {
// If current element is greater than max
if(arr[i] > maxx) {
maxx= arr[i];
*locmax=i;
}
// If current element is smaller than min
if(arr[i] < minx) {
minx= arr[i];
*locmin=i;
}
}
}
}
I had to give an initial value for both locmin,locmax of zero, then the program started working.
I don't know if this is something related to C but it's the first time where I have encountered such a problem.

I'm trying to merge two sorted (int)arrays using pointers and for some reason it stores the addresses

void interclas(int *ptr,int *vec, int *c, int n) {
int i,j,tmp;
tmp=0;
for (i=0;i++;i<n)
for (j=0;i++;j<n)
{
if (vec[j]<=ptr[i])
c[tmp]=vec[j];
else
c[tmp]=ptr[i];
tmp++;
}
}
int main() {
int i,n;
int *ptr,*vec,*c;
printf("Nr. of elements of initial arrays : 5 \n");
n=5;
vec=(int*)malloc( n * sizeof(int));
ptr=(int*)malloc( n * sizeof(int));
c=(int*)malloc( 2 * n * sizeof(int));
for (i=0;i<n;i++) {
scanf("%d",&ptr[i]);
}
for (i=0;i<n;i++) {
scanf("%d",&vec[i]);
}
printf("\n");
printf("Initial arrays are : ");
for (i=0;i<n;i++) {
printf("%d ",ptr[i]);
}
printf("\n");
for (i=0;i<n;i++) {
printf("%d ",vec[i]);
}
interclas(ptr,vec,&c,n);
printf("Merged array is : ");
for (i=0;i<10;i++) {
printf("%d ",c[i]);
}
return 0;
}
So I'm trying to merge two sorted arrays into one new one using pointers with the function 'interclas'. I tried using the same method to sort an array with a pointer in a function and it worked just fine. Now as you can see, it stores the adress of the variable rather than the variable itself.
If I run this, it stores the adresses of the arrays. How can I fix this? (I'm still new to pointers)
In your method's body, change:
for (i=0;i++;i<n)
for (j=0;i++;j<n)
to this:
for (i=0; i<n; i++)
for (j=0; j<n; j++)
and then change the call to your method, from this:
interclas(ptr, vec, &c, n);
to this:
interclas(ptr, vec, c, n);
since the prototype expects a pointer to an int, for the third parameter.
The logic of your method is also flawed, try to put some printfs (e.g. printf("here i = %d, j = %d, ptr[i] = %d, vec[j] = %d, tmp = %d\n", i, j, ptr[i], vec[j], tmp);) to see what values your variables have at its iteration - you only get the first two elements of the first array to be merged!
If you think about it, what you'd like to do is to go through the first element of array ptr and vec, and store the minimum of this two. If now that min was of array ptr, you'd like the next element of ptr to be taken into account, otherwise the next element of vec.
Take a pencil and a paper and sketch that algorithm - you'll see that it goes out nicely, but some leftover elements might be left behind, and not get inserted in the output array.
Driven from that observation, after traversing both the arrays and comparing elements, we will loop over the first array, if needed, to collect elements that were not visited. Similarly for the second array.
Coding that thought gives something like this:
void interclas(int *ptr,int *vec, int *c, int n) {
int i = 0, j = 0, tmp = 0;
// Traverse both arrays simultaneously,
// and choose the min of the two current elements.
// Increase the counter of the array who had
// the min current element.
// Increase the counter for the output array in
// any case.
while(i < n && j < n)
{
if(ptr[i] < vec[j])
{
c[tmp++] = ptr[i++];
}
else
{
c[tmp++] = vec[j++];
}
}
// Store remaining elements of first array
while (i < n)
c[tmp++] = ptr[i++];
// Store remaining elements of second array
while (j < n)
c[tmp++] = vec[j++];
}
Not the source of your problem, but Do I cast the result of malloc? No.

Bubble Function sorting in C on an array of integers

I have coded out a Bubble Function that is supposed to Bubble sort an array of user input integers, but for some reason, my array is only working with arrays with size 6... otherwise the array outputs a zero for the largest number. Please run this code and help me identify the problem.
#include <stdio.h>
//prototype
void bubble(int array[], int size);
int main(void)
{
int n,i,j,size,temp,counter = 0;
//FOR SOME REASON, ONLY INPUT SIZE 6 WORKS PERFECTLY.
int k;
printf("How many numbers to sort?\n");
scanf("%d",&size);
int array[size];
for(i=0;i<size;i++)
{
printf("Enter number %d\n",i+1);
scanf("%d",&k);
array[i] = k;
}
printf("Array before sorting:\n");
for(i=0;i<size;i++)
{
printf("%d ",array[i]);
}
bubble(array,size);
return 0;
}
// use this if you want to test print an array
// for(i=0;i<size;i++)
// {
// printf("%d",array[i]);
// }
void bubble(int array[], int size)
{
int i, j, temp;
for(j=0;j<size;j++)
{
printf("\nIteration# %d\n",j+1);
for(i=0;i<size;i++)
{
if(array[i] > array[i+1])
{
temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
}
printf("%4d",array[i]);
}
}
}
// void select(int array[], int size)
// {
// int i, j, temp;
// min = array[0];
// for(j=0;j<size;j++)
// {
// if(array[j] < min)
// {
// array[j] = temp;
// min = array[j];
// }
// }
// }
Your inner-loop top-end conditional break is size, but within the loop you reference array[i+1], which means you're referring to array[size]. Since C arrays are zero-base indexed, the only allowable indexing is from 0...(size-1). Your code breaches that by one item repeatedly.
Changing the top-end of the inner loop to size-1 will work in your case. but there is arguably a better alternative that alleviates you from remembering the minus-1 in the first place. It involves modifying size as you sort to control the top-end of your inner loop directly. It also eliminates one local variable that you no longer need).
void bubble(int array[], int size)
{
while (size-- > 0)
{
for(int i=0; i<size; ++i)
{
if(array[i] > array[i+1])
{
int temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
}
}
}
}
Often called a "goes-down-to" expression (because it looks like a long arrow pointing at a limiting value), the outer loop has been changed to become while (size-- > 0). This takes the current value of size to a temporary, decrements size, and compares the temporary against > 0 (more or less). The result is size now reflects the top limit of your inner loop that you want. Each enumeration of the outer loop will shrink the next inner loop pass by one. The point of bubble sort is that, once an element has been "bubbled up" to its proper position, you need not visit that element ever again, something your code is not taking advantage of.
Bonus Optimization
Finally, you can optimize this further and give your bubblesort the one and only redeeming quality the algorithm can offer: O(n) in best case where the sequence is already sorted. You do this by doing "swap-detection". If you ever pass over the inner loop without making a single swap, it makes no sense to perform anymore sorting. The sequence is sorted and you're done. It's a near-freebie addition to the original algorithm above, and looks like this:
void bubble(int array[], int size)
{
int swapped = 1;
while (swapped && size-- > 0)
{
swapped = 0;
for(int i=0; i<size; ++i)
{
if(array[i] > array[i+1])
{
int temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
swapped = 1;
}
}
}
}
Given an already sorted sequence of a ten, a hundred, or a hundred-thousand elements, this will finish after only one pass. Worth noting: even one element out of position on one extreme end will make this optimization irrelevant. I.e. if any element that belongs near the beginning is originally near the end, it will take up to size iterations to bring it home, and with that the optimization becomes moot. In short, this sequence
1 3 4 5... 9998 9999 2
will completely foil the optimization above. There are techniques to combat this as well including a two pass inner loop enumeration, where you ascend to bubble up larger values, then reverse direction to descend, bubbling down smaller values. but at this point you're better off using a finer algorithm like quicksort or heapsort. The discussion of that, and indeed the latter half of this post, is beyond the scope of your question.
i<size in combination with i+1 will go past the bounds of the array.
You should replace this:
for(i=0;i<size;i++)
with this:
for(i=0;i<size-1;i++)

bucket sort Implementation without using vector,pointer and counting sort

We want to use Bucket sort to sort numbers between 1 to 2001. the count of numbers can be 10E6.
I know the bucket sort algorithm. But the issue is that in this question, we are not permitted to use variable-length array, vector and pointer. (The only pointer related thing allowed is "pass by reference" of the array) The only solution I found is using using counting sort for each bucket, like the code below, so the code is more like counting sort than the bucket sort: (C language)
#include <stdio.h>
int buckets[201][10]={}; int numbers[1000001]={};
void bucket_sort (int a[],int n) {
for (int i =0;i<=n-1;i++)
{
int index = a[i]/10, index2 = a[i]%10;
buckets[index][index2]++;
}
int counter =0;
for (int i =0;i<=200;i++)
{
for (int j =0; j<=9;j++)
{
while (buckets[i][j])
{
a[counter] = i*10+j;
counter++;
buckets[i][j]--;
}
}
} }
int main() {
int n;
scanf("%d",&n);
if (n==0)
{
return 0;
}
for (int i =0;i<=n-1;i++)
{
scanf("%d",&numbers[i]);
numbers[i];
}
bucket_sort(numbers,n);
for (int i =0;i<=n-1 ;i++)
{
printf("%d\n", numbers[i]);
}
return 0; }
I want to know can bucket sort be implemented without variable-length array, vector and pointer and also without counting sort. Probably using Insertion or Bubble sort. Note that it must be a reasonable bucket-sort algorithm. So defining very big buckets like int bucket [201][1000000]; is also an unacceptable approach.
Given that you can't use variable length arrays or pointers, one of which is required for a bucket sort, your best bet is to go with a counting sort. You only have 2000 possible values, so create an array of size 2000 and for each value you find increments the corresponding array element.
void counting_sort(int a[], int n)
{
int count[2002] = { 0 };
int i, j;
for (i=0; i<n; i++) {
count[a[i]]++;
}
for (i=0, j=0; i<n; i++) {
while (!count[j]) {
j++;
}
a[i] = j;
count[j]--;
}
}

Resources