kth smallest number using variation of quicksort - c

I have the following partition method and kthsmallest method (Variation of quicksort) which works for some cases but gives me the value 32767 for a few cases.
void swap(int* a, int* b){
int temp = *b;
*b = *a;
*a = temp;
}
int partition(int* arr, int l, int r){
int pivot = arr[r];
int i = l, j=0;
for(j=l; j<=r-1; j++){
if(arr[j] <= pivot){
swap(&arr[i], &arr[j]);
i++;
}
}
swap(&arr[i], &arr[j]);
return i;
}
And the kthsmallest function is as follows:-
int kthsmallest(int* arr, int low, int high, int k){
/* low = 0 and high = #elements - 1 */
/* k is in between 1 to high + 1 */
if (k>0 & k<=high-low+1) {
// pos is partitioning index, arr[p] is now at right place
int pos = partition(arr, low, high);
// Separately sort elements before / partition and after partition
if(pos-low == k-1){
return arr[pos];
}
//if position returned is greater than k, recurse left subarray
else if(pos-low > k-1){
return kthsmallest(arr, low, pos-1, k);
}
return kthsmallest(arr, pos+1, high, k-(pos+1));
}
}
However it works when I change the last call in kthsmallest function i.e.
Change: return kthsmallest(arr, pos+1, high, k-(pos+1));
To: return kthsmallest(arr, pos+1, high, k-(pos+1)+low);
I want to understand why I need to add low to k-(pos+1). Because in my view, when we have the subarray on the right in which the recursion enters, the kth smallest number in the large array boils down to k - last partition element -1 i.e. k-(pos+1).

You need low because when you recursively start with a new array, low will be the reference for pos. So the new k will be calculated from low to pos.
Maybe an example would be more clarifying.
Lets find the 9th smallest element of this array:
Now we do the partition, so we get:
From pos to the left we've got the smallest elements in the array, that's the 3 smallest elements. Now we'll work with the subarray starting from pos+1. And we need to get the 6th smallest element:
We do a partition over this subarray:
Remember that we are working over a subarray trying to find the 6th smallest element. In this case we separated the (pos - low + 1)th smallest elements in the subarray. So our new k will be:
We do a new partition:
Now we exceeded the 4th smallest element of the last subarray, so we trim the last part:
We do the partition again:
And we get:
So our number is 17.
Hope it helps.
PD: As David C. Rankin says in comments you probably should change & for &&.

It appears one of the problems you are having is trying to shoehorn a quickselect routine into a recursive function when there is no reason to make the function recursive to begin with. All you need to do is identify the partition the 'k' element resides in, there is no need to sort. All you need for your kthsmallest is:
/** select the ZERO BASED 'k' element from 'arr'.
* where 'low' and 'high' are the ZERO BASED low
* and high indexes for 'arr'.
*/
int kthsmallest (int *arr, int low, int high, int k)
{
for (;;) {
if (low == high)
return arr[low];
int pos = partition (arr, low, high);
if (k == pos)
return arr[k];
else if (k < pos)
high = pos - 1;
else
low = pos + 1;
}
}
Using your exact partition and swap functions, you can write a small example program to test k for every element in an array. (note: the element returned is based on a zero indexed k, e.g. the first smallest element is offset zero from the end of the array -- just like in the rest of C)
#include <stdio.h>
void swap (int *a, int *b);
int partition (int *arr, int l, int r);
/** select the ZERO BASED 'k' element from 'arr'.
* where 'low' and 'high' are the ZERO BASED low
* and high indexes for 'arr'.
*/
int kthsmallest (int *arr, int low, int high, int k)
{
for (;;) {
if (low == high)
return arr[low];
int pos = partition (arr, low, high);
if (k == pos)
return arr[k];
else if (k < pos)
high = pos - 1;
else
low = pos + 1;
}
}
int main (void) {
int a[] = { 51, 86, 34, 79, 92, 68, 14, 47, 22, 6 },
nelem = sizeof a / sizeof *a;
for (int i = 0; i < nelem; i++)
printf (" nth (%2d) element is : %d\n", i,
kthsmallest (a, 0, nelem - 1, i));
return 0;
}
void swap (int *a, int *b)
{
int temp = *b;
*b = *a;
*a = temp;
}
int partition (int *arr, int l, int r)
{
int pivot = arr[r];
int i = l, j = 0;
for (j = l; j <= r - 1; j++) {
if (arr[j] <= pivot) {
swap (&arr[i], &arr[j]);
i++;
}
}
swap (&arr[i], &arr[j]);
return i;
}
Example Use/Output
$ ./bin/kthsmall
nth ( 0) element is : 6
nth ( 1) element is : 14
nth ( 2) element is : 22
nth ( 3) element is : 34
nth ( 4) element is : 47
nth ( 5) element is : 51
nth ( 6) element is : 68
nth ( 7) element is : 79
nth ( 8) element is : 86
nth ( 9) element is : 92

