输出数组P[a,b,b,b]的全排列\全子集 ; 注意集合元素有重复
#define N 4
char P[]={'a', 'b', 'b', 'c'}
int main()
{
int i, j, A[N];
printf("全排列-递归\n");
permutation1(N, A, 0);
printf("全排列-非递归\n");
//用索引 转化数组P 为A[1, 2, 2, 4]
for(i=0; i
{
if( i==0 || P[i]!=P[i-1] )
j = i;
A[i]=j;
}
permutation2(N, P);
printf("子集--增量构造--没有去重\n");
subset1(N, A, 0);
printf("子集--位向量--没有去重\n");
subset2(N, A, 0);
printf("子集--二进制--去重啦\n");
//用索引 转化数组P 为A[1, 2, 2, 4]
for(i=0; i
{
if( i==0 || P[i]!=P[i-1] )
j = i;
A[i]=j;
}
memset(HashArray, -1, sizeof(HashArray));
subset3(N, A);
}
输出:
全排列-递归
a b b b
b a b b
b b a b
b b b a
全排列-非递归
a b b b
b a b b
b b a b
b b b a
子集--增量构造--没有去重
a
a b
a b b
a b b b
a b b
a b
a b b
a b
b
b b
b b b
b b
b
b b
b
子集--位向量--没有去重
b
b
b b
b
b b
b b
b b b
a
a b
a b
a b b
a b
a b b
a b b
a b b b
子集--二进制--去重啦
a
b
a b
b b
a b b
b b b
a b b b
/* 递归
* 不断的填充索引A[cur]的值 直到cur==n
*/
void permutation1(int n, int *A, int cur)
{
int i,j,c1,c2;
if(cur==n)
{
for(i=0; iprintf ("%c ", P[A[i]]);
}
printf("\n");
return;
}
for(i=0;iif( i==0 || P[i]!=P[i-1] )
{
c1=c2=0;
for(j=0;jif(P[i]==P[A[j]]) c1++; // 已经出现次数
for(j=0;j=c2; j++) if(P[i]==P[j]) c2++; // 是否至少出现了c1+1次
if( c1 < c2 )
{
A[cur]=i;
permutation1(n, A, cur+1);
}
}
}
/* 非递归 */
void permutation2(int n, int *A)
{
int i, j;
/*
* 从字典序最小[升序排列] 逐步增大 直到 字典序最大[降序排列]
* 算法:
* 初始态 值升序排列
* 从右往左找到i 使得 A[i] > A[i+1] && A[i+1:]降序 < i==-1 A[0:] 已经是降序排列了 算法结束 >
* 从右往左找到j 使得 A[i] < A[j];
* 逆序 A[i+1:]
*/
while(1)
{
//打印
for(i=0; i
printf("%c ", P[A[i]]);
printf("\n");
//find 临界点A[i]
i=n-2;
while( i>=0 && A[i]>=A[i+1]) i--;
if(i==-1) return;
//find 比A[i]大的数字A[j]
j=n-1;
while(A[i]>=A[j]) j--;
// exchange
A[i] ^= A[j]; A[j] ^= A[i]; A[i] ^= A[j];
// reversed A[i+1:]
for(i=i+1, j=n-1; i
{ A[i] ^= A[j]; A[j] ^= A[i]; A[i] ^= A[j]; }
}
}
/* 子集--增量构造发 */
void subset1(int n, int *A, int cur )
{
int i, s;
for(i=0; iprintf("%c ", P[A[i]]);
printf("\n");
s = cur ? A[cur-1]+1 : 0;
for(i=s; i1);
}
}
void subset2(int n, int *A, int cur)
{
int i;
if(cur==n)
{
for(i=0; iif(A[i])
printf("%c ", P[i]);
printf("\n");
return;
}
A[cur]=0;
subset2(n, A, cur+1);
A[cur]=1;
subset2(n, A, cur+1);
}
/* 判断n是否出现过 需要初始化memset(HashArray, -1, sizeof(HashArray))
* HashArray大小应该要大于所有无重复子集的个数
* */
static int HashArray[1024];
int hasExisted(int n)
{
int LEN=1024;
int k = n%LEN;
while( HashArray[k]!=-1 && HashArray[k]!=n && k!=(n%LEN-1)%LEN) k=(k+1)%LEN;
if (k==(n%LEN-1)%LEN){
return 2; // 数据满了
}
if (HashArray[k]==-1) // 没有n
{
HashArray[k]=n;
return 0;
}
return 1;
}
/*子集--二进制*/
void subset3(int n, int *A)
{
int i=0, j=0, code;
while(i < 1<1;
for(j=0; jif( i & 1<*10+A[j];
switch( hasExisted(code) )
{
case 1:
break;
case 2:
printf("数据error!\n");
return;
case 0:
for(j=0; jif( i & 1<"%c ", P[A[j]]);
printf("\n");
break;
}
i++;
}
}