Reputation: 309
is there possible way to sort an array of three integers with only one pass on the array?
you get:
int array[]={1,2,2,2,3,1,1,2,2,1,3}
and you are told that there are only number 1,2,3
to get:
int array[]={1,1,1,1,2,2,2,2,2,3,3}
and no extra space allowed
Tnx!
Upvotes: 2
Views: 1472
Reputation: 18652
This is the Dutch national flag problem with a simple linear solution described by E. W. Dijkstra in the early 70's. It's sometimes used as a partitioning method for quicksort.
#include <iostream>
template <typename BidIt, typename T>
void dnf_partition(BidIt first, BidIt last, const T &pivot)
{
for (BidIt next = first; next != last;) {
if (*next < pivot) {
std::iter_swap(first++, next++);
} else if (pivot < *next) {
std::iter_swap(next, --last);
} else {
++next;
}
}
}
int main()
{
int array[] = { 1, 2, 2, 2, 3, 1, 1, 2, 2, 1, 3 };
for (int n : array) std::cout << n << ' ';
std::cout << '\n';
dnf_partition(std::begin(array), std::end(array), 2);
for (int n : array) std::cout << n << ' ';
std::cout << '\n';
}
Upvotes: 1
Reputation: 311038
Here is a straightforward approach (without testing)
#include <iostream>
#include <algorithm>
#include <iterator>
void sort( int *first, int *last )
{
for ( int *current = first; current != last; )
{
if ( *current == 1 )
{
if ( current == first )
{
++current;
}
else
{
std::swap( *current, *first );
}
++first;
}
if ( *current == 3 )
{
--last;
if ( *current != *last ) std::swap( *current, *last );
}
if ( *current == 2 ) ++current;
}
}
int main()
{
int a[] = { 1, 2, 2, 2, 3, 1, 1, 2, 2, 1, 3 };
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
sort( std::begin( a ), std::end( a ) );
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output is
1 2 2 2 3 1 1 2 2 1 3
1 1 1 1 2 2 2 2 2 3 3
Upvotes: 1
Reputation: 5369
One pass with no extra space:
first pointer: Denotes start of 2 in the array.
last Pointer: Denotes start of 3 in the array.
If you find a 1, swap it with the first pointer.
If you find a 2, keep it there.
If you find a 3, swap it with the last pointer.
Dry run:
{1,2,2,2,3,1,1,2,2,1,3} cur=1, first=1, last=10
{1,2,2,2,3,1,1,2,2,1,3} cur=2, first=2, last=10
{1,2,2,2,3,1,1,2,2,1,3} cur=3, first=2, last=10
{1,2,2,2,3,1,1,2,2,1,3} cur=4, first=2, last=10
{1,2,2,2,3,1,1,2,2,1,3} cur=5, first=2, last=10
{1,2,2,2,1,1,1,2,2,3,3} cur=5, first=2, last=9
{1,1,2,2,2,1,1,2,2,3,3} cur=5, first=3, last=9
{1,1,1,2,2,2,1,2,2,3,3} cur=6, first=4, last=9
{1,1,1,1,2,2,2,2,2,3,3} ...
Time: O(n) (one pass)
Space: O(1)
Upvotes: 6
Reputation: 201447
Yes. With a counting sort,
int array[]={1,2,2,2,3,1,1,2,2,1,3};
int count[]={0,0,0};
int i = 0;
while (array[i] != '\0') {
count[array[i] - 1]++;
i++;
}
for (i = 0; i < count[0]; i++) {
printf("%i", 1);
printf(",");
}
for (i = 0; i < count[1]; i++) {
printf("%i", 2);
printf(",");
}
for (i = 0; i < count[2]; i++) {
printf("%i", 3);
if (i + 1 < count[2]) {
printf(",");
}
}
printf("\n");
Edit
With no extra space allowed.
Then no. It's not possible.
Upvotes: 0
Reputation: 46617
Yes, use counting sort. Basically, you walk the input array once and count for each of the values how often they occur. Afterwards, you just emit the appropriate number of values for each bucket.
Edit: counting, not bucket sort.
Upvotes: 6