目录
一.例子
现在有一个数组如下:
ar[3] = {1,2,3};
那么这个集合的全部子集为
{} {1} {2} {3} {1,2} }{2,3} {1,3} {1,2,3}。
二.代码
#include<stdio.h>
void fun(int* ar, int* br, int i, int n)
{
if (i >= n)
{
for (int j = 0; j < n; ++j)
{
if (br[j])
{
printf("%d ", ar[j]);
}
}
printf("\n");
}
else
{
//树的左边
br[i] = 1;
fun(ar, br, i + 1, n);
//树的右边
br[i] = 0;
fun(ar, br, i + 1, n);
}
}
int main()
{
int ar[] = { 1,2,3 };
int br[] = { 0,0,0 };
fun(ar, br, 0, 3);
return 0;
}
三.分析
我们看到我们在这个数组的下标分别作了标记,其中:
- 0,0,0代表什么都不打印,即当前的子集为空集{
}
- 1,0,0代表打印1,即当前的子集为{1}
- 0,1,0代表打印2,即当前的子集为{2}
- 0,0,1代表打印3,即当前的子集为{3}
- 1,1,0代表打印1,2,即当前的子集为{1,2}
- 1,0,1代表打印1,3,即当前的子集为{1,3}
- 0,1,1代表打印2,3,即当前的子集为{2,3}
- 1,1,1代表打印1,2,3,即当前的子集为{1,2,3}
即当标记在数组下标的数字为1时,打印数组在这个位置的值。
我们将这一特性与一棵二叉树,相绑定,如下图所示
- 当第一次进入fun函数时,i = 0,n =3,i != n,此时执行br[i] = 1,fun(ar,br,i+1,n)
- 进入新的fun函数时,i = 1,n =3,i != n,此时执行br[i] = 1,fun(ar,br,i+1,n)
- 进入新的fun函数时,i = 2,n =3,i != n,此时执行br[i] = 1,fun(ar,br,i+1,n)
- 进入新的fun函数时,i = 3,n =3,i == n,此时执行打印语句
- 与此同时执行层次遍历,即执行b[i] = 0,fun(ar,br,i+1,n)
- 进入新的fun函数时,i = 3,n =3,i == n,此时执行打印语句
- 进入新的fun函数时,i = 2,n =3,i != n,此时执行br[i] = 1,fun(ar,br,i+1,n)
- 与此同时执行层次遍历,即执行b[i] = 0,fun(ar,br,i+1,n)
- 进入新的fun函数时,i = 2,n =3,i != n,此时执行br[i] = 1,fun(ar,br,i+1,n)
- 进入新的fun函数时,i = 3,n =3,i == n,此时执行打印语句
- 与此同时执行层次遍历,即执行b[i] = 0,fun(ar,br,i+1,n)
- 进入新的fun函数时,i = 3,n =3,i == n,此时执行打印语句
- 进入新的fun函数时,i = 2,n =3,i != n,此时执行br[i] = 1,fun(ar,br,i+1,n)
- 进入新的fun函数时,i = 1,n =3,i != n,此时执行br[i] = 1,fun(ar,br,i+1,n)
- 与此同时执行层次遍历,即执行b[i] = 0,fun(ar,br,i+1,n)
上面就是这个二叉树左子树的的执行过程,右面的执行过程与其相同,我们就不在进行阐述。