Quick sort and bubble sort give different results - c

I'm facing with a singular issue:
I have a big table which content is a lot of pair of numbers. I have to sort them in descending order. I wrote a BubbleSort procedure and works fine, but is very slow to do its job. So I used a QuickSort procedure and... Data inside of the array changes after the sort!
So I tried with a sample table, with similar dimensions and "easy-to-write" content, basically a cicle which assign to
table[i][0]=i*3
and
table[i][1]=i*5
and... Works fine.
The code used is the following:
typedef struct MATCHES {
short size;
unsigned short values[10000][2];
} MATCHES;
int partition(MATCHES **data, int left, int right, int pivot, int col){
int temp;
int i;
int storeIndex = left;
int pivotVal = (**data).values[pivot][col];
(**data).values[pivot][col] = (**data).values[right][col];
(**data).values[right][col] = pivotVal;
for(i = left; i < right; i++){
if ((**data).values[i][col] >= pivotVal){ //Change this to greater then and BOOM we're done
temp = (**data).values[i][col];
(**data).values[i][col] = (**data).values[storeIndex][col];
(**data).values[storeIndex][col] = temp;
storeIndex++;
}
}
temp = (**data).values[storeIndex][col];
(**data).values[storeIndex][col] = (**data).values[right][col];
(**data).values[right][col] = temp;
return storeIndex;
}
void quickSort(MATCHES **vec, int left, int right, int col) {
int r;
if (right > left) {
r = partition(vec, left, right, right+1/2, col);
quickSort(vec, left, r - 1, col);
quickSort(vec, r + 1, right, col);
}
}
void sorter(MATCHES *table) {
quickSort(&table, 0, (*table).size-1, 0);
quickSort(&table, 0, (*table).size-1, 1);
}
int main () {
MATCHES table;
table.size=10000;
int i;
for (i=0; i<table.size; i++) {
table.values[i][0]=i*3;
table.values[i][1]=i*5;
}
printf("Unsorted\n");
for (i=0; i<table.size; i++)
printf("%d %d\n",table.values[i][0],table.values[i][1]);
sorter(&table);
printf("Sorted\n");
for (i=0; i<table.size; i++)
printf("%d %d\n",table.values[i][0],table.values[i][1]);
return 0;
}
For doing another try, I took the data I need to sort into this program and result is again wrong.
I'll link the code, since is very long due the initialization vector.
http://pastebin.com/Ztwu6iUP
Thanks in advance for any help!
EDIT:
I found a partial solution. Instead of using quickSort, that is unstable, I used mergeSort. Now, when I sort the second time the table, for every duplicate (or three times the same value) on the second column, in the first I have data sorted in ascending order.
The code is the following:
void merge(MATCHES *v, int i1, int i2, int fine, int col, MATCHES *vout) {
int i=i1, j=i2, k=i1;
while (i<=i2-1 && j<=fine) {
if ((*v).values[i][col]>(*v).values[j][col]) {
(*vout).values[k][0]=(*v).values[i][0];
(*vout).values[k][1]=(*v).values[i][1];
i++;
}
else {
(*vout).values[k][0]=(*v).values[j][0];
(*vout).values[k][1]=(*v).values[j][1];
j++;
}
k++;
}
while (i<=i2-1){
(*vout).values[k][0]=(*v).values[i][0];
(*vout).values[k][1]=(*v).values[i][1];
i++;
k++;
}
while (j<=fine){
(*vout).values[k][0]=(*v).values[j][0];
(*vout).values[k][1]=(*v).values[j][1];
j++;
k++;
}
for (i=i1; i<=fine; i++) {
(*v).values[i][0]=(*vout).values[i][0];
(*v).values[i][1]=(*vout).values[i][1];
}
}
void mergeSort(MATCHES *v, int iniz, int fine, int col, MATCHES *vout) {
int mid;
if(iniz<fine){
mid=(fine+iniz)/2;
mergeSort(v, iniz, mid, col, vout);
mergeSort(v, mid+1, fine, col, vout);
merge(v, iniz, mid+1, fine, col, vout);
}
}
Any hint for this?

