问题
I was given pseudo code for a partition algorithm but I'm not really sure how to implement it.
Below is the pseudo code and my implementation. Please let me know if this is correct/explain what it's doing. Right now I have a partial understanding of it but it is not correct.
Input: 0.963, 0.003, 0.0251, 0.353, 0.667, 0.838, 0.335, 0.915, 0.796, 0.833, 0.345, 0.871, 0.089, 0.888, 0.701, 0.735
Expected: 0.003 0.0251 0.089 0.335 0.345 0.353 0.667 0.701 0.735 0.796 0.833 0.838 0.871 0.888 0.915 0.963
Actual: 0.003000 0.025100 0.353000 0.667000 0.838000 0.335000 0.915000 0.796000 0.833000 0.345000 0.871000 0.089000 0.888000 0.7 01000 0.735000 0.963000
int partition_data( float xdata[], int ndata, float xmiddle ) {
int left;
int right;
int j,i;
float temp;
for(i = 0; i < xmiddle; i ++){
if(left == right){
left += 1;
}
else{
for( j = ndata - 1; j >= xmiddle; j--){
if(left == right){
right -= 1;
}
else{
temp = xdata[j];
xdata[j] = xdata[i];
xdata[i] = temp;
right -= 1;
if(left == right){
left += 1;
break;
}
}
}
}
}
}
回答1:
As others already said, both here and at Code Review, the pseudocode is quite non-standard, and hard to read (although it's not true it is mis-indented).
However, if you're not interested in improving it, but just want to implement it 'as is', here it is, word-by-word translated into C language:
int Partition(float X[], int ndata, float xmiddle)
{
int left = 0;
int right = ndata - 1;
while(1) { // 'left' loop
if(X[left] < xmiddle)
{
if(left == right)
return left + 1;
left ++;
}
else
while(1) { // 'right' loop
if(X[right] >= xmiddle)
{
if(left == right)
return left;
right --;
}
else
{
float tmp = X[left]; // these three lines
X[left] = X[right]; // swap the two values
X[right] = tmp; // X[left] and X[right]
right --;
if(left == right)
return left + 1;
left ++;
break; // exit the 'right' loop
}
} // end of 'right' loop
} // end of 'left' loop
} // end of Parition
The code is actually C, in C++ you might make it a function template with a type parameter instead of explicit float
, so that the function may partition arrays of different types (as long as operators <
and >=
are defined). You might also use std::swap
for efficient swapping data and dropping the explicit tmp
variable.
回答2:
Maybe the assignment was to implement a full quicksort?
Quicksort with conventional pre-increment / pre-decrement Hoare partition scheme:
int Partition(float x[], int lo, int hi)
{
float xmiddle = x[(lo+hi)/2];
int left = lo - 1;
int right = hi + 1;
float tmp;
while (1){
while (x[++left] < xmiddle);
while (x[--right] > xmiddle);
if(left >= right)
break;
tmp = x[left];
x[left] = x[right];
x[right] = tmp;
}
return right;
}
void QuickSort(float x[], int lo, int hi){
int pivot;
if (lo < hi){
pivot = Partition(x, lo, hi);
QuickSort(x, lo, pivot);
QuickSort(x, pivot+1, hi);
}
}
One issue with quicksort is that a minor bug in the partition scheme may work for most data patterns and only fail for specific data patterns, making it difficult to determine if a quicksort is really bug free.
Quicksort using modified version from the psuedo code above. This works for the example data, but I'm not sure it's bug free. Partition should return an index that points to a value == xmiddle:
int Partition(float X[], int lo, int hi)
{
int left = lo;
int right = hi;
float xmiddle = X[(lo+hi)/2];
float tmp;
while(1) {
while(X[left] < xmiddle){
if(left == right)
return left+1;
left++;
}
while(X[right] >= xmiddle){
if(left == right)
return left;
right--;
}
tmp = X[left];
X[left] = X[right];
X[right] = tmp;
right --;
if(left == right)
return left + 1;
left ++;
}
}
void QuickSort(float x[], int lo, int hi){
int pivot;
if (lo < hi){
pivot = Partition(x, lo, hi);
QuickSort(x, lo, pivot);
QuickSort(x, pivot+1, hi);
}
}
回答3:
Explanation of the algorithm
The routine re-arranges data so that items less than the supplied xmiddle
value remain on the left side of the array (at smaller indices) and items greater than xmiddle
are put to the right part (at bigger indices). The return value is a length of the left part.
Variables left
and right
scan the array from both ends to find items which should be swapped.
The 'left loop' (starting at line 4) increments the left
index until it finds an item greater than or equal to xmiddle
(line 5) or until it reaches the right
position (line 6). As right
is initially the last index of the array (and later it can only be decremented), the loop must eventually stop incrementing left
.
If the left
index meets right
then all items below and at left
are less than xmiddle
, so left+1
is returned as a length of the left subarray. Note that if xmiddle
is chosen bigger than all items of the array, the return value is equal to the array's length (ndata
).
If left
stops at an item greater than or equal to xmiddle
, then the 'otherwise' branch at line 9 executes and the 'right loop' starts. Similar to the left loop
it decrements right
, stepping over all items greater than or equal to xmiddle
until the right
index meets left
. If the two indices meet (line 11), then all items below them are less than, and all items above and at them are greater than or equal to xmiddle
; then left
is returned as the length of the left part.
On the other hand, if the right
index finds an item less than xmiddle
(i.e. not satisfying the condition at line 10), then it needs to be swapped with the item at index left
, which is greater than or equal to xmiddle
(it didn't satisfy the condition at line 5). Then the 'otherwise' branch at line 13 is executed.
The branch swaps the two values (line 14), so both left and right part become one item longer. To reflect that, the right
index is decremented (line 15) and then compared to left
. If they got equal (line 16), i.e. we swapped adjacent items, the partitioning is done, so left+1
is returned as a length of the left part. Otherwise left
gets incremented (line 17) and we exit the 'right loop' (line 18) and proceed to the closing brace of the 'left loop' in line 20, which brings the execution back to line 4.
Then again left
gets incremented (that is the left part grows) until it meets the right part or finds an item to be swapped. And so on...
The loops invariants are:
left
≤right
X[i] < xmiddle
for0 ≤ i < left
X[i] ≥ xmiddle
forright < i < ndata
and the un-tested part of the array gets reduced (the difference right - left
is decremented) at least by 1 in every iteration of a loop.
来源:https://stackoverflow.com/questions/34002448/partition-algorithm-with-two-loops-c