关于所有子集的求法,前面有介绍到利用回溯法,可以求出所有子集的字典序
如果不要求字典序,可以选择其他思路来解答:
如果所有字符的个数为N,可以定义一个unsigned int型的数字,初始化为0,循环+1,直到第N+1位为1,基于这个思想,不难写出代码:
#include <iostream>
using namespace std;
char source[] = "123";
const int size = sizeof source / sizeof *source;
void print(char *source, const int size, unsigned int value)
{
unsigned int flag = 0x01;
cout << "{";
for (int i = 0; i < size; i++)
{
if (value & (flag << i))
{
cout << source[size - i - 1];
}
}
cout << "}" << endl;
}
void printPermutations(char *source)
{
if (source == NULL || size <= 0)
return;
unsigned int length = strlen(source);
unsigned int flag = 0;
while ((flag >> length) == 0)
{
print(source, length, flag);
flag++;
}
}
void main()
{
printPermutations(source);
}
可以更改print函数,print顺序发生变化:
void print(char *source, const int size, unsigned int value)
{
unsigned int flag = 0x01;
cout << "{";
for (int i = 0; i < size; i++)
{
if (value & (flag << i))
{
cout << source[i];
}
}
cout << "}" << endl;
}
但是这样的代码存在一个问题,那就是如果元素个数超过32个,得定义一个unsigned long long int型变量来保存状态,否则记录不了这么多的状态,如果更大点,额。。。还是用数组吧。。。编程珠玑里的位图。。。真蛋疼。。。
还有一种用字符串数组来保存'0', '1'状态的解法,真是层出不穷呀。。。
代码如下:
#include <iostream>
using namespace std;
char source[] = "123";
const int size = sizeof source / sizeof *source;
void print(char *source, const int size, char *states)
{
cout << "{";
for (int i = 0; i < size; i++)
{
if (states[i] == '1')
{
cout << source[i];
}
}
cout << "}" << endl;
}
void printPermutations(char *source)
{
if (source == NULL || size <= 0)
return;
unsigned int length = strlen(source);
unsigned int flag = 0;
char *states = new char[length + 1];
for (int i = 0; i <= length; i++)
states[i] = '0';
do {
print(source, length, states);
if (states[0] == '0')
states[0] = '1';
else
{
states[0] = '0';
int i = 1;
while (states[i] != '0')
states[i++] = '0';
states[i] = '1';
}
} while (states[length] != '1');
delete[] states;
}
void main()
{
printPermutations(source);
}
对比一下优缺点,不难发现char数组来保存状态,每个状态消耗的内存是1bytes,用unsigned int型变量保存状态,每个状态消耗的内存是1bit
由于上面的打印序列并非字典序,如果按照字典序打印呢,这个算法比较难想:
#include <iostream>
using namespace std;
#define MAXSIZE 20
#define LOOP 1
void printLexicographical(int *set, int n)
{
int position = 0;
set[position] = 1;
while (LOOP)
{
printf("\n{%d", set[0]);
for (int i = 1; i <= position; i++)
printf(",%d", set[i]);
printf("}");
if (set[position] < n)
{
set[position + 1] = set[position] + 1;
position++;
}
else if (position != 0)
set[--position]++;
else
break;
}
}
void main()
{
int set[MAXSIZE];
int n;
cout << "input number" << endl;
cin >> n;
printLexicographical(set, n);
}
对上面的算法稍作修改,即可对字符进行字典序生成:
#include <iostream>
using namespace std;
#define MAXSIZE 20
#define LOOP 1
char source[] = "abc";
const int size = sizeof source / sizeof *source;
void printLexicographical(int *set, int n)
{
int position = 0;
set[position] = 1;
while (LOOP)
{
printf("\n{%c", source[set[0] - 1]);
for (int i = 1; i <= position; i++)
printf(",%c", source[set[i] - 1]);
printf("}");
if (set[position] < n)
{
set[position + 1] = set[position] + 1;
position++;
}
else if (position != 0)
set[--position]++;
else
break;
}
}
void main()
{
int set[MAXSIZE];
int n;
cout << "input number" << endl;
cin >> n;
printLexicographical(set, n);
}
这样并不要求字符是连续有序的了~
再来看下面的解法
#include <iostream>
using namespace std;
#define MAXSIZE 20
#define LOOP 1
int set[MAXSIZE];
const int n = 3;
void printLexicographical()
{
const int size = 3;
int array[size];
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
array[j] = 0;
for (int j = i; j < size; j++)
{
array[j] = 1;
cout << "{";
for (int i = 0; i < size; i++)
{
if (array[i] == 1)
cout << i + 1;
}
cout << "}" << endl;
}
}
}
void main()
{
printLexicographical();
}