views:

538

answers:

3

I want to make simple sorting algorithm.

given the input "abcde", I would like the output below. could you tell me the algorithm for that?

arr[0] = "a"
arr[1] = "ab"
arr[2] = "ac"
arr[3] = "ad"
arr[4] = "ae"
arr[5] = "abc"
arr[6] = "abd"
arr[7] = "abe"
...
arr[n] = "abcde"

arr[n+1] = "b"
arr[n+2] = "bc"
arr[n+3] = "bd"
arr[n+4] = "be"
arr[n+5] = "bcd"
arr[n+5] = "bce"
arr[n+5] = "bde"
...
arr[n+m] = "bcde"
...
...
A: 

An algorithm for "generating Power Set" from an array is what you are looking for. You can try Google or some other search engine to find the algorithm that best fits your needs.

rahmivolkan
-1 because directing people to google is arrogant at best.
Space_C0wb0y
+1 cause sometimes people feel that they need to google for something but do not know the name of the algorithm.
Muxecoid
@Space_C0wb0y - You are right; I needed to hurry for some other thing. I just wrote what he needs.(now it's better, I guess)@Muxecoid - that's exactly what I thought.
rahmivolkan
Removed the -1 after your edit.
Space_C0wb0y
A: 

You are describing a power set. Here is some C++ code:

#include <vector>
#include <string>
#include <algorithm>
#include <functional>
using namespace std;

vector< string > string_powerset( string const &in ) {
    vector< string > result(1); // start output with one empty string
    result.reserve( 1 << in.size() ); // output size = 2^( in.size() )
    if ( result.capacity() != 1<<in.size() ) throw range_error( "too big" );

    for ( string::const_iterator it = in.begin(); it != in.end(); ++ it ) {
        size_t middle = result.size(); // duplicate what we have so far
        result.insert( result.end(), result.begin(), result.end() );

          // append current character onto duplicated output
        for_each( result.begin() + middle, result.end(),
           bind2nd( mem_fun_ref( &string::push_back ), * it ) );
    }
    return result;
}

Tested working :v) . The range check isn't the best, but whatever.

This code will tend to overflow, due to the exponential growth of the powerset, so you should only pass it short strings. The other posted answer avoids this problem by generating and returning one string at a time. However, this is easier to understand, and using a far larger and more confusing piece of code would be premature optimization unless you actually have an overflow problem.

EDIT: I wrote up a next_subset answer, and it looks nothing like Ben's.

Potatoswatter
explain downvotes pls?
Potatoswatter
Space_C0wb0y
1. I felt I earned some laziness by fixing the question and writing all this code. OP doesn't strike me as likely to have large-codebase issues. This isn't a header file. 2. So I commented on it and also noted dismay on the overflow situation. 3. My `const` style is more uniform. `const` attaches to the *preceding* identifier or modifier, unless `const` is the first token of the type. I avoid the special case. Also, saying `string` first "gets down to business faster."
Potatoswatter
For the record, this answer now has 3 upvotes and 3 downvotes. No downvoter has left a comment.
Potatoswatter
@Potatoswatter I upvoted you for the reason they downvoted. I myself use style presented by you, and if someone tells me that he never saw this before I just don't know what to say.
There is nothing we can do
+4  A: 

In C++ given the following routine:

template <typename Iterator>
bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
   /* Credits: Mark Nelson http://marknelson.us */
   if ((first == last) || (first == k) || (last == k))
      return false;
   Iterator i1 = first;
   Iterator i2 = last;
   ++i1;
   if (last == i1)
      return false;
   i1 = last;
   --i1;
   i1 = k;
   --i2;
   while (first != i1)
   {
      if (*--i1 < *i2)
      {
         Iterator j = k;
         while (!(*i1 < *j)) ++j;
         std::iter_swap(i1,j);
         ++i1;
         ++j;
         i2 = k;
         std::rotate(i1,j,last);
         while (last != j)
         {
            ++j;
            ++i2;
         }
         std::rotate(k,i2,last);
         return true;
      }
   }
   std::rotate(first,k,last);
   return false;
}

You can then proceed to do the following:

std::string s = "abcde";
for(std::size_t i = 1; i != s.size(); ++i)
{
   do
   {
      std::cout << std::string(s.begin(),s.begin() + i) << std::endl;
   }
   while(next_combination(s.begin(),s.begin() + i,s.end()));
}

Note: That you should expect to see 2^n-1 combinations, where n is the length of the array or string.

Beh Tou Cheh