I was asked to write a permutation algorithm to find the permutations of {a,b,c}. Since this is a famous question to which an answer is readily available online, I wanted to do it a little differently, so that it won't look like I copied off the Internet. It was evaluated as OK for the algorithm being correct, but said that the algorithm is inefficient and also there are 'major concerns' in the code.
I would really appreciate if the experts here would advice me on what is wrong about this code, so that I can learn and fix my mistakes. I understand that the use of templates is an overkill, but other than that, what is so wrong about this code? The question was, find the permutations of {a,b,c}.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
template<typename T> vector<T> TruncateVector(vector<T>, int);
template<typename T> vector<vector<T> > GetPerms(vector<T>);
unsigned GetNumPerms(unsigned);
template<typename T>
bool ValidatePermutations(vector<T>, vector<vector<T> >);
int main()
{
// Create a vector with the elements required to permute
vector<char> permSet;
permSet.push_back('a');
permSet.push_back('b');
permSet.push_back('c');
// Get the permutations
vector<vector<char> > vectorOfPerms = GetPerms(permSet);
/* Printing the permutations */
for(unsigned x=0, counter=1;x<vectorOfPerms.size(); x++)
{
cout << "(" << counter << ") ";
for(unsigned y=0;y<vectorOfPerms[x].size(); y++)
{
cout << vectorOfPerms[x].at(y) << ' ';
}
counter++;
cout << endl;
}
// Validate the calculated permutations
// This validation only valid for sets with lexicographic order. See notes in the function.
bool validation = ValidatePermutations(permSet,vectorOfPerms);
return 0;
}
template<typename T>
vector<vector<T> > GetPerms(vector<T> permSet)
{
/* --------------- Permutation algorithm -----------------
* In this algorithm permutations are calculated by sequentially taking each element in the vector,
* and then combining it with 'all' the permutations of the rest of the vector elements.
* Example:
* GetPerms('a,b,c') --> ( {a, GetPerms('b,c')}, {b, GetPerms('a,c')}, {c, GetPerms('a,b')} }
* The resultant permutations are returned as a vector of vectors, with each vector consisting of one permutation.
*
* Vectors were chosen to store the elements because of its ease of handling (inserting, deleting) and also for its ability
* to handle different types of data.
*/
vector<vector<T> > vectorOfPerms(GetNumPerms(permSet.size()));
unsigned PermCount=0;
if(permSet.size() == 1) // Base case. Only one element. Return it back.
{
vectorOfPerms[0].push_back(permSet.at(0));
}
else
{
for(unsigned idx=0; idx<permSet.size(); idx++)
{
vector<T> vectorToPermutate = RemoveElement(permSet, idx); // Remove the current element being combined to permutations.
vector<vector<T> > PermVector = GetPerms(vectorToPermutate); // Get the permutations for the rest of the elements.
// Combine with the received permutations
for(unsigned count=0 ; count<PermVector.size(); count++, PermCount++)
{
vectorOfPerms[PermCount].push_back(permSet.at(idx)); // Insert the first element
vectorOfPerms[PermCount].insert(vectorOfPerms[PermCount].begin()+1, PermVector[count].begin(), PermVector[count].end()); // Insert the permutations
}
}
}
return vectorOfPerms;
}
/*
* This function removes the element at index from the vector permSet
*/
template<typename T>
vector<T> RemoveElement(vector<T> permSet, int index)
{
permSet.erase(permSet.begin()+index);
return permSet;
}
/*
* This function returns the number of possible permutations for a given
* number of elements
*/
unsigned GetNumPerms(unsigned numElems) {
return (numElems == 1 ? numElems : numElems*GetNumPerms(numElems - 1));
}
/*
* This function validates the calculated permutations with the std::next_permutation
* IMPORTANT: This validation will only work if the elements are different and inserted in lexicographic order.
* I.e. {a,b,c} will be correctly validated, but not {a,c,b}.
* The permutations generated are CORRECT. Only the validation with std::next_permutation will not be correct.
* This validation was chosen to validate the program for the given question of finding permutations of {a,b,c}.
*/
template<typename T>
bool ValidatePermutations(vector<T> permSet, vector<vector<T> > result)
{
bool validationResult = true;
/* Validating the calculated permutations with the std::next_permutation
* Since std::next_permutation gives the next lexicographically greater permutation with each call,
* it must match with the permutations generated in GetPerms() function.
*/
if(result.size() != GetNumPerms(permSet.size()))
{
cout << "Number of permutations is incorrect." << endl;
}
else
{
// Compare element by element
for(unsigned permCount=0; permCount<result.size(); permCount++)
{
for(unsigned elemCount=0; elemCount<permSet.size(); elemCount++)
{
if(result[permCount].at(elemCount) != permSet.at(elemCount))
{
validationResult = false;
break;
}
}
if(!validationResult)
{
break;
}
else
{
next_permutation(permSet.begin(),permSet.end());
}
}
}
cout << "Number of elements: " << permSet.size() << endl;
cout << "Number of permutations: " << result.size() << endl;
if(validationResult)
{
cout << "Validation: " << "PASS" << endl;
}
else
{
cout << "Validation: " << "FAIL" << endl;
}
return validationResult;
}
std::next_permutation()
cplusplus.com/reference/algorithm/next_permutation \$\endgroup\$