编写字符串全排是一个练习递归和算法的好方式,同时也能见到数学知识与代码编写结合起来,求解问题会变得非常简单。这里摘录了两个字符串全排的例子,仅供参考。
例一,手机号码与字符全排: 键盘式的手机,对于9宫格式的手机,每个按键上都会刻有数字和字母,这样是否可以编写一个程序把数字转换成字母全排(相当于输入法....).
例二,对于给定的字符,写出其全排列。
两个例子比较经典,直接看代码吧。
// PhoneNumberToWords.cpp : Defines the entry point for the console application.
// Author: mingspy 5/22 2012 mingspy@163.com
//
// Solution of <<Beauty of Programming>> 3.2.
// Question:
//
// On old phone keyboard, the digital numbers and English alphas are paired, for
// example 2,A,B,C are in a single key, so can we design an algorithm to print
// all permutation of a given phone number, e.g 1860000000000.
#include "stdafx.h"
#include <istream>
char code[10][10] =
{
"", //0
"", //1
"abc", //2
"def", //3
"ghi", //4
"jkl", //5
"mno", //6
"pqrs", //7
"tuv", //8
"wxyz", //9
};
int codesLen[10]= {0, 0, 3, 3, 3, 3, 3, 4, 3, 4};
const int AnswerLen = 20;
int answer[AnswerLen] = {0};
// Translate phone number to words.
// The principle of this algorithm is using an array to save
// travel footprint, when the answer[i] equals codesLen[pNumber[i]]
// that means the permutation of this number has completed, then travel
// next until all number traveled.
/*长时间不看,回头来看自己写的代码,发现还是需要看一会才明白。所以应该写出代码流程或伪代码,然后再贴代码。
非递归手机号码与字符映射解决方法。
非递归的方法原理是:把全排看成数字递增。简单来说,比如手机有3个数字键[0,1,2] 对应9个字符[abc def ghi]那么
数字 0 -> abc char * code[0]
数字 1 -> def char * code[1]
数字 2 -> ghi char * code[2]
那么对于每一个数字就有3个字符对应,那么打印出每个数字i对应的所有字符,就需要打印code[i][0-2]相当于1位三进制数
的累加然后转码。从0累加到2,并打印出数字i相应的第j个字符。
如果打印两个数字i,j对应字符的全排,那么相当于两个三进制数的累加转码问题从00到22。
用一个int数组表示当前的多进制数。
算法步骤:
初始化多进制数组为0
打印当前多进制数组代表的字符。
递增多进制数
如果多进制数越界,退出。
*/
void PhoneNumberToWords(int * pNumber, int nLen)
{
// Check the in put parameters are reasonable.
if(!pNumber)
{
return;
}
if(nLen > AnswerLen)
{
printf("Too many numbers.");
return;
}
// Initialize answer to zero.
for(int i = 0; i < nLen; i ++)
{
answer[i] = 0;
}
while(true)
{
// Print answer.
for(int i = 0; i < nLen; i ++)
{
printf("%c", code[pNumber[i]][answer[i]]);
}
printf("\n");
int k = nLen - 1;
// Backwards increase answer[i] until all the character in this number key are
// printed. It's like a trinary number increase step by step.
while(k>=0)
{
if(answer[k] < codesLen[pNumber[k]] - 1)
{
answer[k]++;
break;
}
else
{
answer[k] = 0;
k--;
}
}
if(k < 0)
{
break;
}
}
}
// Print each words composition of the given number Recursively.
/*递归打印电话号码数字对应的字符全排。
对于全排问题,P(R1R2...RN) = P(R2...Rn)*P(R1)
算法步骤:
如果为一个号码排列,打印所有字符。
取出一个字符,打印其余字符的全排
*/
void RecursiveNumberToWords(int * pNumber, int nLen, int current)
{
// Check the inputs, in order to improve the performance,
// this lines could be comment out.
if(!pNumber || nLen > AnswerLen )
{
return;
}
// Print the result.
if(current == nLen)
{
for(int j = 0; j < nLen; j++)
{
printf("%c", code[pNumber[j]][answer[j]]);
}
printf("\n");
return;
}
// if current number has no alpha company with,
// print others. // 用于去除空字符,增加程序健壮性。
if(codesLen[pNumber[current]] == 0)
{
RecursiveNumberToWords(pNumber, nLen, current+1);
}
else
{
// Recursively print each alpha.
// 核心算法
for(int i = 0; i < codesLen[pNumber[current]]; i++)
{
answer[current] = i;
RecursiveNumberToWords(pNumber, nLen, current+1);
}
}
}
// 一维字符全排问题
// Another Question about permutation:
// Please design a program to print all permutation of given characters.
void RecursivePermutationCharacters(char * pChars, int nLen, int iFrom)
{
if(iFrom > nLen)
{
return;
}
// Assume Perm(CH) as the all permutation for CH={Ch(i)| i= 1, 2, ... n},
// and set Perm(CHI)= CH - {Ch(i)};
//according to mathematics knowledges,
// Perm(n) = Ch(1)Perm(CH1) + Ch(2)Perm(CH2) + .... +Ch(n)Perm(CHn).
if(iFrom < nLen)
{
for(int i = iFrom; i < nLen; i ++)
{
std::swap(pChars[i], pChars[iFrom]);
RecursivePermutationCharacters(pChars, nLen, iFrom + 1 );
std::swap(pChars[i], pChars[iFrom]);
}
}
else
{
// print result.
for(int i = 0; i< nLen; i++)
{
printf("%c", pChars[i]);
}
printf("\n");
}
}
// Test case.
int _tmain(int argc, _TCHAR* argv[])
{
int number[5];
number[0] = 1;
number[1] = 2;
number[2] = 3;
number[3] = 4;
number[4] = 5;
// Initialize answer={0}, as this is the first time
// use answer, don't have to do this.
//RecursiveNumberToWords(number, 5, 0);
char buf[3];
buf[0] = '1';
buf[1] = '2';
buf[2] = '3';
RecursivePermutationCharacters(buf, 3, 0);
return 0;
}