In order to use quicksort to get stability, you need to answer the following question.
Can I tell the difference between a1 and a2?
If a1 and a2 differ because they have a secondary field, then there is a 'stable' solution with quick sort.
If a1 and a2 differ because they were added at different times (a field which doesn't matter), then the sort is unstable and will sometimes have a1 before a2 and sometimes after.
In your question, it is not clear if these numbers are linked
1,9
5,8
3,7
4,6
Should that go to :-
1,6
3,7
4,8
5,9
or
4,6
3,7
5,8
1,9
Are there 2 independent sorts? or is it a secondary field sort.
The merge code looks like a secondary field sort.
Sort on a secondary field
To sort on a secondary field, the comparison needs to be like :-
int compare( Atype* lhs, Atype * rhs )
{
if( lhs->field1 < rhs->field1 ) return -1;
if( lhs->field1 > rhs->field1 ) return 1;
if( lhs->field2 < rhs->field2 ) return -1;
if( lhs->field2 > rhs->field2 ) return 1;
/* more fields can be added here */
return 0;
}
Instead of sorting columns independently
quickSort(&table, 0, (*table).size-1, 0);
quickSort(&table, 0, (*table).size-1, 1);
Try the following.
Combining the sort into one go :-
quickSort(&table, 0, (*table).size-1 );
Change the comparison to take base array
int compare( short * lhs, short * rhs ) /* sort by 1 then 0 */
{
if( lhs[1] < rhs[1] ) return -1;
if( lhs[1] > rhs[1] ) return 1;
if( lhs[0] < rhs[0] ) return -1;
if( lhs[0] > rhs[0] ) return 1;
return 0;
}
Partition becomes
int partition(MATCHES **data, int left, int right, int pivot, int col){
int temp;
int i;
int storeIndex = left;
short pivotVal[2];
pivotVal[0] = (**data).values[pivot][0];
pivotVal[1] = (**data).values[pivot][1];
/* here you were jumbling pivot value - not keeping [0,1] together */
(**data).values[pivot][0] = (**data).values[right][0];
(**data).values[pivot][1] = (**data).values[right][1];
(**data).values[right][0] = pivotVal[0];
(**data).values[right][1] = pivotVal[1];
for(i = left; i < right; i++){
if ( compare( (**data).values[i] , pivotVal ) >= 0){ //Change this to greater then and BOOM we're done
temp = (**data).values[i][0];
(**data).values[i][0] = (**data).values[storeIndex][0];
(**data).values[storeIndex][0] = temp;
temp = (**data).values[i][1];
(**data).values[i][1] = (**data).values[storeIndex][1];
(**data).values[storeIndex][1] = temp;
storeIndex++;
}
}
temp = (**data).values[storeIndex][0];
(**data).values[storeIndex][0] = (**data).values[right][0];
(**data).values[right][0] = temp;
temp = (**data).values[storeIndex][1];
(**data).values[storeIndex][1] = (**data).values[right][1];
(**data).values[right][1] = temp;
return storeIndex;
}

Related

How to find the minimum number of coins needed for a given target amount(different from existing ones)

This is a classic question, where a list of coin amounts are given in coins[], len = length of coins[] array, and we try to find minimum amount of coins needed to get the target.
The coins array is sorted in ascending order
NOTE: I am trying to optimize the efficiency. Obviously I can run a for loop through the coins array and add the target%coins[i] together, but this will be erroneous when I have for example coins[] = {1,3,4} and target = 6, the for loop method would give 3, which is 1,1,4, but the optimal solution is 2, which is 3,3.
I haven't learned matrices and multi-dimensional array yet, are there ways to do this problem without them? I wrote a function, but it seems to be running in an infinity loop.
int find_min(const int coins[], int len, int target) {
int i;
int min = target;
int curr;
for (i = 0; i < len; i++) {
if (target == 0) {
return 0;
}
if (coins[i] <= target) {
curr = 1 + find_min(coins, len, target - coins[i]);
if (curr < min) {
min = curr;
}
}
}
return min;
}
I can suggest you this reading,
https://www.geeksforgeeks.org/generate-a-combination-of-minimum-coins-that-results-to-a-given-value/
the only thing is that there is no C version of the code, but if really need it you can do the porting by yourself.
Since no one gives a good answer, and that I figured it out myself. I might as well post an answer.
I add an array called lp, which is initialized in main,
int lp[4096];
int i;
for (i = 0; i <= COINS_MAX_TARGET; i++) {
lp[i] = -1;
}
every index of lp is equal to -1.
int find_min(int tar, const int coins[], int len, int lp[])
{
// Base case
if (tar == 0) {
lp[0] = 0;
return 0;
}
if (lp[tar] != -1) {
return lp[tar];
}
// Initialize result
int result = COINS_MAX_TARGET;
// Try every coin that is smaller than tar
for (int i = 0; i < len; i++) {
if (coins[i] <= tar) {
int x = find_min(tar - coins[i], coins, len, lp);
if (x != COINS_MAX_TARGET)
result = ((result > (1 + x)) ? (1+x) : result);
}
}
lp[tar] = result;
return result;
}

Hoare quicksort in c

Similarly to other users I am using this wikipedia algorithm. However I have tried to reimplement the algorithm using pointer arithmetic. However I'm having difficulty finding where I've gone wrong.
I think that this if statement is probably the cause but I'm not be sure.
...
if (left >= right) {
ret = (right - ptr);
return ret;
}
temp = *left;
*left = *right;
*right = temp;
/* sortstuff.h */
extern void quicksort(const size_t n, int * ptr);
/* sortstuff.c */
size_t quicksortpartition(const size_t n, int * ptr);
void quicksort(const size_t n, int * ptr) {
int* end = ptr + n - 1;
// for debug purposes
if (original_ptr == NULL) {
original_ptr = ptr;
original_count = n;
}
if (n > 1) {
size_t index = quicksortpartition(n, ptr);
quicksort(index, ptr);
quicksort(n - index - 1, ptr + index + 1);
}
return;
}
size_t quicksortpartition(const size_t n, int * ptr) {
int* right = ptr + n - 1;
int* pivot = ptr + (n - 1) / 2;
int* left = ptr;
int temp;
size_t ret = NULL;
while (1) {
while (*left <= *pivot && left < pivot) {
++left;
}
while (*right > *pivot) {
--right;
}
if (left >= right) {
ret = (right - ptr);
return ret;
}
temp = *left;
*left = *right;
*right = temp;
//print_arr();
}
}
int main(void) {
}
/* main.c */
int array0[] = {5, 22, 16, 3, 1, 14, 9, 5};
const size_t array0_count = sizeof(array0) / sizeof(array0[0]);
int main(void) {
quicksort(array0_count, array0);
printf("array out: ");
for (size_t i = 0; i != array0_count; ++i) {
printf("%d ", array0[i]);
}
puts("");
}
I don't think there are any off by one errors
The code you have presented does not accurately implement the algorithm you referenced. Consider in particular this loop:
while (*left <= *pivot && left < pivot) {
++left;
}
The corresponding loop in the algorithm description has no analog of the left < pivot loop-exit criterion, and its analog of *left <= *pivot uses strict less-than (<), not (<=).
It's easy to see that the former discrepancy must constitute an implementation error. The final sorted position of the pivot is where the left and right pointers meet, but the condition prevents the left pointer ever from advancing past the initial position of the pivot. Thus, if the correct position is rightward of the initial position then the partition function certainly cannot return the correct value. It takes a more thoughtful analysis to realize that in fact, the partition function is moreover prone to looping infinitely in that case, though I think that's somewhat data-dependent.
The latter discrepancy constitutes a provisional error. It risks overrunning the end of the array in the event that the selected pivot value happens to be the largest value in the array, but that's based in part on the fact that the left < pivot condition is erroneous and must be removed. You could replace the latter with left < right to resolve that issue, but although you could form a working sort that way, it probably would not be an improvement on the logic details presented in the algorithm description.
Note, however, that with the <= variation, either quicksortpartition() needs to do extra work (not presently provided for) to ensure that the pivot value ends up at the computed pivot position, or else the quicksort function needs to give up its assumption that that will happen. The former is more practical, supposing you want your sort to be robust.
Pivot needs to be an int, not a pointer. Also to more closely follow the Wiki algorithm, the parameters should be two pointers, not a count and a pointer. I moved the partition logic into the quick sort function.
void QuickSort(int *lo, int *hi)
{
int *i, *j;
int p, t;
if(lo >= hi)
return;
p = *(lo + (hi-lo)/2);
i = lo - 1;
j = hi + 1;
while (1){
while (*(++i) < p);
while (*(--j) > p);
if (i >= j)
break;
t = *i;
*i = *j;
*j = t;
}
QuickSort(lo, j);
QuickSort(j+1, hi);
}
The call would be:
QuickSort(array0, array0+array0_count-1);

Changing the contents of an array in a recursive function

I am having trouble understanding something regarding recursion and arrays.
basically, what the program does is to check what is the maximum weights of items that can be placed in two boxes. I know it's far from perfect as it is right now, but this is not the point.
Generally everything is working properly, however, now I decided that I want to see the contents of each box when the weight is maximal. For this purpose I tried using arr1 and arr2.
I don't understand why I get different results for arr1 and arr2 (the first options gives me what I want, the second does not).
This is the program:
#define N 5
int help(int items[N][2], int box1[N], int box2[N], int rules[N][N],
int optimal,int current_weight,int item,int arr1[],int arr2[])
{
if (item == N)
{
if(current_weight>optimal) //This is the first option
{
memcpy(arr1,box1,sizeof(int)*N);
memcpy(arr2,box2,sizeof(int)*N);
}
return current_weight;
}
int k = items[item][1]; int sol;
for (int i = 0; i <= k; i++)
{
for (int j = 0; i+j <= k; j++)
{
box1[item] += i; box2[item] += j;
if (islegal(items, box1, box2, rules))
{
sol = help(items, box1, box2, rules, optimal,
current_weight + (i + j)*items[item][0],item+1,arr1,arr2);
if (sol > optimal)
{
optimal = sol;
memcpy(arr1,box1,sizeof(int)*N); //This is the second option
memcpy(arr2,box2,sizeof(int)*N);
}
}
box1[item] -= i; box2[item] -= j;
}
}
return optimal;
}
int insert(int items[N][2], int rules[N][N])
{
int box1[N] = { 0 }; int arr1[N] = { 0 };
int box2[N] = { 0 }; int arr2[N] = { 0 };
int optimal = 0;
int x = help(items, box1, box2, rules,0, 0,0,arr1,arr2);
print(arr1, N);
print(arr2, N);
return x;
}
Can anyone explain what causes the difference? Why the first option is correct and the second is not? I couldn't figure it out by my own.
Thanks a lot.
This doesn't work because when you pass box1 and box2 to help, they are mutated by help. It's pretty obvious from the algorithm that you want them to not be mutated. So, we can do as follows:
int help(int items[N][2], int box1in[N], int box2in[N], int rules[N][N],
int optimal,int current_weight,int item,int arr1[],int arr2[])
{
int box1[N];
int box2[N];
memcpy(box1, box1in, sizeof(int)*N);
memcpy(box2, box2in, sizeof(int)*N);
Your algorithm may still have problems but that problem is now removed.

How can I make this more efficient? (Merging arrays in C)

The program is supposed to merge two arrays and place them in an output array. What I have is:
void Merge(int *arr1, int *arr2, int *output, int arr1size, int arr2size) {
int arr2count = 0, arr1count = 0;
while (arr1count < arr1size) {
if (arr2count >= arr2size) { /* dump arr1 because arr2 is done */
*output++ = *arr1++;
arr1count++;
}
else if (*arr1 < *arr2) {
*output++ = *arr1++;
arr1count++;
}
else {
*output++ = *arr2++;
arr2count++;
}
}
while (arr2count++ < arr2size) { /* dump arr2 */
*output++ = *arr2++;
}
}
How can I make this more efficient? I mean, strip literally any bit of code off to make it slightly more efficient.
For arguement's sake, consider the triple while loop implementation (shown below) less efficient.
while (arr1count < arr1size && arr2count < arr2size) { .... }
while (arr1count < arr1size) { .... }
while (arr2count < arr2size) { .... }
Also, this must use pointer notation, not array notation (I wish...)
I tried removing variables and increments. Note these are minor improvements while the algorithm still takes O(m+n) time.
Edit: incorporated the breaking of loop as mentioned by user2048454
Edit2: Removed two while loops and replaced with memcpy.Thanks to FUZxxl
void Merge2(int *arr1, int *arr2, int *output, int *a1last, int *a2last) {
while (arr1 < a1last && arr2 < a2last) {
if (*arr1 < *arr2) {
*output++ = *arr1++;
}
else {
*output++ = *arr2++;
}
}
/* Replaced while with memcpy () */
memcpy(output,arr1,sizeof(int)*(a1last-arr1));
memcpy(output,arr2,sizeof(int)*(a2last-arr2));
}
}
int main()
{
int a[]={1,3,5,7};
int b[]={2,4,6,8};
int c[10];
int i;
Merge2(a,b,c,&a[4],&b[4]); //&a[4] points to the end address of the array. Do not access value at that address, it is "out of bounds"
for(i=0; i<8; i++)
printf("%d ",c[i]);
printf("\n");
return 0;
}
Something like this?
void Merge(int *arr1, int *arr2, int *output, int arr1size, int arr2size) {
for (int i=0,i1=0,i2=0; i<arr1size+arr2size; i++) {
if (i1==arr1size) *output++ = *arr2++;
else if (i2==arr2size) *output++ = *arr1++;
else if (*arr1<*arr2) *output++ = *arr1++, i1++;
else *output++ = *arr2++, i2++;
}
}
Judging from the above code, the arrays are initially sorted and output should also contain sorted values.
One idea because of the restriction you mention would be to not use arr1count/arr2count, and use instead:
arr1last/arr2last
where:
"arr1last=arr1+arr1size" and "arr2last=arr2+arr2size"
this way you won't have to increment a counter and the compiler will juggle with fewer variables(--*count --*size ++*last) just do the compare on arr1 < arr1last. same for arr2
Also your first if when true, will always be true, so depending on the size of your arrays it might be worth breaking out at that point and going with the triple loop implementation you've mentioned, because the above 2 loop implementation might be inefficient if arr2size=1, arr1size=999 and arr2[0] would be among the first values in 'output'

Find number of paths in a 2d binary array (C)

I have been asked this question during an interview, and have been struggling to find an elegant solution (in C), Problem statement:
You are given a two-dimensional array with M rows and N columns.
You are initially positioned at (0,0) which is the top-left cell in
the array.
You are allowed to move either right or downwards.
The array is filled with 1′s and 0′s. A 1 indicates that you can move
through that cell, a 0 indicates that you cannot move through the
cell.
Write a function in C ‘numberOfPaths’ which takes in the above two dimensional array, return the number of valid paths from the top-left cell to the bottom-right cell (i.e. [0,0] to [M-1,N-1]).
Edit: forgot to mention that the requirement is for a recursive solution
help would be greatly appreciated!
Thanks
If you are looking for a recursive solution you can use DFS.
DFS (array, x, y)
{
if (array [x][y]==0 || x>M || y>N){
return;
}
if (x==M && y==N){
count++;
return;
}
DFS (array, x, y+1);
DFS (array, x+1, y);
}
The number of paths to a given point is just the number of paths to the point above, plus the number of paths to the point to the left. So, the pseudo-code would roughly be:
num_paths[0][0] = 1;
for (x = 0; x < M; ++x)
for (y = 0; y < N; ++y)
if (!allowed_through[x][y])
num_paths[x][y] = 0;
else
num_paths[x][y] = num_paths[x-1][y] + num_paths[x][y-1];
You need special cases for x=0 and y=0, but otherwise, I think that should do.
#include <stdio.h>
int count=0;
int maxrows = 10;
int maxcols = 10;
int M, N;
void DFS (int array[][10], int x, int y)
{
int r, c;
/* process element at input row and column */
if (array [x][y]==0 || x>M || y>N){
/* no path forward; return */
return;
}
if (x==M-1 && y==N-1){
/* found path; increment count */
count++;
return;
}
/* recurse: to matrix starting from same row, next column */
r = x;
c = y +1;
if (c < N-1) {
DFS (array, r,c);
} else {
/* if last column - check to see */
/* if rest of rows in last column allow for a path */
int tr = r;
while ( tr <= M-1) {
if (array[tr][c] == 1) {
tr++;
}
else {
return;
}
}
/* reached last node - path exists! */
count++;
}
/* recurse: to matrix starting from next row, same column */
r = x+1;
c = y;
if (r < M-1) {
DFS (array, r,c);
} else {
/* if last row - check to see */
/* if rest of columns in last row allow for a path */
int tc = c;
while ( tc <= N-1) {
if (array[r][tc] == 1) {
tc++;
} else {
return;
}
}
/* reached last node - path exists! */
count++;
}
}
int main () {
int i, j;
scanf("%d %d",&M,&N);
int a[10][10] = {};
int row, col;
for(i=0;i<M;i++)
for(j=0;j<N;j++)
scanf("%d", &a[i][j]);
if ((M > maxrows) || (N > maxcols)) {
printf("max of 10 rows and 10 cols allowed for input\n");
return (-1);
};
/* print input matrix */
for(row=0;row<M;row++) {
for(col=0;col<N;col++){
printf("%d ",a[row][col]);
}
printf(" EOR\n");
}
DFS(a,0,0);
printf("number of paths is %d\n", count);
return 0;
}
Try this function its a preliminary step before printing all the paths.
If the size of the vector Out is 0 then the # of paths are 0, but if size(Out) > 0 then the size of vector Nodes + 1 are the total number of paths from top left to bottom right.
#include <iostream>
#include <vector>
using namespace std;
typedef vector<pair<int,int> > vPii;
bool pathTL2BR( int Arr2D[][4], vPii &Out, vPii &Nodes,
int _x,int _y, int _M, int _N)
{
bool out1 = false;
bool out2 = false;
if( Arr2D[_x][_y] == 1 )
{
if( _y+1 < _N )
out1 = pathTL2BR( Arr2D, Out, Nodes, _x, _y+1, _M, _N);
if( _x+1 < _M )
out2 = pathTL2BR( Arr2D, Out, Nodes, _x+1, _y, _M, _N);
if( (out1 || out2) ||
( (_x == (_M-1)) && (_y == (_N-1)) ) )
{
if(out1 && out2)
Nodes.push_back( make_pair(_x,_y ) );
Out.push_back( make_pair(_x,_y ) );
return true;
}
else
return false;
}
else
return false;
}
// Driver program to test above function
int main()
{
int Arr2D[][4] = {
{1,1,1,1},
{0,1,0,1},
{0,1,0,1},
{0,1,0,1}
};
vPii Out;
vPii Nodes;
vector<vPii> Output;
pathTL2BR( Arr2D, Out, Nodes, 0, 0, 4, 4);
return 0;
}
This is a python solution, I have put explanations in the comments.
def find_num_paths(arr_2D, i, j):
# i,j is the start point and you have to travel all the way back to 0,0
if i == j and i == 0:
return 1 # you have reached the start point
if i < 0 or j < 0 or arr_2D[i][j] == 0: # out of range or no path from that point
return 0
if arr_2D[i][j] == 1:
return find_num_paths(arr_2D, i, j-1) + find_num_paths(arr_2D, i-1, j) + find_num_paths(arr_2D, i-1, j-1) # you could go one step above, to the left or diagonally up.

Resources