K&R Qsort example with Pointers and Arrays confusion - c

I find it difficult to understand the following snippet of code. I understand the pointer to function mannerism showed, but where I find confusion is in the indicated lines.
void qsort(void **v, int left, int right, int (*comp) (void *, void *))
{
int i, last;
void swap(int **v, int i, int j);
if (left >= right) /* do nothing if array contains */
return; /* fewer than two elements */
swap(v, left, (left + right)/2); /* move partition elem */ [1]
last = left; /* to v[0] */ [2]
for (i = left + 1; i <= right; i++) /* partition */ [3]
if ((*comp) (v[i], v[left]) < 0) [4]
swap(v, ++last, i); [5]
swap(v, left, last); /* restore partition elem */ [6]
qsort(v, left, last - 1); [7]
qsort(v, last + 1, right); [8]
}
Can someone explain this routine to me, especially the indicated lines, just tell me what it's doing, because I can't figure this qsort out, the eskimo guide I read whilst reading k&r said that the qsort routine is rubbish, and overly complicated. I just need to understand why it's written like this, because it makes no sense to me.
Thanks, if for nothing, for reading this.

This is a beautiful piece of code!
First off, it's important that you understand the idea behind quicksort:
1) Take a list of numbers.
2) Pick one, call it X.
3) Make two lists, one of all the numbers smaller than X, and one of all the numbers bigger.
4) Sort the numbers smaller than X. Sort the numbers bigger than X.
The idea is that if we get lucky and pick a good value for X, then the list of numbers smaller than X is the same size as the list of numbers bigger than X. If we start with 2*N+1 numbers, then we get two lists of N numbers. Each time, we hope to divide by two, but we have to sort N numbers. How many times can we divide N by two? That's Log(N).
So, we sort N Log(N) times. This is great!
As for how the code works, here's the runthrough, with a little sketch. We'll pick a small array :)
here's our array: [DACBE]
at the start, left=0, pointing to D. right=4, pointing to E.
now, following the code, with your labelling:
[1] swap(v,0,2) [DACBE] -> [CADBE]
we've swapped our chosen value out and put it at the start of the array.
[2] last=0
this is a bit clever... we want to keep a counter so we know which values were greater and which less... you'll see how this progresses
[3] for (i=1;i<=4;i++)
for all the remaining elements in the list...
[4] if ((*comp)(v[i], 'C')<0)
if the value at i is LESS than 'C'...
[5] swap(v,++last,i);
put it at the start of the list!
let's run the code for 3,4,5
i=1:
[CADBE]
if ('A'<'C')
swap('A','A') (AND INCREMENT LAST!)
[CADBE]->[CADBE] (no change)
last=1
i=2:
[CADBE]
if ('D'<'C')
fails. move on.
i=3:
[CADBE]
if ('B'<'C')
swap('B','D') And increment last!
[CADBE] -> [CABDE] (lookit! it's sorting!)
last=2
i=4:
[CABDE]
if ('E'<'C')
fails. move on.
Ok, ace. so that loop gives is [CABDE], last=2 ('B')
Now line [6].... swap(left,last)... that's swap('C','B')
[CABDE] -> [BACDE]
Now, the magic of this is... it's partially sorted! BA < C < DE!
So now we sort the sub-lists!!
[7] -> [BA] -> [AB]
so
[BACDE] -> [ABCDE]
[8]-> [DE]->[DE]
so
[ABCDE] -> [ABCDE]
and we're done!

K&R's quick is an example of great coding but not a great example of how quicksort works. The purpose of the preswap is not intuitive and the identity swaps are inefficient and confusing. I have written a program to help clarify this. Code comments explain the issues.
I have compiled and tested only under Linux but Visual Studio should have no problem with this plain vanilla console app.
/***************************** QUICK.CPP ***************************************
Author: David McCracken
Updated: 2009-08-14
Purpose: This illustrates the operation of the quicksort in K&R "The C
Programming Language" (second edition p. 120). Many programmers are frustrated
when they attempt to understand quicksort in general from this version, which
was clearly not intended as a tutorial on quicksort but on the use of pointers
to functions. My program modifies the original to work only on ints in order to
focus on the sorting process. It can print the global list and recursive
sublist at each change to trace the sorting decision process. My program also
clarifies two confusing aspects, both involving unexplained swapping, of the
original by comparing its operation to that of two further modified versions.
One confusing thing that the original does is to swap an item with itself.
The code (modified for ints only) is:
last = left;
for( i = left+1 ; i <= right ; i++ )
if( v[i] < v[ left ] )
swap( v[ ++last ], v[ i ]);
Note that left and v[ left ] are loop-invariant. v[ left ] is the pivot.
A superfluous swap is performed on all values less than the pivot without an
earlier value greater than the pivot. For example, given sublist (after
preswap) 9,8,5,7,4,6, initially i = left + 1, selecting 8. Since this is less
than 9, last is incremented to point to the same element as i (selecting 8) and
a superfluous swap is performed. At the next iteration, last selects 8 while i
selects 5 and 5 is swapped with itself. This continues to the end of the
sublist. The sorting function krQuick2 is identical to krQuick but tests ++last
against i to avoid superfluous swapping. This certainly yields better
performance for practically no cost but, more importantly, helps to clarify
just what the code is trying to do, which is to find and swap a value that is
larger than the pivot with one that occurs later and is smaller than the pivot.
A second source of confusion is the purpose of the preswap, where the midpoint
value is swapped with the left-most. Since this is done without regard to
value, it cannot decrease entropy. In fact, it does exactly the opposite in the
very important case of a sublist that is already sorted, which normally makes
quicksort perform badly. This action deliberately unsorts a sorted list and
essentially does nothing to an unsorted one. This simple and cheap action
substantially improves average and worst case performance, as demonstrated by
the third variation, quick3, which just removes the preswap from krQuick2.
quick3 demonstrates that the preswap is not required; in fact that any value
can be chosen from the list to serve as the pivot. Only in the most unsorted
cases does quick3 exhibit slightly better performance than krQuick2 by virture
of skipping the preswap. With increasing initial order, the performance of
krQuick2 steadily improves over quick3.
Some confusion may also come from the testing of v[i] against v[left]. left and
v[ left ] are loop-invariant. An optimizing compiler should recognize this and
hoist the value out of the loop, but this loop-invariance is not immediately
obvious to someone studying this as an example of quicksort. During the swap
loop, v[left] serves only to hold the pivot value. An automatic could just as
easily hold the value and its purpose would be more clear. However, the code is
an example of indirection. We don't know what the list items are but we can be
sure that any one of them can fit into v[ left ] and that the swap function can
put it there. Thus, the one preswap operation does three things; it randomizes
a sorted sublist; it conveniently copies the pivot to a place where it won't be
subject to swapping; and it fills the hole in the loop left by extracting the
pivot. It does all of this without even knowing what the elements are and with
a function that we already have. This amazing programming feat is well worth
studying but not in the interest of understanding quicksort.
HOW TO USE THIS PROGRAM
There are three general variables, the function, the data to be sorted, and what
to display.
The simplified K&R original function, krQuick, is function 0. Function 1,
krQuick2, is krQuick with identity swaps removed. Function 2, quick3, is
krQuick2 without preswap.
The data to be sorted can be any one of five builtin lists or all of them or
a space-delimited list of decimal ints entered on the command line.
The displayed information affords a trace of the function's operation. In all
cases, the list is displayed before and after sorting, and executing statistics
are reported. If SHOW_NOTHING then nothing else is reported. If SHOW_GLOBAL,
the changing full list is displayed at each invocation of the recursive sort
function. If SHOW_LOCAL1, the sublist passed to the function is displayed before
it is modified. If SHOW_LOCAL, the sublist is displayed after each swap. If
SHOW_INDEX, the indices involved in swapping and the values at those indices
are shown before the swap occurs.These selections correspond to the SHOW_ enum
and are culmulative flags.
By default, all three functions are applied in succession to all five builtin
data lists, with SHOW_NOTHING. This is useful for comparing the performance of
the functions. For example, it shows that on the unordered list 11 0 10 1 9 2 8
3 7 4 6 5 quick3 uses 37 compares and 30 swaps while krQuick2 uses 38 compares
and 44 swaps. However, on the ordered list 0 1 2 3 4 5 6 7 8 9 10 11 quick3
uses 66 compares and 22 swaps while krQuick2 uses 25 compares and 28 swaps.
Command line arguments alter the content but not the order of operation. In all
cases, each selected function is applied to all selected data lists.
Command arguments are case-insensitive: F function selector, D data selector,
and S show what map. Each is followed without space by a single character.
F0, F1, F2, FA select function 0, 1, or 2 only or all functions.
D0, D1, D2, D3, D4, DA select builtin data list 0, 1, 2, 3, or 4 only or all.
S0 (default) shows no extra information.
S1 (GLOBAL) shows the full list (without "GLOBAL" legend) at each invocation.
S2 (LOCAL1) shows the sublist before processing.
S3 (GLOBAL+LOCAL1)
S4 (LOCAL) shows the sublist after each swap. It also shows the sublist before
processing.
S8 (INDEX) shows indices but these would never be shown without at least LOCAL,
which can't be combined with 8 in the single-digit argument.
SA (All)
Note that the Local legend includes a numeric suffix to identify where in the
point in the code that is reporting.
The most useful S formats are S1, S5, and SA (S0 is default).
After any F and S arguments, any space-delimited list of numbers will be taken
as the data list. Any D argument is ignored. For example:
quick 20 21 15 12 40 0
applies all three functions to the data, reporting only the unsorted and sorted
full lists and operational statistics.
quick f0 sa 20 21 15 12 40 0
applies only function 0 krQuick to the data, reporting everything.
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// ======================== DATA AND DECLARATIONS ===============================
#define DIM(A) ( sizeof A / sizeof A[0])
typedef unsigned int UINT;
enum { SHOW_NOTHING, SHOW_GLOBAL = 1, SHOW_LOCAL1 = 2, SHOW_LOCAL = 4,
SHOW_INDEX = 8, SHOW_ALL = 0xFF };
int showWhat = SHOW_NOTHING;
int list0[] = { 4,0,2,5,1,3 };
int list1[] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
int list2[] = { 11,10,9,8,7,6,5,4,3,2,1,0 };
int list3[] = { 11,9,7,5,3,1,0,2,4,6,8,10 };
int list4[] = { 11,0,10,1,9,2,8,3,7,4,6,5 };
static struct { int *list; int cnt; } lists[] =
{
{ list0, DIM( list0 )},
{ list1, DIM( list1 )},
{ list2, DIM( list2 )},
{ list3, DIM( list3 )},
{ list4, DIM( list4 )},
};
int total[ 1000 ];
int totalCnt;
int *userData = 0;
int userDataLen = 0;
int recursion; // Current recursion level.
int calls; // Number of times the sort function is called.
int depth; // Maximum recursion level.
int swaps; // Count of swaps.
int compares; // Count of list item compares.
int totCalls;
int totDepth;
int totCompares;
int totSwaps;
void (*sortFunc)( int *list, int left, int right );
char dArg = 'A'; // command line argument selects 0,1,2,3,4, or A
int dataList; // If dArg is numeric, this is its int value.
//============================== FUNCTIONS =====================================
// ------------------------------ indent --------------------------------------
// Print two spaces for each level of recursion to indent subsequent print
// output.
// ............................................................................
void indent( void )
{
for( int indent = 1 ; indent < recursion ; indent++ )
printf( " " );
}
// -------------------------------- show ---------------------------------------
// Print the given int list according to the global control setting showWhat
// and the given local identification. This may print nothing or the global
// list or the local sublist. It may or may not print the legend GLOBAL or
// LOCALx where x is the local ID, which tells at what point in the sort code
// we are showing the sublist.
// Returns: Nothing
// Arguments:
//- int *ia points to the int list.
//- int cnt is the number of elements in the list.
//- int local tells the local point in the sort routine if greater than 0. 0
// indicates that this is global. In either case, format is controlled by
// showWhat. If local is -1, the list is printed unconditionally and without
// any legend.
// Global:
//- showWhat bitmapped control word
//-- 0 (SHOW_NOTHING) This is the complete value, not a bit flag.
//-- 1 (SHOW_GLOBAL) Print the list if local is 0. If any other bit is also
// set, the GLOBAL legend is printed before the list.
//-- 2 (SHOW_LOCAL1) Print the list only if local is 1.
//-- 3 (SHOW_LOCAL) Print the list if local is 1 or greater.
//
// ...................... notes .............................................
// SHOW_NOTHING
// This exists because the callers don't test showWhat before calling. If we
// only want to show the initial unsorted list and final sorted version then
// SHOW_NOTHING blocks all print output from the sort function. The control
// function calls show with local = -1 to print the list.
// ..........................................................................
void show( int *ia, int cnt, int local )
{
if( local >= 0 )
{
switch( showWhat )
{
case SHOW_NOTHING:
return;
case SHOW_GLOBAL: // Only SHOW_GLOBAL
if( local > 0 )
return; // This is a local
break; // Print list without legend.
default: // Some combination of SHOW_GLOBAL, SHOW_LOCAL1, SHOW_LOCAL
if( local == 0 ) // global
{
if( ( showWhat & SHOW_GLOBAL ) == 0 )
return;
printf( "GLOBAL " );
}
else if( showWhat & SHOW_LOCAL || ( showWhat & SHOW_LOCAL1 && local == 1 ))
{
indent();
printf( "Local%d: ", local );
}
else
return;
}
}
for( int *end = ia + cnt ; ia < end ; ia++ )
printf( "%d ", *ia );
putchar( '\n' );
}
// -------------------------------- swap ---------------------------------------
void swap( int *p1, int *p2 )
{
int temp = *p2;
*p2 = *p1;
*p1 = temp;
++swaps;
}
// ------------------------------ krQuick --------------------------------------
// K&R's quick function modified to handle only integers and to use inline
// numeric comparison instead of an indirect comp function.
// .............................................................................
void krQuick( int *list, int left, int right )
{
int i, last;
++calls;
if( recursion > depth )
depth = recursion; // At first call recursion = 0 and depth is 0, i.e. no recursion yet.
++recursion;
show( total, totalCnt, 0 ); // GLOBAL
show( list + left, right - left + 1, 1 ); // LOCAL
if( left < right )
{
swap( list + left, list + (left + right) / 2 );
++swaps;
show( list + left, right - left + 1, 2 );
last = left;
for( i = left + 1 ; i <= right ; i++ )
{
++compares;
if( list[ i ] < list[ left ])
{
if( showWhat & SHOW_INDEX )
{
indent();
printf( "i=%d #i=%d left=%d #left=%d last=%d\n",
i, list[i], left, list[ left ], last );
}
swap( list + ++last, list + i );
show( list + left, right - left + 1, 3 );
++swaps;
}
}
swap( list + left, list + last );
show( list + left, right - left + 1, 4 );
++swaps;
krQuick( list, left, last - 1 );
krQuick( list, last + 1, right );
}
--recursion;
}
// ------------------------------- krQuick2 ------------------------------------
// K&R's quick function modified as in krQuick plus elimination of identity
// swaps.
// .............................................................................
void krQuick2( int *list, int left, int right )
{
int i, last;
++calls;
if( recursion > depth )
depth = recursion; // At first call recursion = 0 and depth is 0, i.e. no recursion yet.
++recursion;
show( total, totalCnt, 0 ); // GLOBAL
show( list + left, right - left + 1, 1 ); // LOCAL
if( left < right )
{
swap( list + left, list + (left + right) / 2 );
++swaps;
show( list + left, right - left + 1, 2 );
last = left;
for( i = left + 1 ; i <= right ; i++ )
{
++compares;
if( list[ i ] < list[ left ] && ++last != i )
{
if( showWhat & SHOW_INDEX )
{
indent();
printf( "i=%d #i=%d left=%d #left=%d last=%d\n",
i, list[i], left, list[ left ], last );
}
swap( list + last, list + i );
show( list + left, right - left + 1, 3 );
++swaps;
}
}
swap( list + left, list + last );
show( list + left, right - left + 1, 4 );
++swaps;
krQuick2( list, left, last - 1 );
krQuick2( list, last + 1, right );
}
--recursion;
}
// ------------------------------------ quick3 ---------------------------------
// krQuick2 modified to not do the preswap. In the K&R original, the purpose of
// the preswap is to introduce randomness into a presorted sublist. The sorting
// result is not changed by eliminating this but the performance degrades with
// more compares and swaps in all cases between average and worst. Only near the
// best case does eliminating the preswap improve performance.
// ............................................................................
void quick3( int *list, int left, int right )
{
int i, last;
++calls;
if( recursion > depth )
depth = recursion; // At first call recursion = 0 and depth is 0, i.e. no recursion yet.
++recursion;
show( total, totalCnt, 0 ); // GLOBAL
show( list + left, right - left + 1, 1 ); // LOCAL
if( left < right )
{
last = left;
for( i = left + 1 ; i <= right ; i++ )
{
++compares;
if( list[ i ] < list[ left ] && ++last != i )
{
if( showWhat & SHOW_INDEX )
{
indent();
printf( "i=%d #i=%d left=%d #left=%d last=%d\n",
i, list[i], left, list[ left ], last );
}
swap( list + last, list + i );
show( list + left, right - left + 1, 3 );
++swaps;
}
}
swap( list + left, list + last );
show( list + left, right - left + 1, 4 );
++swaps;
quick3( list, left, last - 1 );
quick3( list, last + 1, right );
}
--recursion;
}
static struct { void (*func)( int *list, int left, int right ) ; char *name ; } sortFuncs[] =
{
{ krQuick, (char*)"krQuick" },
{ krQuick2, (char*)"krQuick2 (no identity swaps)" },
{ quick3, (char*)"quick3 (no preswaps)" }
};
// ------------------------------------ sortOne --------------------------------
// Set up performance counters, invoke the currently selected sort on the current
// data list, and print the performance (for this one case of selected function
// applied to selected data list).
// .............................................................................
void sortOne( void )
{
recursion = 0;
calls = 0;
depth = 0;
swaps = 0;
compares = 0;
show( total, totalCnt, -1 );
sortFunc( total, 0, totalCnt - 1 );
show( total, totalCnt, -1 );
printf( "Calls = %d, depth = %d, compares = %d, swaps = %d\n",
calls, depth, compares, swaps );
printf( "---------------------------------\n" );
}
// ---------------------------- sortOneSet -------------------------------------
// Purpose: Apply the currently selected sort function to one data list.
void sortOneSet( int idx )
{
if( idx < 0 )
{
totalCnt = userDataLen;
memcpy( total, userData, totalCnt * sizeof( int ));
}
else
{
totalCnt = lists[ idx ].cnt;
memcpy( total, lists[ idx ].list, totalCnt * sizeof( int ));
}
sortOne();
totCalls += calls;
totDepth += depth;
totCompares += compares;
totSwaps += swaps;
}
// ------------------------- testOneFunc ---------------------------------------
// Purpose: Apply the selected function to one or all data lists.
// Returns: Nothing
// Arguments: int sel is 0,1,or 2, selecting krQuick, krQuick2, or quick3.
// Globals: char dArg is the data list selector command line argument. It is '0',
// '1', '2', or 'A'. 'A' selects all data lists. Otherwise, int dataList is the
// int value of dArg, which has already been translated for us by the command
// line processor.
// .............................................................................
void testOneFunc( int sel )
{
totCalls = 0;
totDepth = 0;
totCompares = 0;
totSwaps = 0;
sortFunc = sortFuncs[ sel ].func;
printf( "====== %s ======\n", sortFuncs[ sel ].name );
if( userDataLen != 0 )
sortOneSet( -1 );
else if( dArg == 'A' )
{
for( UINT idx = 0 ; idx < DIM( lists ) ; idx++ )
sortOneSet( idx );
printf( "Total: calls = %d, depth = %d, compares = %d, swaps = %d\n",
totCalls, totDepth, totCompares, totSwaps );
}
else
sortOneSet( dataList );
}
// --------------------------------- main --------------------------------------
// Purpose: Process command line arguments, set up show (print output) and data
// list selectors, and invoke testOneFunc either once for the selected function
// or for each of the three functions.
// .............................................................................
int main( int argc, char **argv )
{
char *cp;
char fArg = 'A'; // function selector 0,1,2,A
UINT idx;
showWhat = SHOW_NOTHING;
dArg = 'A';
for( int cnt = 1 ; cnt < argc ; cnt++ )
{
cp = argv[ cnt ];
switch( toupper( *cp ))
{
case 'F':
fArg = toupper( cp[1] );
break;
case 'D':
dArg = toupper( cp[1] );
if( dArg != 'A' )
{
dataList = dArg - '0';
if( dataList < 0 || dataList >= (int)DIM( lists ))
{
printf( "Error: bad data list selector %c\n", dArg );
return 1;
}
}
break;
case 'S': // show selector matches bit-mapped showWhat or N or A
++cp;
if( *cp != 0 || toupper( *cp ) != 'N' )
{
if( toupper( *cp ) == 'A' )
showWhat = SHOW_ALL;
else
showWhat = atoi( cp );
}
break;
default:
if( !isdigit( *cp ))
{
printf( "Error: There is no option %c\n", *cp );
return 1;
}
for( idx = 0 ; idx < DIM( total ) && cnt < argc ; idx++, cnt++ )
total[ idx ] = atoi( argv[ cnt ] );
userData = (int*)malloc( sizeof( int ) * idx );
if( userData == 0 )
{
printf( "Error: Unable to allocate memory for data list\n" );
return 2;
}
memcpy( userData, total, sizeof( int ) * idx );
userDataLen = idx;
}
}
switch( fArg )
{
case 'A':
for( UINT sfi = 0 ; sfi < DIM( sortFuncs ) ; sfi++ )
testOneFunc( sfi );
break;
case '0':
case '1':
case '2':
testOneFunc( fArg - '0' );
break;
default:
printf( "Error: bad function selector %c\n", fArg );
return 1;
}
return 0;
}
Results of quick
This uses all defaults, which is most useful for comparing the performance
of the three different functions.
====== krQuick ======
4 0 2 5 1 3
0 1 2 3 4 5
Calls = 7, depth = 2, compares = 8, swaps = 20
---------------------------------
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 15, depth = 3, compares = 25, swaps = 48
---------------------------------
11 10 9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 17, depth = 5, compares = 30, swaps = 62
---------------------------------
11 9 7 5 3 1 0 2 4 6 8 10
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 13, depth = 5, compares = 33, swaps = 56
---------------------------------
11 0 10 1 9 2 8 3 7 4 6 5
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 15, depth = 6, compares = 38, swaps = 60
---------------------------------
Total: calls = 67, depth = 21, compares = 134, swaps = 246
====== krQuick2 (no identity swaps) ======
4 0 2 5 1 3
0 1 2 3 4 5
Calls = 7, depth = 2, compares = 8, swaps = 16
---------------------------------
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 15, depth = 3, compares = 25, swaps = 28
---------------------------------
11 10 9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 17, depth = 5, compares = 30, swaps = 52
---------------------------------
11 9 7 5 3 1 0 2 4 6 8 10
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 13, depth = 5, compares = 33, swaps = 46
---------------------------------
11 0 10 1 9 2 8 3 7 4 6 5
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 15, depth = 6, compares = 38, swaps = 44
---------------------------------
Total: calls = 67, depth = 21, compares = 134, swaps = 186
====== quick3 (no preswaps) ======
4 0 2 5 1 3
0 1 2 3 4 5
Calls = 7, depth = 3, compares = 10, swaps = 10
---------------------------------
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 23, depth = 11, compares = 66, swaps = 22
---------------------------------
11 10 9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 23, depth = 11, compares = 66, swaps = 22
---------------------------------
11 9 7 5 3 1 0 2 4 6 8 10
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 15, depth = 7, compares = 46, swaps = 54
---------------------------------
11 0 10 1 9 2 8 3 7 4 6 5
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 19, depth = 6, compares = 37, swaps = 30
---------------------------------
Total: calls = 87, depth = 38, compares = 225, swaps = 138
*******************************************************************************
Results of quick f0 s5 d1
S5 format is best for displaying how the sublist changes during sorting. Since
LOCAL is displayed only after a swap, superfluous identity swaps (many in this
example) are readily apparent.
====== krQuick ======
0 1 2 3 4 5 6 7 8 9 10 11
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 0 1 2 3 4 5 6 7 8 9 10 11
Local2: 5 1 2 3 4 0 6 7 8 9 10 11
Local3: 5 1 2 3 4 0 6 7 8 9 10 11
Local3: 5 1 2 3 4 0 6 7 8 9 10 11
Local3: 5 1 2 3 4 0 6 7 8 9 10 11
Local3: 5 1 2 3 4 0 6 7 8 9 10 11
Local3: 5 1 2 3 4 0 6 7 8 9 10 11
Local4: 0 1 2 3 4 5 6 7 8 9 10 11
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 0 1 2 3 4
Local2: 2 1 0 3 4
Local3: 2 1 0 3 4
Local3: 2 1 0 3 4
Local4: 0 1 2 3 4
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 0 1
Local2: 0 1
Local4: 0 1
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1:
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 1
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 3 4
Local2: 3 4
Local4: 3 4
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1:
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 4
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 6 7 8 9 10 11
Local2: 8 7 6 9 10 11
Local3: 8 7 6 9 10 11
Local3: 8 7 6 9 10 11
Local4: 6 7 8 9 10 11
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 6 7
Local2: 6 7
Local4: 6 7
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1:
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 7
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 9 10 11
Local2: 10 9 11
Local3: 10 9 11
Local4: 9 10 11
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 9
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 11
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 15, depth = 3, compares = 25, swaps = 48
********************************************************************************
Results of quick f0 sa d1
This is the same as the previous example but shows the additional detail of index
values that lead to the swapping decision. However, the clutter tends to obscure
what is actually happening to the sublist.
====== krQuick ======
0 1 2 3 4 5 6 7 8 9 10 11
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 0 1 2 3 4 5 6 7 8 9 10 11
Local2: 5 1 2 3 4 0 6 7 8 9 10 11
i=1 #i=1 left=0 #left=5 last=0
Local3: 5 1 2 3 4 0 6 7 8 9 10 11
i=2 #i=2 left=0 #left=5 last=1
Local3: 5 1 2 3 4 0 6 7 8 9 10 11
i=3 #i=3 left=0 #left=5 last=2
Local3: 5 1 2 3 4 0 6 7 8 9 10 11
i=4 #i=4 left=0 #left=5 last=3
Local3: 5 1 2 3 4 0 6 7 8 9 10 11
i=5 #i=0 left=0 #left=5 last=4
Local3: 5 1 2 3 4 0 6 7 8 9 10 11
Local4: 0 1 2 3 4 5 6 7 8 9 10 11
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 0 1 2 3 4
Local2: 2 1 0 3 4
i=1 #i=1 left=0 #left=2 last=0
Local3: 2 1 0 3 4
i=2 #i=0 left=0 #left=2 last=1
Local3: 2 1 0 3 4
Local4: 0 1 2 3 4
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 0 1
Local2: 0 1
Local4: 0 1
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1:
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 1
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 3 4
Local2: 3 4
Local4: 3 4
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1:
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 4
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 6 7 8 9 10 11
Local2: 8 7 6 9 10 11
i=7 #i=7 left=6 #left=8 last=6
Local3: 8 7 6 9 10 11
i=8 #i=6 left=6 #left=8 last=7
Local3: 8 7 6 9 10 11
Local4: 6 7 8 9 10 11
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 6 7
Local2: 6 7
Local4: 6 7
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1:
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 7
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 9 10 11
Local2: 10 9 11
i=10 #i=9 left=9 #left=10 last=9
Local3: 10 9 11
Local4: 9 10 11
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 9
GLOBAL 0 1 2 3 4 5 6 7 8 9 10 11
Local1: 11
0 1 2 3 4 5 6 7 8 9 10 11
Calls = 15, depth = 3, compares = 25, swaps = 48

magic useful google keywords: QuickSort
e.g. google:how quicksort works turns up this explanation: http://www.angelfire.com/pq/jamesbarbetti/articles/sorting/001a_HowQuicksortWorks.htm among others.
Essentially, the code applies a variation of quicksort to the elements between the left and right boundaries specified.
For the lines you've identified:
swap the middle element with the first (left) one. it will become the "pivot".
keep track of the boundary between bigger and smaller elements. this is where the pivot belongs.
for every element after the first one,
if it's smaller than the pivot,
move it before the first bigger element.
move the pivot back into place.
recursively apply qsort to the elements before the pivot. (the smaller ones)
recursively apply qsort to the elements after the pivot. (the bigger ones)
Try applying the code yourself to a list of numbers, and see if it makes more sense then....

There's a bug in your code, the lines at the end:
qsort(v, left, last - 1); [7]
qsort(v, last + 1, right); [8]
should be:
qsort(v, left, last - 1, comp); [7]
qsort(v, last + 1, right, comp); [8]
Or am I missing something?
Furthermore, it's bad style to reuse names of the standard library, especially if the new function has a different signature than the one in the lib.
The function qsort of the standard library has this prototype:
void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *));
If your program is a bit bigger (more than one object file) this can give interesting bugs. Imagine another module calling the standard qsort function but as you have redefined it, with a compatible signature, but with a different semantic, you get an unexpected bug.

Hi I did the example from page 87. May be someone will understand from this. But before going for this code, see quicksort
/**
* qsort.c
* Quick sort using recursion
*/
#include <stdio.h>
void qsort(int v[], int left, int right);
int main()
{
int v[] = {9, 3, 4, 6, 7, 3, 1};
qsort(v, 0, 6);
int i;
for (i = 0; i < 7; i++)
printf(" %d ", v[i]);
printf("\n");
return 0;
}
void qsort(int v[], int left, int right)
{
int i, last; /* last is pivot */
void swap(int v[], int i, int j);
if (left >= right)
return;
swap(v, left, (left + right) / 2); // swap mid element to front
last = left; // set this position as pivot
for (i = left + 1; i <= right; i++) {
/*loop through every other element
swap elements less than pivot i.e bigger to right, smaller to left
*/
if (v[i] < v[left])
swap(v, ++last, i); // when swapping lesser element, record
// where our pivot moves
/*
we don't swap elements that are bigger than pivot, and are to right.
However we swap elements those are less than pivot.
With ++pivot we are essentially going to find out, where our
pivot will fit to be at the position, where all the elements
before it are less than it and all after it greater.
*/
}
// swap left(our pivot) to last(where pivot must go
// i.e all elements before pivot are less than it
// and all elements above it are greater
// remember they are lesser and greater
// but may not be sorted still
// this is called partition
swap(v, left, last);
// Do same(qsort) for all the elements before our pivot
// and above our pivot
qsort(v, left, last - 1); // last is our pivot position
qsort(v, last + 1, right);
// Each of above two qsort will use middle element as pivot and do
// what we did above, because same code will be executed by recursive
// functions
}
void swap(int v[], int i, int j)
{
int temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
The most important part is the pivot(put your one feet at place, while free to move other). We choose the middle element as pivot, bring it to front, compare it with all other elements. If they are less than our pivot we swap them and increment only our pivot position (be careful our pivot element still lies at first). After we finish the loop we bring the pivot element(which is at first) to this place (pivot place). After the loop, we have all the elements before pivot less than pivot and all those above pivot greater than pivot. At first loop they are not sorted. So you must again apply same sorting algorithm recursively to all elements below pivot and above pivot to sort them.

Related

How to create a Sudoku grid with the following pattern in C without arrays?

I have to create a Sudoku grid with the following pattern in C:
1 2 3 4
3 4 1 2
2 3 4 1
4 1 2 3
The first number in the top left corner (here: 1) must be an editable variable for a start value. There is another variable to create the grid with by the square size, in this example the square size is 2 and the 1 2 3 4 are in one square. 3 4 1 2 are in another square and so on...
If the start value is e.g. 3, the grid looks like this:
3 4 1 2
1 2 3 4
4 1 2 3
2 3 4 1
I noticed that there is a pattern: If the row number is odd, the new start value of the next row is the second last one. If the row number is even, the new start value of the next row is the last one. I tried to do it in C, but the even rows are cloning themselves. Note that arrays and pointers are not allowed here, only loops and other control-structures.
I tried the following approach, but the even rows are cloning themselves:
#include <stdio.h>
const int intSquareSize = 2;
const int intFieldLength = intSquareSize * intSquareSize;
int intStartValue = 3;
int main() {
int a = 0;
int b = 0;
int m = 0;
for (int intRowCounter = 1; intRowCounter <= intFieldLength; intRowCounter++) {
m = intFieldLength - 1;
for (int intColumnCounter = 1; intColumnCounter <= intFieldLength; intColumnCounter++) {
a = intStartValue + (intColumnCounter - 1);
b = a;
if (a > intFieldLength) {
a = intFieldLength - m;
m--;
}
if (intRowCounter % 2 == 0 && intColumnCounter == intFieldLength) {
intStartValue = a;
} else if (intRowCounter % 2 == 1 && intColumnCounter == (intFieldLength - 1)) {
intStartValue = b;
}
printf("%d\t", a);
}
printf("\n");
}
return 0;
}
What did I wrong and how can I fix it?
If the row number is odd, the new start value of the next row is the second last one. If the row number is even, the new start value of the next row is the last one.
I don't think it is helpful to think in terms of odd and even. The involved numbers are just symbols, and one could even replace them with distinct colors (for example). Odd/even is not a significant thing here, and it would certainly not play the same role in other board sizes.
The pattern I see is this:
In the first intSquareSize rows, the values shift horizontally (compared to the previous row) by intSquareSize. For example with intSquareSize=3 the first three rows could be:
3 4 5 6 7 8 9 1 2
6 7 8 9 1 2 3 4 5
9 1 2 3 4 5 6 7 8
Notice the shift of 3 positions to the left at each next row.
Then the pattern for the next chunks of intSquareSize rows would be the same, but with one shift. So the complete 9x9 sudoku would look like this:
3 4 5 6 7 8 9 1 2
6 7 8 9 1 2 3 4 5
9 1 2 3 4 5 6 7 8
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
1 2 3 4 5 6 7 8 9
5 6 7 8 9 1 2 3 4
8 9 1 2 3 4 5 6 7
2 3 4 5 6 7 8 9 1
This is just one possible pattern you could follow. There could be others. But the following code will apply the above logic. Note I used your variables, but I prefer to use 0-based logic, so loop variables start at 0, and the value of a is also 0-based. Only at the time of printing 1 is added to that value, so it becomes 1-based:
int a = intStartValue - 1; // Move from 1-based to 0-based
for (int intBlockCounter = 0; intBlockCounter < intSquareSize; intBlockCounter++) {
for (int intRowCounter = 0; intRowCounter < intSquareSize; intRowCounter++) {
for (int intColumnCounter = 0; intColumnCounter < intFieldLength; intColumnCounter++) {
printf("%d\t", (a + 1)); // back to 1-based
a = (a + 1) % intFieldLength;
}
printf("\n");
a = (a + intSquareSize) % intFieldLength; // Shift within a block
}
a = (a + 1) % intFieldLength; // Shift between blocks
}

BubbleSorting C language

We are learning arrays and I just came around bubble sorting.
I wrote the following code to sort the array in ascending order but there is a problem.
I can't find it out but I know there's a problem.
I have found the correct code but I still don't understand why this is not working.
My Code
int a;
int i;
int temp;
int value[5] = { 5, 4, 3, 2, 1 };
for (i = 0; i < 5; i++) {
if (value[i] > value[i + 1]) {
temp = value[i];
value[i] = value[i + 1];
value[i + 1] = temp;
}
}
for (a = 0; a < 5; a++) {
printf(" %d ", value[i]);
}
Your Code Has Multiple Problems ,
First And Foremost You are printing the array elements after that sorting that you did with value[i] and you are running loop with variable a.
for(a=0;a<5;a++){ //You Are Incrementing a
printf(" %d ",value[i]); //But Using i here , change it to a.
//As It will just print the value[i] member
}
You are Accessing value[5] , which is not yours.
for(i=0;i<5;i++){ //Here In The Last Loop value[4] is compared with value[5],
// value[5] is not defined
//for(i=0;i<4;i++)
//Instead Run Loop Till i<4 , I guess this is what you
//wanted but accidently made a mistake.
if(value[i]>value[i+1])
The Biggest Problem, is that you have not understood Bubblesort completely.
In Bubble Sort The Loop is run multiple times, until in a loop there are no member to swap, that is when you stop looping.
This is What Wikipedia Says
Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the list to be sorted, compares each pair of adjacent items and swaps them if they are in the wrong order. The pass through the list is repeated until no swaps are needed, which indicates that the list is sorted. The algorithm, which is a comparison sort, is named for the way smaller or larger elements "bubble" to the top of the list. Although the algorithm is simple, it is too slow and impractical for most problems even when compared to insertion sort.It can be practical if the input is usually in sorted order but may occasionally have some out-of-order elements nearly in position.
See The Below Presentation To Understand How Bubble Sort Works.See the Loop Run again and again, till there are no member left to swap.
Step-by-step example
Let us take the array of numbers "5 1 4 2 8", and sort the array from lowest number to greatest number using bubble sort. In each step, elements written in bold are being compared. Three passes will be required.
First Pass
( 5 1 4 2 8 ) to ( 1 5 4 2 8 ), Here algorithm compares the first 2 elements,and swap since 5 > 1.
( 1 5 4 2 8 ) to ( 1 4 5 2 8 ), Swap since 5 > 4
( 1 4 5 2 8 ) to ( 1 4 2 5 8 ), Swap since 5 > 2
( 1 4 2 5 8 ) to ( 1 4 2 5 8 ), Now, since these elements are already in order (8 > 5), algorithm does not swap them.
Second Pass
( 1 4 2 5 8 ) to ( 1 4 2 5 8 )
( 1 4 2 5 8 ) to ( 1 2 4 5 8 ), Swap since 4 > 2
( 1 2 4 5 8 ) to ( 1 2 4 5 8 )
( 1 2 4 5 8 ) to ( 1 2 4 5 8 )
Now, the array is already sorted, but the algorithm does not know if it is completed. The algorithm needs one whole pass without any swap to know it is sorted.
Third Pass
( 1 2 4 5 8 ) to ( 1 2 4 5 8 )
( 1 2 4 5 8 ) to ( 1 2 4 5 8 )
( 1 2 4 5 8 ) to ( 1 2 4 5 8 )
( 1 2 4 5 8 ) to ( 1 2 4 5 8 )
So You Need To Run The Loop Multiple Times Until No Member Are There To Swap, You Can Do So By Having a new variable count, initially initialised to 1 at the start, and before each loop starts, it get initialised to 0, if in the loop, Swap statement executes then, it changes to 1, and again the loop is executed because count is 1, if in the last pass, its value does not changes to 1 because all member are now sorted, so loop does not run again.
When i == 4 you access the position 5 with value[i+1] and it is not yours.
You are accessing unreserved memory.

Running weighted quick union

So I have to take an ID array
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
And perform weighted quick union on it. I have to perform the operations 9-0, 3-4, 5-8, 7-2, 2-1, 5-7, 0-3, and 4-2. Here's what I did to the array for these operations:
9-0
0 1 2 3 4 5 6 7 8 9
9 1 2 3 4 5 6 7 8 9
3-4
0 1 2 3 4 5 6 7 8 9
9 1 2 3 3 5 6 7 8 9
5-8
0 1 2 3 4 5 6 7 8 9
9 1 2 3 3 5 6 7 5 9
7-2
0 1 2 3 4 5 6 7 8 9
9 1 7 3 3 5 6 7 5 9
2-1
0 1 2 3 4 5 6 7 8 9
9 7 7 3 3 5 6 7 5 9
5-7
0 1 2 3 4 5 6 7 8 9
9 7 7 3 3 7 6 7 5 9
0-3
0 1 2 3 4 5 6 7 8 9
9 7 7 3 3 7 6 7 5 3
4-2
0 1 2 3 4 5 6 7 8 9
9 7 7 3 3 7 6 3 5 9
The problem is that the ID array operations are different depending on if you're using quick find or quick union or weighted quick union. So would this be right for weighted quick union? Here's the code I'm using for weighted quick union:
public class WeightedQuickUnionUF
{
private int[] id; // parent link (site indexed)
private int[] sz; // size of component for roots (site indexed)
private int count; // number of components
public WeightedQuickUnionUF(int N)
{
count = N;
id = new int[N];
for (int i = 0; i < N; i++) id[i] = i;
sz = new int[N];
for (int i = 0; i < N; i++) sz[i] = 1;
}
public int count()
{ return count; }
public boolean connected(int p, int q)
{ return find(p) == find(q); }
private int find(int p)
{ // Follow links to find a root.
while (p != id[p]) p = id[p];
return p;
}
public void union(int p, int q)
{
int i = find(p);
int j = find(q);
if (i == j) return;
// Make smaller root point to larger one.
if (sz[i] < sz[j]) { id[i] = j; sz[j] += sz[i]; }
else { id[j] = i; sz[i] += sz[j]; }
count--;
}
}
The code for weighted quick union shows you how it works but basically it's a type of Union-find where you connect two trees together. With weighted quick union you always connected the smaller tree to the larger one. The ID array is a representation of a tree where there's numbers on the top row and bottom row. If the number on top matches the bottom then that number is a root in the forest but for example if the top number is a 9 and the bottom number is 0 then it means 9 is a child of 0. The ID array starts out with 9 single node trees and operations like 9-0 connects two trees together.

How do you create an outer loop to read two separate mazes using the user's input C program

So we're supposed to read an input file from the user.
The input file contains the following:
First Line: The number of mazes in the file
Second Line: the first number is the number of nodes and the second number is the...
ith Line: There will be lines that has the same format as the second line.
These lines serve to tell you that you have reached the next maze. There are n such pairs of numbers, where n is the number indicated in the first line of the file.
The Rest of the Lines: The rest of the lines are sets of three numbers containing the source, number of edges,destination, and edge/path cost.
The problem is, my program only reads the first half of the program. When it comes to the next "maze", it stops.
How to read both mazes in one go? Help please.
Here is the input file:
2
16 15
0 1 1
1 5 1
5 6 1
6 7 1
7 11 1
11 10 1
10 14 1
14 13 1
13 9 1
14 15 1
1 2 1
2 3 1
0 4 1
4 8 1
8 12 1
16 15
0 1 1
1 2 1
2 6 1
6 7 1
7 11 1
11 15 1
15 14 1
14 13 1
13 9 1
9 5 1
9 10 1
2 3 1
0 4 1
4 8 1
8 12 1
And here's my program:
fh = fopen("maze_test_small", "r");
chk_null_ptr(fh);
fscanf(fh, "%d",&nlines);
fscanf(fh, "%d %d", &nnodes, &nedges);
adjlist = (edgelist_t**) calloc(nnodes + 1, sizeof(edgelist_t *));
chk_null_ptr(adjlist);
for(i = 0; i < nnodes; i++)
{
adjlist[i] = (edgelist_t *) calloc(1, sizeof(edgelist_t));
chk_null_ptr(adjlist[i]);
adjlist[i][0].cost = 0;
}
while(nedges--)
{
fscanf(fh, "%d %d %d", &na, &nb, &wt);
adjlist[na] = (edgelist_t *) realloc(adjlist[na], (adjlist[na] [0].cost + 2) * sizeof(edgelist_t));
adjlist[nb] = (edgelist_t *) realloc(adjlist[nb], (adjlist[na][0].cost + 2) * sizeof(edgelist_t));
chk_null_ptr(adjlist[na]);
chk_null_ptr(adjlist[nb]);
adjlist[na][adjlist[na][0].cost + 1].dest = nb;
adjlist[nb][adjlist[nb][0].cost + 1].dest = na;
adjlist[na][adjlist[na][0].cost + 1].cost = wt;
adjlist[nb][adjlist[nb][0].cost + 1].cost = wt;
adjlist[na][0].cost++;
adjlist[nb][0].cost++;
}
You have not used a outer loop with nlines. That's why it is only reading a single maze.
You can do following thing:
for(i = 0; i < nlines; i++){
// your code.
}
and if you do not need nlines anywhere else then,
while(nlines--){
//your code
}

Need help with logic (C)

I need to swap first n elements from two non repeating sequences(arrays), where n is a random integer.
Seq1: 1 4 5 6 9 8 2 3 7
Seq2: 3 9 1 2 8 7 4 5 6
If n = 4
Seq1: 3 9 1 2 | 9 8 2 3 7
Seq2: 1 4 5 6 | 8 7 4 5 6
Now i need to repair the sequence by replacing the repeated numbers after '|'.
How to do this?
This is my effort..
for(left1 = 0; left1<pivot; left1++)
{
for(right1 = pivot; right1 < no_jobs; right1++)
{
if(S1->sequence[left1] == S1->sequence[right1])
{
for(left2 = 0; left2<pivot; left2++)
{
for(right2 = pivot; right2<no_jobs; right2++)
{
if(S2->sequence[left2] == S2->sequence[right2])
{
swap_temp = S1->sequence[right1];
S1->sequence[right1] = S2->sequence[right2];
S2->sequence[right2] = swap_temp;
break;
}
}
}
}
}
}
Swapping the first n elements is straightforward using a single for loop.
for(int i = 0; i < n; i++){
int tmp = array1[i];
array1[i] = array2[i];
array2[i] = tmp;
}
Now you need to find what has changed in the arrays. You can do this by comparing the parts you swapped.
int m1 = 0, m2 = 0;
int missing_array1[n];
int missing_array2[n];
for(int i = 0; i < n; i++){
bool found = false;
for(int j = 0; j < n; j++){
if(array1[i] == array2[j]){
found = true;
break;
}
}
if(!found){
missing_array2[m2++] = array1[i];
}
}
for(int i = 0; i < n; i++){
bool found = false;
for(int j = 0; j < n; j++){
if(array2[i] == array1[j]){
found = true;
break;
}
}
if(!found){
missing_array1[m1++] = array2[i];
}
}
missing_array2 now contains the numbers that are missing from array2. These are all the numbers that will be duplicated in array1. The same goes for missing_array1. Next you need to scan both arrays and replace the duplicates with the missing numbers.
while(m1 >= 0){
int z = 0;
while(missing_array1[m1] != array2[n + z]){
z++;
}
array2[n + z] = missing_array2[m1--];
}
while(m2 >= 0){
int z = 0;
while(missing_array2[m2] != array1[n + z]){
z++;
}
array1[n + z] = missing_array1[m2--];
}
In summary, you compare the parts you swapped to find the values that will be missing from each array. These value are also the values that will be duplicated in the opposite array. Then you scan each of the arrays and replace the duplicate values with one of the missing values (I assume you don't care which of the missing values, as long as all the values are unique.
If the swapped portions of the sequences contain the same values, then there would be no repeats - performing the swap would just shuffle the first n elements. So the values you need to repair are the values which occur in one of the swapped sequences
Firstly, I'd create a histogram of the n swapped elements, with those from sequence 1 counting as bit 0, and those from sequence 2 as bit 1. If any members of the histogram are non-zero, then they occur in one or the other sequence only.
If there are values requiring repair, then you can construct a look-up table of the values which require rewriting. This should map i to i unless i is one of the asymmetric values in the histogram, in which case it needs to map to the another asymmetric value.
Seq1: 1 4 5 6 9 8 2 3 7
Seq2: 3 9 1 2 8 7 4 5 6
If n = 4
Seq1: 3 9 1 2 | 9 8 2 3 7
Seq2: 1 4 5 6 | 8 7 4 5 6
histogram
value 1 2 3 4 5 6 7 8 9
count 3 1 1 2 2 2 0 0 1
mapping for sequence 1 ( while histogram [S1[i]] & 1, replace[S1[i]] with S2[i] )
value 1 2 3 4 5 6 7 8 9
replace 1 6 5 4 5 6 7 8 4
apply mapping to sequence 1 for i > n
Seq1: 3 9 1 2 | 9 8 2 3 7
replace - - - - | 4 8 6 5 7
result 3 9 1 2 | 4 8 6 5 7
mapping for sequence 2 ( while histogram [S2[i]] & 2, replace[S2[i]] with S1[i] )
value 1 2 3 4 5 6 7 8 9
replace 1 2 3 9 3 2 7 8 9
apply mapping to sequence 1 for i > n
Seq2: 1 4 5 6 | 8 7 4 5 6
replace - - - - | 8 7 9 3 2
result 1 4 5 6 | 8 7 9 3 2
Alternatively, replace with the next value with the other bit set in the histogram (the iterated replace will also need to check for replacing a value with itself); I'm assuming it doesn't really matter what value is used as the replacement as long as the values in the result are unique.

Resources