Related

transforming max-heap into min-heap with heapfy

I'm trying to heapfy a max-heap i've got into a min-heap. For some reason i'm not getting the result i expect.
i've built my max-heap and the array contents of it are showing as expected:
60 50 30 20 40 10
When trying heapfy the above array and transform it into a min-heap, the desired result is:
10 20 30 60 50 40
However, the result i'm getting is:
10 20 60 50 40 30
here are my functions:
struct _heap
{
int max; //array max
int pos; //current position
int* priority; //array gets initialized after.
};
typedef struct _heap heap_t;
void heapify_min(heap_t* h, int father)
{
int smallest = father;
int left = 2 * father + 1;
int right = 2 * father + 2;
if (left < h->pos && h->priority[left] < h->priority[smallest) {
smallest = left;
}
if (dir < h->pos && h->priority[right] < h->priority[smallest])
smallest = right;
if (smallest != father) {
swap(father,smallest,h->priority);
heapify_min(h,left);
}
}
void swap(int a, int b, int *v)
{
int f = v[a];
v[a] = v[b];
v[b] = f;
}
void build_heap(heap_t* h)
{
int n = h->pos;
int i2 = (n/2) -1;
int i;
for (i = i2;i>=0;i--) {
heapify_min(h,i);
}
}
Any insights would be really helpful.
Check your code against my (below is working code for min_heap).
There are 3 problems :
In heapify_min function when you calling function recursively you should use variable smallest not left.
operators of comparing values in MIN HEAP should be > (greater) instead of < (smaller)
Function build_heap is correct but that should be just very first rearrange of array. And after that first rearrange of array (first creation of max heap) you should swap first and last element in array. After that initial swap you continue with heapify function but every further creation of max heap, swapping values in sub-trees (during recursive calling) and swaping first element with last element is done in cycle until there is only one node left.
Here is code :
void heapify(int arr[], int n, int i)
{
int smallest = i;
int l = 2 * i + 1;
int r = 2 * i + 2;
// If left child is larger than root
if (l < n && arr[l] > arr[smallest])
smallest = l;
// If right child is larger than largest so far
if (r < n && arr[r] > arr[smallest])
smallest = r;
// If largest is not root
if (smallest != i) {
//swap
int backUp = arr[i];
arr[i] = arr[smallest];
arr[smallest] = backUp;
// Recursively call on heapify function
heapify(arr, n, smallest);
}
}
void heapSort(int arr[], int n)
{
// Build heap (rearrange array)
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
// One by one extract an element from heap
for (int i = n - 1; i > 0; i--) {
// Swap root node with last node in array (WARNING: last node don't have to be
necessarily smallest one)
int backUp = arr[0];
arr[0] = arr[i];
arr[i] = backUp;
// call max heapify on the reduced heap
heapify(arr, i, 0);
}
}
/* A utility function to print array of size n */
void printArray(int arr[], int n)
{
for (int i = 0; i < n; ++i)
printf("%d ", arr[i]);
printf("\n");
}

inversion count mergesort in C

