Related
Consider the following algorithm:
void qsort(int arr[], int left, int right) {
if (left < right) {
int index = partition(arr, left, right);
qsort(arr, left, index - 1);
qsort(arr, index + 1, right);
}
}
int partition(int arr[], int left, int right) {
int pivot = arr[right];
int i = left - 1;
for (int j = left; j < right; j++) {
if (arr[j] <= pivot) {
++i;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[right]);
return i + 1;
}
inline void swap(int* i, int* j) {
int temp = *i;
*i = *j;
*j = temp;
}
After I fixed the segfaults, I noticed that the algorithm always produces a garbage value at arr[0]. So if the input array is: 5 5 1 3 7 0 0 0 3 , the output is -858993460 0 0 0 1 3 3 5 5. I've ran this through a debugger numerous times and nevertheless I still have no idea where the garbage value comes from. What's more interesting is that in Java pretty much the same algorithm works perfectly.
edit
The initial function is called like this: qsort(arr, 0, 9); where 9 is the length of the array - 1.
I suspect you have an off-by-one error in how you initialize arr or how you call qsort(). Likely it gets called with a garbage (uninitialized) element either at the start or at the end of the array. This also likely explains why the largest value, 7, is missing from the output.
If I were to speculate further, I'd guess that in Java, the array gets initialized with zeros and so you get an extra zero in the output (that perhaps you're overlooking amongst the other zeros?)
edit: The initial function is called like this: qsort(arr, 0, 9); where 9 is the length of the array - 1.
The 9 is clearly not correct for your example, so here is one error. It would account for the garbage element but not for the missing element.
My next hypothesis is that, having sorted a ten-element array (9 real + 1 garbage) you then only print out the first nine elements. This would account for the missing 7 in your output (it's the largest and so gets placed in the final spot, which is the spot that doesn't get printed out).
P.S. If I may offer some unsolicited advice for future questions, posting a Minimal, Complete, and Verifiable example would make all this debugging-by-conjecture completely unnecessary as we'd be able to see right away what exactly is going on with your code. :)
If you invoke the function with the size instead of the index of the right-most element (which is the size - 1), you access the array out of bounds.
This code works:
#include <stdio.h>
static
inline void swap(int *i, int *j)
{
int temp = *i;
*i = *j;
*j = temp;
}
static
int partition(int arr[], int left, int right)
{
int pivot = arr[right];
int i = left - 1;
for (int j = left; j < right; j++)
{
if (arr[j] <= pivot)
{
++i;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[right]);
return i + 1;
}
static
void qsort(int arr[], int left, int right)
{
if (left < right)
{
int index = partition(arr, left, right);
qsort(arr, left, index - 1);
qsort(arr, index + 1, right);
}
}
static void dump_array(const char *tag, int size, int *arr)
{
printf("%s (%d):", tag, size);
for (int i = 0; i < size; i++)
printf(" %d", arr[i]);
putchar('\n');
}
int main(void)
{
int arr[] = { 5, 5, 1, 3, 7, 0, 0, 0, 3, };
enum { ARR_SIZE = sizeof(arr) / sizeof(arr[0]) };
dump_array("Before", ARR_SIZE, arr);
qsort(arr, 0, ARR_SIZE - 1);
dump_array("After", ARR_SIZE, arr);
return 0;
}
Output:
Before (9): 5 5 1 3 7 0 0 0 3
After (9): 0 0 0 1 3 3 5 5 7
/*I recently learnt qsort function. This c code is giving incorrect output. Need help with this.
PROBLEM- Sorting an array of integers in alternate fashion. (the elements at even indices and those at odd indices are sorted separately)
OUTPUT- 0 4 1 2 5 8 7 5 9 3
10 5
*/
#include <stdio.h>
#include <stdlib.h>
// This function is used in qsort to decide the relative order
// of elements at addresses p and q.
int comparator(const void *p, const void *q)
{
// Get the values at given addresses
int l = *(const int *)p;
int r = *(const int *)q;
return (l-r);
}
// A utility function to print an array
void printArr(int arr[], int n)
{
int i;
for (i = 0; i < n; i = i+1)
printf("%d ", arr[i]);
}
// Driver program to test above function
int main()
{
int arr[] = {1,4,7,2,9,3,0,8,6,5};
int size0 = sizeof(arr) / sizeof(arr[0]);
int size1 = (int) ((float)sizeof(arr) / sizeof(arr[0]) / 2 + 0.5);
int size2 = size0 - size1;
qsort((void *)arr+1, size2, 2*sizeof(arr[0]), comparator);
//sort odd positions
qsort((void *)arr, size1, 2*sizeof(arr[0]), comparator);
//sort even positions
printf("Output array is\n");
printArr(arr, size0);
printf("\n%d %d", size0, size1);
return 0;
}
It is possible to use qsort() for sorting of even/odd elements separately.
However, the setup must be changed slightly to accomplish this.
As Peter mentioned correctly (and I didn't consider before as I must admit) sorting for even elements will "destroy" the result for odd elements as swapping considers the element size which is denoted as pair of even and odd element.
This in mind, a solution can be done for all that if the result of first sorting is saved before second sorting is done.
In my sample, I copied the relevant elements after first sorting and merged them in after second sorting.
This is my sample testQSortEvenOdd.c:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int compEven(const int *p1, const int *p2)
{
return (p1[0] > p2[0]) - (p1[0] < p2[0]);
}
int compOdd(const int *p1, const int *p2)
{
return (p1[1] > p2[1]) - (p1[1] < p2[1]);
}
void printArray(size_t n, int *arr, int step)
{
for (; n--; arr += step) printf(" %d", *arr);
putchar('\n');
}
int main()
{
int arr[] = { 1, 4, 7, 2, 9, 3, 0, 8, 6, 5 };
enum { size = sizeof arr / sizeof *arr };
assert(!(size & 1));
/* sort odd positions */
qsort(arr, (size + 1) / 2, 2 * sizeof *arr,
(int(*)(const void*, const void*))&compOdd);
/* output of sorted array for odd positions */
puts("Odd elements sorted:");
printArray(size / 2, arr + 1, 2);
int arrRes[(size + 1) / 2];
for (size_t i = 1; i < size; i += 2) arrRes[i / 2] = arr[i];
/* sort even positions */
qsort(arr, (size + 1) / 2, 2 * sizeof *arr,
(int(*)(const void*, const void*))&compEven);
/* output of sorted array for even positions */
puts("Even elements sorted:");
printArray((size + 1) / 2, arr, 2);
/* merge array with copy */
for (size_t i = 1; i < size; i += 2) arr[i] = arrRes[i / 2];
puts("Merged elements:");
printArray(size, arr, 1);
/* done */
return 0;
}
Tested in Cygwin on Windows 10 (64 bit):
$ gcc --version
gcc (GCC) 6.4.0
$ gcc -std=c11 -o testQSortEvenOdd testQSortEvenOdd.c
$ ./testQSortEvenOdd
Odd elements sorted:
2 3 4 5 8
Even elements sorted:
0 1 6 7 9
Merged elements:
0 2 1 3 6 4 7 5 9 8
$
Some additional notes:
The way I (and the questioner) used qsort(), it handles two consecutive int values at once. Hence, it must be granted that the array has an appropriate number of elements. (Otherwise, qsort() either does out-of-bound access or cannot consider the last element.) To consider this fact, I inserted the
assert(!(size & 1));
which can be read as "Assure that the array has an even number of elements."
I decided to make separate functions compEven() and compOdd() as IMHO it simplified things. I changed the signature of both to my needs and got complains (warnings) from gcc about wrong function signature. Therefore, I casted the function pointers to the expected type (to make gcc silent).
Jonathon gave a nice hint to make the comparison functions robust against underflow issues. return p1[0] - p2[0]; can cause wrong results when the difference becomes greater than INT_MAX or smaller than INT_MIN. Instead he recommends to use:
return (p1[0] > p2[0]) - (p1[0] < p2[0]);
which never can have any overflow/underflow issues.
How it works:
In case a < b: (a > b) - (a < b) ⇒ 0 - 1 ⇒ -1
In case a == b: (a > b) - (a < b) ⇒ 0 - 0 ⇒ 0
In case a > b: (a > b) - (a < b) ⇒ 1 - 0 ⇒ 1
Very clever Jonathan Leffler – I'm impressed.
qsort:
void qsort( void *ptr, size_t count, size_t size,
int (*comp)(const void *, const void *) );
Sorts the given array pointed to by ptr in ascending order. The array contains count elements of size bytes. Function pointed to by comp is used for object comparison.
ptr - pointer to the array to sort
count - number of element in the array
size - size of each element in the array in bytes
comp - comparison function which returns a negative integer value if
the first argument is less than the second,
In your program, you are passing size of each element as 2*sizeof(arr[0]) which results in 8 bytes which is incorrect input to qsort(). Hence you are getting incorrect output.
qsort needs a contiguous block of memory to function properly.
If you need to sort odd and even indexed elements separately, you could start by separating the elements, sort them indipendently and then merge the two parts.
You can do that even without allocating any extra memory:
#include <stdio.h>
#include <stdlib.h>
int less_int(const void *lhs, const void *rhs)
{
return *(const int *)lhs < *(const int *)rhs ? -1
: *(const int *)lhs > *(const int *)rhs ? 1 : 0;
}
int greater_int(const void *lhs, const void *rhs)
{
return *(const int *)lhs > *(const int *)rhs ? -1
: *(const int *)lhs < *(const int *)rhs ? 1 : 0;
}
void sort_ascending(int* arr, size_t n)
{
qsort(arr, n, sizeof *arr, less_int);
}
void sort_descending(int* arr, size_t n)
{
qsort(arr, n, sizeof *arr, greater_int);
}
inline void swap_int(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
size_t partition_odd_even(int* arr, size_t n )
{
size_t n_odds = n - n / 2;
for (size_t i = 1, j = n_odds + n_odds % 2; i < n_odds; i += 2, j += 2)
{
swap_int(arr + i, arr + j);
}
return n_odds;
}
void interleave_odd_even(int* arr, size_t n )
{
size_t n_odds = n - n / 2;
for (size_t i = 1; i < n_odds; ++i )
{
for (size_t j = n_odds - i; j < n_odds + i; j += 2)
{
swap_int(arr + j, arr + j + 1);
}
}
}
void print_arr(int* arr, size_t n);
int main(void)
{
int arr[] = {1, 4, 7, 2, 9, 3, 0, 8, 6, 5};
size_t arr_size = sizeof arr / sizeof *arr;
print_arr(arr, arr_size);
size_t n_odds = partition_odd_even(arr, arr_size);
size_t n_evens = arr_size - n_odds;
// print_arr(arr, arr_size);
sort_ascending(arr, n_odds);
// print_arr(arr, n_odds);
sort_descending(arr + n_odds, n_evens);
// print_arr(arr + n_odds, n_evens);
interleave_odd_even(arr, arr_size);
print_arr(arr, arr_size);
return 0;
}
void print_arr(int* arr, size_t n)
{
for(size_t i = 0; i < n; ++i)
{
printf(" %d", arr[i]);
}
puts("");
}
Which gives:
1 4 7 2 9 3 0 8 6 5
0 8 1 5 6 4 7 3 9 2
EDIT
As noted in the comments below by greybeard the code above is not really time efficient as the merge part is O(N²). Using a temporary array which contains only the elements to be sorted in a particular way, the following program only need O(N) extra time and O(N/K) space, where K is the number of different sorting order needed (2 in OP's question).
Jonathan Leffler also pointed out that it could be made more general allowing the algorithm "to handle 3, 4, … N evenly interlaced sub-arrays, possibly with different sort orders for each". I implemented it in the following snippet by passing to the sort function an array of pointer to compare functions.
#include <stdio.h>
#include <stdlib.h>
// compare functions
typedef int (*PCMPFN)(const void*, const void*);
int ascending_cmp_int(const void *lhs, const void *rhs)
{
return *(const int *)lhs < *(const int *)rhs ? -1
: *(const int *)lhs > *(const int *)rhs ? 1 : 0;
}
int descending_cmp_int(const void *lhs, const void *rhs)
{
return *(const int *)lhs > *(const int *)rhs ? -1
: *(const int *)lhs < *(const int *)rhs ? 1 : 0;
}
// This function is never called. Whithout knowing the actual implementation
// of 'qsort' we can't make any assumption
int untouched_cmp_int(const void *lhs, const void *rhs)
{
(void)lhs; // Those parameters are unused here, this is to avoid a warning
(void)rhs;
return 0;
}
// Copy the elements of the source array starting from index 'start' with stride 'step'
size_t strided_split(int* dest, const int *src, size_t n, size_t start, size_t step)
{
size_t j = 0;
for (size_t i = start; i < n; i += step, ++j)
{
dest[j] = src[i];
}
return j;
}
// Inverse of the previous
void strided_merge(int* dest, const int *src, size_t n, size_t start, size_t step)
{
for (size_t i = start, j = 0; j < n; i += step, ++j)
{
dest[i] = src[j];
}
}
// Apply different sort orders to different elements
void alternate_sort(int* arr, const size_t n, PCMPFN comps[], const size_t k)
{
int tmp[n/k + 1]; // Please note that VLA are optional in C11
for ( size_t i = 0; i < k; ++i )
{
if ( comps[i] == untouched_cmp_int )
continue;
// First select the elements
size_t n_copied = strided_split(tmp, arr, n, i, k);
// then sort only them as needed
qsort(tmp, n_copied, sizeof tmp[0], comps[i]);
// Once sorted, copy back the elements in the source array
strided_merge(arr, tmp, n_copied, i, k);
}
}
void print_arr(const int* arr, const size_t n);
int main(void)
{
int arr[] = {1, 4, 7, 2, 9, 3, 0, 8, 6, 5};
const size_t N = sizeof arr / sizeof *arr;
print_arr(arr, N);
PCMPFN compares[] = {
descending_cmp_int, untouched_cmp_int, ascending_cmp_int
};
const size_t K = sizeof compares / sizeof *compares;
alternate_sort(arr, N, compares, K);
print_arr(arr, N);
return 0;
}
void print_arr(const int* arr, const size_t n)
{
for(size_t i = 0; i < n; ++i)
{
printf(" %d", arr[i]);
}
puts("");
}
Given two arrays containing integers, figure out whether or not three consecutive integers are present in both arrays.
For example: A = [1, 4, 5, 7, 2] and B = [3, 1, 4, 5, 9] will result in "true" / 1 because [1, 4, 5] is present in both arrays.
My solution to this task is present below, but I feel like there must be a more optimized solution than this.
int consecutiveInts(int *a, int sizeA, int *b, int sizeB){
int i, j;
// Iterate over every integer in array b for every integer in array a.
for (i = 0 ; i < sizeA - 2 ; i++){
for (j = 0 ; j < sizeB - 2 ; j++){
if (a[i] == b[j] && a[i + 1] == b[j + 1] && a[i + 2] == b[j + 2])
return 1;
}
}
return 0;
}
For small arrays, OP approach is OK. For array lengths m,n it has O(m*n) run time.
An alternate makes 2 value arrays, sorts them and then looks for a common element. It has O(m*log2(m) + n*log2(n)) run time. Certainly faster with large arrays than OP's code.
typedef struct {
int i[3];
} int3;
void Init3(int3 *i3, const int *i, size_t n) {
while (n--) {
i3[n].i[0] = i[n];
i3[n].i[1] = i[n + 1];
i3[n].i[2] = i[n + 2];
}
}
int fcmp(const void *a, const void *b) {
return memcmp(a, b, sizeof (int3));
}
bool Pattern3(const int *a, size_t size_a, const int *b, size_t size_b) {
if (size_a < 3 || size_b < 3) return false;
int3 a3[size_a - 2];
Init3(a3, a, size_a - 2);
qsort(a3, size_a - 2, sizeof *a3, fcmp);
int3 b3[size_b - 2];
Init3(b3, b, size_b - 2);
qsort(b3, size_b - 2, sizeof *b3, fcmp);
while (size_a && size_b) {
int cmp = fcmp(&a[size_a - 1], &b[size_b - 1]);
if (cmp == 0) return true;
if (cmp > 0) size_a--;
else size_b--;
}
return false;
}
int main() {
int A[] = { 1, 4, 5, 7, 2 };
int B[] = { 3, 1, 4, 5, 9 };
printf("%d\n", Pattern3(A, sizeof A / sizeof *A, B, sizeof B / sizeof *B));
}
An alternative would use a bsearch() rather than form the 2nd int3 b3[]/qsort().
I think I cannot be wrong by sayin that declaring i and j outside of the loop is useless and not optimized.
Something like :
for (unsigned i = 0; i < sizeA - 2; i++) // i will only exist inside the loop
Would be a little better.
I use unsigned type because it is a habit I have taken when using an iterating variable. I think this is a matter which, if you are interested and not already informed, you could learn from by reading this topic.
Not sure it optimizes running speed, but I notice that in case there are repeated numbers you don't need to check them over and over again.
For example three sequential elements in the first array are all 1. After checking a[i] and seeing it's a mismatch you can skip directly to a[i + 3] without comparing a[i + 1] or a[i + 2] (they are also a mismatch).
The management of this condition, particularly if it's a short sequence of repeats, may not improve running time. You have to measure.
With code changes that do not affect the order of complexity, any candidate improvements need profiling (tests that measure the performance) to verify.
The following is still a O(n*m), yet with reduced coefficient as it can step through b[] faster if a[] has repeated values that also exist in b[]. This speeds the inner b[] loop where the majority of time is consumed.
Look at the a[] pattern for distinct values to so j may be advanced faster.
Example:
#define x 0
bool Pattern3(const int *a, size_t size_a, const int *b, size_t size_b) {
static const unsigned char deltas[2][2][2][2] = { //
// What type of pattern is a[0], a[1], a[2]?
{ { { 1, 1 }, // X Y Z
{ 1, 1 } }, // X Y Y
{ { 1, 2 }, // X Y X
{ x, x } } }, // not possible
{ { { 2, 1 }, // X X Y
{ x, x } }, // not possible
{ { x, x }, // not possible
{ 2, 3 } } } }; // X X X
for (unsigned i = 0; i + 2 < size_a; i++) {
const unsigned char *delta23 = deltas[a[0] == a[1]][a[0] == a[2]][a[1] == a[2]];
for (unsigned j = 0; j + 2 < size_b;) {
if (a[0] != b[j]) {
j++;
} else if (a[0 + 1] != b[j + 1]) {
j += delta23[0];
} else if (a[0 + 2] != b[j + 2]) {
j += delta23[1];
} else {
return true;
}
}
a++;
}
return false;
}
Other minor changes which may help.
In the above, swap a,b when size_a > size_b.
Use const as lesser compilers can optimized on that.
// int consecutiveInts(int *a, int sizeA, int *b, int sizeB){
int consecutiveInts(const int *a, int sizeA, const int *b, int sizeB){
Iterate from 2. Adjust indexing accordingly.
for (i = 2 ; i < sizeA ; i++){
...
try using the following loop
for(int i=0;i<A.length;i++)
{
for(int j=0;j<A.length;j++)
{
if(A[i]==B[j])
{
count=count+1; //It checks how many times equal elements have been found
//ensure to declare and initialize int count=0;
}
}
}
if(count>=3)
System.out.println("true");
How can one iterate through order of execution?
I am developing a piece of software that have several steps to compute over some data, and i was thinking in may changing the order of those steps pragmatically so i can check what would be the best order for some data.
Let me exemplify: I have let's say 3 steps (it's actually more):
stepA(data);
stepB(data);
stepC(data);
And I want a contraption that allow me to walk thought every permutation of those steps and then check results. Something like that:
data = originalData; i=0;
while (someMagic(&data,[stepA,stepB,stepC],i++)){
checkResults(data);
data = originalData;
}
then someMagic execute A,B then C on i==0. A, C then B on i==1. B, A then C on i==2 and so on.
You can use function pointers, maybe something like the following:
typedef void (*func)(void *data);
int someMagic(void *data, func *func_list, int i) {
switch (i) {
case 0:
func_list[0](data);
func_list[1](data);
func_list[2](data);
break;
case 1:
func_list[0](data);
func_list[2](data);
func_list[1](data);
break;
case 2:
func_list[1](data);
func_list[0](data);
func_list[2](data);
break;
default: return 0;
}
return 1;
}
func steps[3] = {
stepA,
stepB,
stepC
}
while (someMagic(&data, steps, i++)) {
....
}
The key is to find a way to iterate over the set of permutations of the [0, n[ integer interval.
A permutation (in the mathematical meaning) can be seen as a bijection of [0, n[ into itself and can be represented by the image of this permutation, applied to [0, n[.
for example, consider the permutation of [0, 3[:
0 -> 1
1 -> 2
2 -> 0
it can be seen as the tuple (1, 2, 0), which in C, translate naturally to the array of integers permutation = (int []){1, 2, 0};.
Suppose you have an array of function pointers steps, then for each permutation, you'll then want to call steps[permutation[i]], for each value of i in [0, n[.
The following code implements this algorithm:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static void stepA(int data) { printf("%d: %s\n", data, __func__); }
static void stepB(int data) { printf("%d: %s\n", data, __func__); }
static void stepC(int data) { printf("%d: %s\n", data, __func__); }
static void (* const steps[])(int) = {stepA, stepB, stepC,};
static int fact(int n) { return n == 0 ? 1 : fact(n - 1) * n; }
static int compare_int(const void *pa, const void *pb)
{
return *(const int *)pa - *(const int *)pb;
}
static void get_next_permutation(int tab[], size_t n)
{
int tmp;
unsigned i;
unsigned j;
unsigned k;
/* to find the next permutation in the lexicographic order
* source: question 4 (in french, sorry ^^) of
* https://liris.cnrs.fr/~aparreau/Teaching/INF233/TP2-permutation.pdf
. */
/* 1. find the biggest index i for which tab[i] < tab[i+1] */
for (k = 0; k < n - 1; k++)
if (tab[k] < tab[k + 1])
i = k;
/* 2. Find the index j of the smallest element, bigger than tab[i],
* located after i */
j = i + 1;
for (k = i + 1; k < n; k++)
if (tab[k] > tab[i] && tab[k] < tab[j])
j = k;
/* 3. Swap the elements of index i and j */
tmp = tab[i];
tab[i] = tab[j];
tab[j] = tmp;
/* 4. Sort the array in ascending order, after index i */
qsort(tab + i + 1, n - (i + 1), sizeof(*tab), compare_int);
}
int main(void)
{
int n = sizeof(steps) / sizeof(*steps);
int j;
int i;
int permutation[n];
int f = fact(n);
/* first permutation is identity */
for (i = 0; i < n; i++)
permutation[i] = i;
for (j = 0; j < f; j++) {
for (i = 0; i < n; i++)
steps[permutation[i]](i);
if (j != f - 1)
get_next_permutation(permutation, n);
}
return EXIT_SUCCESS;
}
The outer loop in main, indexed by j, iterates over all the n! permutations, while the inner one, indexed by i, iterates overs the n steps.
The get_next_permutation modifies the permutation array in place, to obtain the next permutation in the lexicographical order.
Note that it doesn't work when the permutation in input is the last one (n - 1, ..., 1, 0), hence the if (j != f - 1) test.
One could enhance it to detect this case (i isn't set) and to put the first permutation (0, 1, ..., n - 1) into the permutation array.
The code can be compiled with:
gcc main.c -o main -Wall -Wextra -Werror -O0 -g3
And I strongly suggest using valgrind as a way to detect off-by-one errors.
EDIT: I just realized I didn't answer the OP's question precisely. The someMagic() function would allow a direct access to the i-th permutation, while my algorithm only allows to compute the successor in the lexicographic order. But if the aim is to iterate on all the permutations, it will work fine. Otherwise, maybe an answer like this one should match the requirement.
I've come to a solution that is simple enough:
void stepA(STRUCT_NAME *data);
void stepB(STRUCT_NAME *data);
void stepC(STRUCT_NAME *data);
typedef void (*check)(STRUCT_NAME *data);
void swap(check *x, check *y) {
check temp;
temp = *x;
*x = *y;
*y = temp;
}
void permute(check *a, int l, int r,STRUCT_NAME *data) {
int i, j = 0, score;
HAND_T *copy, *copy2, *best_order = NULL;
if (l == r) {
j = 0;
while (j <= r) a[j++](data);
} else {
for (i = l; i <= r; i++) {
swap((a + l), (a + i));
permute(a, l + 1, r, data);
swap((a + l), (a + i));
}
}
}
check checks[3] = {
stepA,
stepB,
stepC,
};
int main(void){
...
permute(checks,0,2,data)
}
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]);