A permutation of integers from 1 to n is a sequence a1, a2, ..., an, such that each integer from 1 to n is appeared in the sequence exactly once.
Two integers in а permutation form an inversion, when the bigger one is before the smaller one.
As an example, in the permutation 4 2 7 1 5 6 3, there are 10 inversions in total. They are the following pairs: 4–2, 4–1, 4–3, 2–1, 7–1, 7–5, 7–6, 7–3, 5–3, 6–3.
Input n and array[n] 2<=n<=100,000
First I solved problem with bubble sorting but then i met time complexity problem.
Second I solved it mergesort but I didn't do well
Here is my cord
#include <stdio.h>
#include <malloc.h>
int n;
void sizein(){
scanf("%d",&n);
}
int count=0;
static void merge(int data[],int p,int q,int r){
int i,j,l;
int k=p;
int sorted[n];
for(i=p,j=q+1;i<=q&&j<=r;){
sorted[k++]=(data[i]<=data[j]) ? data[i++]:data[j++];
if(data[i>data[j]]){
count+=q-i;
}
}
if(i>q){
for(l=j;l<=r;l++,k++){
sorted[k]=data[l];
}
}
else{
for(l=i;l<=q;l++,k++){
sorted[k]=data[l];
}
}
for(l=p;l<=r;l++){
data[l]=sorted[l];
}
}
void merge_sort(int data[],int p,int r){
if(p<r){
int q=(p+r)/2;
merge_sort(data,p,q);
merge_sort(data,q+1,r);
merge(data,p,q,r);
}
}
int main(void){
int i;
int data[n];
for(i=0;i<n;i++){
scanf("%d",&data[i]);
}
merge_sort(data,0,n);
printf("%d",count);
return 0;
}
Where should i fix it
I cannot find some implementation bits in your code that divides the arrays into sub-arrays based on the index(as quick sort sorts based on value)
kindly have a look at the code provided below
int q = p + (r - l) / 2;//recommended to be used in the function mergesort
int q=(p+r)/2;//your implementation
try this code for your function part as my code runs well with over half a million values, I cannot clearly see any subarray to which values are copied in your implementation of the function merge I have added comments to make it easier for you to understand, the terminology of the variables are slightly different.
refer "ANANY LEVETIN-INTRODUCTION TO THE DESIGN AND ANALYSIS OF ALGORITHS" book for a vivid explanation on this algorithm
Have a look and try this
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
int L[n1], R[n2];
/* Copy data to temp arrays L[] and R[] */
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
/* Merge the temp arrays back into arr[l..r]*/
i = 0; // Initial index of first subarray
j = 0; // Initial index of second subarray
k = l; // Initial index of merged subarray
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
}
else {
arr[k] = R[j];
j++;
}
k++;
}
/* Copy the remaining elements of L[], if there
are any */
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there
are any */
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
/* l is for left index and r is right index of the
sub-array of arr to be sorted */
void mergeSort(int arr[], int l, int r)
{
if (l < r) {
// Same as (l+r)/2, but avoids overflow for
// large l and h
int m = l + (r - l) / 2;
// Sort first and second halves
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
/* Driver code */
int main()
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
int arr_size = sizeof(arr) / sizeof(arr[0]);
printf("Given array is \n");
//printArray(arr, arr_size);
mergeSort(arr, 0, arr_size - 1);
printf("\nSorted array is \n");
//printArray(arr, arr_size);
return 0;
}
After reading the code for some time I still can not say I understand the idea of counting the inversions. However, I can point out three things in it which seem incorrect to me.
First, I can't see where you call the sizein() function to initialize the n variable.
The second problem is the condition here:
if(data[i>data[j]]){
count+=q-i;
}
You compare the index i to the value of a data item data[j] which looks strange. Even worse, if you were to sort an array of geometric figures or an array of songs it could be just impossible due to incompatibility of the types of data to be compared. What's even worse, even if comparison succeedes, as in the case of an int index and an int value in data[],the result of comparison is an int value 1 if comparison is satisfied or 0 otherwise. As a result this condition will resolve to
if(data[0]){
count+=q-i;
}
or to
if(data[1]){
count+=q-i;
}
which is obviously wrong.
The correct code looks like this:
if (data[i] > data[j]) {
count += q - i;
}
The error would be more apparent if you left appropriate spacing between operators and their operands.
Yet another error lurks in the call to merge_sort(). First, you fill the data[] array with this loop:
for (i = 0; i < n; i ++) {
scanf("%d", &data[i]);
}
Obviously, you fill an n-items array with data at indices from 0 through n-1.
Then you call the merge-sorting routine:
merge_sort( data, 0, n);
which suggests the parameter p is the index of the first item or the part to be sorted and q is one-past-the last item. However, this disagrees with recursive calls:
merge_sort( data, p, q);
merge_sort( data, q+1, r);
Setting q as the ending index in the first call and q+1 as the starting index in the second suggests the ending index is inclusive, that is, it is the position of the last item in the segment to be sorted. Otherwise the two calls would leave the item data[q] unsorted. This also follows from internal loops, which continue while i <= q or whle l <= r etc.
So the initial call shouldn't be
merge_sort( data, 0, n);
but rather
merge_sort( data, 0, n-1);

Construct count array in better than O(n^2) time complexity

Given an array A[] of size n, construct two arrays C_min[] and C_max[] such that
C_min[i] represents number of elements smaller than A[i] in A[0 to i] and
C_max[i] represents number of elements greater than A[i] in A[i to n-1]
For example A[5] = {1,2,4,3,6} then C_min[] and C_max[] would be
C_min[5] = {0,1,2,2,4}
C_max[5] = {4,3,1,1,0}
I am not able to think of an algorithm better than O(n^2) but this post motivates me to think of some better way of doing this, but am not able to able apply similar kind of logic(which is mentioned in the post) here.
In the given post, problem given is to find no of inversion in an array. if array[i] > array[j] and j>i then it forms a inversion. for example The sequence 2, 4, 1, 3, 5 has three inversions (2, 1), (4, 1), (4, 3).
idea used to solve this problem is a merge sort algorithm.
In merge process, let i is used for indexing left sub-array(L[]) and j
for right sub-array(R[]). At any step in merge(), if L[i] is greater
than R[j], then there are (mid – i+1) inversions,where mid is the
middle index passed to the merge function of merge sort. because left
and right subarrays are sorted, so all the remaining elements in
left-subarray (L[i+1], L[i+2] … L[mid]) will be greater than R[j]
code for this logic is given below:
#include <bits/stdc++.h>
int _mergeSort(int arr[], int temp[], int left, int right);
int merge(int arr[], int temp[], int left, int mid, int right);
/* This function sorts the input array and returns the
number of inversions in the array */
int mergeSort(int arr[], int array_size)
{
int *temp = (int *)malloc(sizeof(int)*array_size);
return _mergeSort(arr, temp, 0, array_size - 1);
}
/* An auxiliary recursive function that sorts the input array and
returns the number of inversions in the array. */
int _mergeSort(int arr[], int temp[], int left, int right)
{
int mid, inv_count = 0;
if (right > left)
{
/* Divide the array into two parts and call _mergeSortAndCountInv()
for each of the parts */
mid = (right + left)/2;
/* Inversion count will be sum of inversions in left-part, right-part
and number of inversions in merging */
inv_count = _mergeSort(arr, temp, left, mid);
inv_count += _mergeSort(arr, temp, mid+1, right);
/*Merge the two parts*/
inv_count += merge(arr, temp, left, mid+1, right);
}
return inv_count;
}
/* This funt merges two sorted arrays and returns inversion count in
the arrays.*/
int merge(int arr[], int temp[], int left, int mid, int right)
{
int i, j, k;
int inv_count = 0;
i = left; /* i is index for left subarray*/
j = mid; /* i is index for right subarray*/
k = left; /* i is index for resultant merged subarray*/
while ((i <= mid - 1) && (j <= right))
{
if (arr[i] <= arr[j])
{
temp[k++] = arr[i++];
}
else
{
temp[k++] = arr[j++];
/*this is tricky -- see above explanation/diagram for merge()*/
inv_count = inv_count + (mid - i);
}
}
/* Copy the remaining elements of left subarray
(if there are any) to temp*/
while (i <= mid - 1)
temp[k++] = arr[i++];
/* Copy the remaining elements of right subarray
(if there are any) to temp*/
while (j <= right)
temp[k++] = arr[j++];
/*Copy back the merged elements to original array*/
for (i=left; i <= right; i++)
arr[i] = temp[i];
return inv_count;
}
/* Driver progra to test above functions */
int main(int argv, char** args)
{
int arr[] = {1, 20, 6, 4, 5};
printf(" Number of inversions are %d \n", mergeSort(arr, 5));
getchar();
return 0;
}
so can this count array problem be done on similar lines.
Is it possible to construct count array in better than O(n^2)-time?
Suppose you kept an array, S, where S[0..x] is a sorted version of A[0..x]. Then computing C_min[x+1] when you have already computed C_min[0..x] would amount to inserting A[x+1] into S (an O(log n) operation) and locating A[x+1] within S (at worst, another O(log n) operation). That would make computing all of C_min O(n log n). Computing C_max would be similar, but would need its own version of S, making computing both C_min and C_max O(n log n).

Merge-sort implementation doesn't work

I'm trying to implement merge sort in C using arrays, here's my code:
#include <stdio.h>
#include <stdlib.h>
void merge(int s[], int low, int middle, int high)
{
int i,l=0,r=0;
int left[high/2], right[high/2];
for(i = low; i<=middle; i++) left[i-low] = s[i];
for(i = middle+1; i<=high; i++) right[i-middle-1] = s[i];
i = low;
while(l <= middle-low || r <= high - middle - 1)
{
if(left[l] <= right[r])
{
s[i++] = left[l];
l++;
}
else
{
s[i++] = right[r];
r++;
}
}
while(l <= middle-low)
{
s[i++] = left[l];
l++;
}
while(r <= high - middle - 1)
{
s[i++] = left[r];
r++;
}
}
void mergesort(int s[], int low, int high)
{
int i;
int middle;
if(low < high){
middle = (low + high)/2;
mergesort(s, low, middle);
mergesort(s, middle+1, high);
merge(s, low, middle, high);
}
}
int main()
{
int nums[] = {5, 345, 1, 120, 40, 3450};
int size = (sizeof(nums))/(sizeof(int));
int i;
for(i = 0; i < size; i++)
printf("%d ", nums[i]);
printf("\n");
mergesort(nums, 0, size);
for(i = 0; i < size; i++)
printf("%d ", nums[i]);
printf("\n");
return 0;
}
That outputs:
5 345 1 120 40 3450
0 1 4 5 40 120
Which is kind of close. Could someone point out my mistakes? Thank you.
You access the array out of bounds at several places. Your code uses C-style ranges, which have an inclusive lower bound L and an exclusive upper bound H. Exclusive means that the upper bound H is not a valid index in the (sub-)array. A typical loop over the range look like this:
for (i = L; i < U; i++) ...
or
i = L;
while (i < U) ...
A greater-than-or-equal operator <= in such loops should make you wary, as should suprious additions or subtraction of 1. They might be correct in some cases, but they are usually consequences of inconsitent array indexing.
Let's revise your code with the C-style ranges in mind:
int left[high/2], right[high/2];
The array sizes are wrong. The left array has middle - low elements and the right array has high - middle elements. If the array size high - low is odd, you have one more element in right than in left.
for(i = low; i<=middle; i++) left[i-low] = s[i];
You mistakenly put the middle element in the left array. It is the first element of the right array.
for(i = middle+1; i<=high; i++) right[i-middle-1] = s[i];
Same here, plus you access s[high] which is one beyond the array.
i = low;
while(l <= middle-low || r <= high - middle - 1)
The conditions should have < and no -1. More importantly, the conditions should both be true, otherwise you access the subarrays out of bounds; hence the operator should be ´&&`.
if(left[l] <= right[r])
The <= is okay, though, for once.
while(l <= middle-low)
{
s[i++] = left[l];
l++;
}
while(r <= high - middle - 1)
{
s[i++] = left[r];
r++;
}
Here, it should be < again. Also note that you access left with the index r, which is probably just a typo owed to copy and paste.
if(low < high){
middle = (low + high)/2;
mergesort(s, low, middle);
mergesort(s, middle+1, high);
merge(s, low, middle, high);
}
Here, the second call to megesort should be to middle, not to middle + 1. Because the upper bound is exclusive and the lower is not, adjacent arrays share the same bounds.
Here's a sort that works:
void merge(int s[], int low, int middle, int high)
{
int i, l = 0, r = 0;
int left[middle - low];
int right[high - middle];
for (i = low; i < middle; i++) left[i - low] = s[i];
for (i = middle; i < high; i++) right[i - middle] = s[i];
i = low;
while (low + l < middle && middle + r < high) {
if (left[l] < right[r]) {
s[i++] = left[l];
l++;
} else {
s[i++] = right[r];
r++;
}
}
while (low + l < middle) {
s[i++] = left[l];
l++;
}
while (middle + r < high) {
s[i++] = right[r];
r++;
}
}
void mergesort(int s[], int low, int high)
{
int middle;
if (low + 1 < high) {
middle = (low + high) / 2;
mergesort(s, low, middle);
mergesort(s, middle, high);
merge(s, low, middle, high);
}
}
The code can still be improved. The different indices for the left and right subarrays make it difficult to maintain and test the code. If you have already learned about pointer arithmetic, you can do without the low bound entirely by passing array + low and the size as new array base, as EOF has suggested in a comment.
M Oehm provided an explanation and a fixed example of the original code in his answer.
Here is an alternate version that does a one time allocation of the temporary array and uses a pair of co-recursive functions to avoid copying of data. I'm not sure why top down merge sort is used so often, bottom up merge sort is non-recursive, a little bit faster, and simpler to understand.
On my system, Intel 2600K 3.4ghz, this example can sort 20 million 32 bit integers in about 2 seconds. (A bottom up merge sort would take about 1.9 seconds).
void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee);
void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee);
void MergeRuns(int a[], int b[], size_t ll, size_t rr, size_t ee);
void TopDownMergeSort(int a[], size_t n)
{
int *b;
if(n < 2) // if size < 2 return
return;
b = malloc(n * sizeof(int)); // one time allocation
TopDownSplitMergeAtoA(a, b, 0, n);
free(b);
return;
}
void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee)
{
size_t rr;
if((ee - ll) == 1) // if size == 1 return
return;
rr = (ll + ee)>>1; // midpoint, start of right half
TopDownSplitMergeAtoB(a, b, ll, rr);
TopDownSplitMergeAtoB(a, b, rr, ee);
MergeRuns(b, a, ll, rr, ee); // merge b to a
}
void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee)
{
size_t rr;
if((ee - ll) == 1){ // if size == 1 copy a to b
b[ll] = a[ll];
return;
}
rr = (ll + ee)>>1; // midpoint, start of right half
TopDownSplitMergeAtoA(a, b, ll, rr);
TopDownSplitMergeAtoA(a, b, rr, ee);
MergeRuns(a, b, ll, rr, ee); // merge a to b
}
void MergeRuns(int a[], int b[], size_t ll, size_t rr, size_t ee)
{
size_t o = ll; // b[] index
size_t l = ll; // a[] left index
size_t r = rr; // a[] right index
while(1){ // merge data
if(a[l] <= a[r]){ // if a[l] <= a[r]
b[o++] = a[l++]; // copy a[l]
if(l < rr) // if not end of left run
continue; // continue (back to while)
while(r < ee) // else copy rest of right run
b[o++] = a[r++];
break; // and return
} else { // else a[l] > a[r]
b[o++] = a[r++]; // copy a[r]
if(r < ee) // if not end of right run
continue; // continue (back to while)
while(l < rr) // else copy rest of left run
b[o++] = a[l++];
break; // and return
}
}
}

Sort numbers according to n-th term

I know how to sort an array(i.e. bubble sort) but I don't have any idea how I can sort an array according to n-th term. Could you give me idea or example if there is? Thank you for all appreciated answer.
#edit: how can be the program sensed a number with zeros I mean for 1 program sense 0001 or 00001 .... ?
Example:
2 --> nth digit
4 45 62 1 900 105 --> inputs
Output:
001 004 105 900 045 065
void bubble_sort(int iarr[], int num) {
int i, j, k, temp;
printf("\nUnsorted Data:");
for (k = 0; k < num; k++) {
printf("%5d", iarr[k]);
}
for (i = 1; i < num; i++) {
for (j = 0; j < num - 1; j++) {
if (iarr[j] > iarr[j + 1]) {
temp = iarr[j];
iarr[j] = iarr[j + 1];
iarr[j + 1] = temp;
}
}
printf("\nAfter pass %d : ", i);
for (k = 0; k < num; k++) {
printf("%5d", iarr[k]);
}
}
}
The quick answer is that your comparison function needs to look at the n-th digit instead of the whole number.
So if your original comparison was something like:
if (a < b) // handle a before b case
elseif (b < a) // handle b before a case
you'll want to change it to be:
aDigit = getNthDigit(a, n);
bDigit = getNthDigit(b, n);
if (aDigit < bDigit) // handle a before b case
elseif (bDigit < aDigit) // handle b before a case
You'll also have to implement getNthDigit, which would involve integer division and modulus operators.
Take a look at qsort for what a generic sort function requires. For your specific question, look at the sort algorithm you want to implement (i.e. bubble sort), and replace comparisons of elements with a function call to an order function. Your compare function should then extract the second digit and compare those digits.
Based on your code, you should change if (iarr[j] > iarr[j + 1]) with if(comp_gt(iarr[j], iarr[j + 1])). And, I would implement comp_gt by
int comp_gt(int a, int b)
{
int a_second_digit = (a / 10) % 10;
int b_second_digit = (b / 10) % 10;
return (a_second_digit < b_second_digit);
}
It means that you sort the numbers based on their n-th digit.
In the example you have, you see that the bolded digits (the second digit in every number) are the ones who define the order of the output.
Here is an example on how you can solve it (I am tuning it right now, because the method it uses to find a digit is wrong):
#include <stdio.h>
#include <math.h>
void quickSort(int a[], int first, int last, int n_th);
int pivot(int a[], int first, int last, int n_th);
void swap(int* a, int* b);
int n_th_digit(int number, int n);
void print(int array[], const int N);
int main() {
int test[] = { 7, 9, 1, 3, 6, 5, 2, 4 };
int N = sizeof(test) / sizeof(int);
int n_th = 0; // digit(from the end) to sort by
printf("Size of test array : %d\n", N);
printf("Before sorting : \n");
print(test, N);
quickSort(test, 0, N - 1, n_th);
printf("After sorting : \n");
print(test, N);
return 0;
}
/**
* Quicksort.
* #param a The array to be sorted.
* #param first The start of the sequence to be sorted.
* #param last The end of the sequence to be sorted.
* #param n_th The digit to sort by
*/
void quickSort(int a[], int first, int last, int n_th) {
int pivotElement;
if (first < last) {
pivotElement = pivot(a, first, last, n_th);
quickSort(a, first, pivotElement - 1, n_th);
quickSort(a, pivotElement + 1, last, n_th);
}
}
/**
* Find and return the index of pivot element.
* #param a The array.
* #param first The start of the sequence.
* #param last The end of the sequence.
* #param n_th The digit to sort by
* For example the third digit of 137
* requires n_th to be 0.
*
*/
int pivot(int a[], int first, int last, int n_th) {
int i, p = first;
int pivotElement = a[first];
for (i = first + 1; i <= last; i++) {
if (n_th_digit(a[i], n_th) <= n_th_digit(pivotElement, n_th)) {
p++;
swap(&a[i], &a[p]);
}
}
swap(&a[p], &a[first]);
return p;
}
/**
* Swap the parameters.
* #param a The first parameter.
* #param a The second parameter.
*/
void swap(int* a, int* b) {
// You still can use the swap that
// does not uses an extra variable
// from the C++ implementation.
int temp = *a;
*a = *b;
*b = temp;
}
int n_th_digit(int number, int n) {
if (number < 0)
number *= -1;
return fmod((number / pow(10, n)), 10);
}
/**
* Print an array.
* #param a The array.
* #param N The size of the array.
*/
void print(int a[], const int N) {
int i;
for (i = 0; i < N; i++)
printf("array[%d] = %d\n", i, a[i]);
}
I got the how to find the n-th digit from here and the quicksort from here.
Replace
void bubble_sort(int iarr[], int num) {
....
if (iarr[j] > iarr[j + 1])
With
void bubble_sort(int iarr[], int num, int term) {
unsigned pow10 = upow10(term - 1);
....
if (compareu(iarr[j], iarr[j + 1], pow10) > 0)
// To calculate pow(10, x) quickly
static unsigned upow10(unsigned y) {
unsigned z = 1;
unsigned base = 10;
while (y) {
if (y & 1) {
z *= base;
}
y >>= 1;
base *= base;
}
return z;
}
int compareu(int a1, int a2, unsigned pow10) {
unsigned b1 = abs(a1);
unsigned b2 = abs(a2);
b1 = (b1 / pow10) % 10;
b2 = (b2 / pow10) % 10;
if (b1 > b2) return 1;
if (b1 < b2) return -1;
return (a1 > a2) - (a1 < a2);
}
[Edit] per OP's update
Q: how can be the program sensed a number with zeros I mean for 1 program sense 0001 or 00001?
A: That is part of the code that reads input which is not posted. If code needs to distinguish between "0001" and "00001", then the whole problem is one of strings and not integers. In that case save each element as a string and do compares from a textual point-of-view.
Yet I suspect that is not the true coding goal. Simply use arithmetical compares and not be concerned with differing leading zeros.
The printf() function is another matter. To print at least term digits with leading 0, use "%0*d".
term = 2; // or 6 or 9, etc.
// printf("%5d", iarr[k]);
printf("%0*d ", term, iarr[k]);

Resources