博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
子集生成——回溯法的准备篇
阅读量:6870 次
发布时间:2019-06-26

本文共 1204 字,大约阅读时间需要 4 分钟。

在如何获得全排列的文字里,大家会发现递归可以说随处可见,而在回溯法中,递归更是实现枚举的基本手段。在生成子集的方法中,我们也将看到递归的影子

为了简单,这里不涉及可重集的子集

递归不能深究详细的过程,而要注意第一步向第二步如何推广,以及推广后的递归如何在边界终止。

一、增量构造法

这种思路和按照字典序枚举全排列的思路一致,本质是递归地构造子集。

思路等同于解答树:

  1. 如果子集非空,则输出
  2. 递归调用,将a[cur-1]+1不断赋值给a[cur],然后递归找出剩余的子集
  3. 边界终止条件:隐式的递归条件,当没有元素可加入时,递归就会停止

代码如下:

1 //定义数据 2 int a[5]; 3 void print_subset(int n,int *a,int cur){ 4      for(int i=0;i

 

二、位向量法

位向量法与直接构造法的区别在于数组的使用方式不同,位向量法用数组下标表示子集元素,而数组内容为1或0,表示该元素 在 或者 不在 集合内。

注意,和直接构造不同,每个元素都有0和1(不在/在)两种方式,因此,位向量法的解答树节点数比直接构造法多出一倍减一个,例如直接构造法的10个元素的解答树,有2^10=1024个节点,而用位向量法,因为每个元素都有0和1两种状态,因此有2*1024-1=2047个节点(根节点都只有一个,所以不是单纯2倍关系),因此速度理论上要慢一些,但多数情况下仍然够用

位向量法需要指定显式的递归边界,因为我们不能明确知道究竟一次有多少元素会被打印。

 代码如下:

1 int a[5]; 2 void print_subset(int n,int *a,int cur){ 3     if(cur==n){
//显式的递归边界 4 for(int i=0;i

 

三、二进制法(最快最简单代码最少,限制是数字会爆)

本质和位向量法相同,但是由于是二进制,因此一个整数(1<<n)-1就可以代表一个全集,这种实现接近计算机底层,加上C语言自身就支持二进制的运算,如&(交集),|(并集),^(对称差和开关性)等,因此速度和代码简洁性都优于位向量法。

 二进制法从右向左表示集合中的元素(从低位到高位)如0110是数字6,代表的集合是{ 1,2 },010111是数字23,代表的是{ 0,1,2,4 },n个元素所有的可能的情况有2^n个,即(1<<n)-1种

实现如下: 

1 void print_subset(int n,int s){
//s为{0,1,。。,n-1}的子集 2 for(int i=0;i

其实我觉得我对于二进制还不是很熟悉,因此二进制法应当继续加深练习。今天就到这,拜拜~~~

转载于:https://www.cnblogs.com/luruiyuan/p/5625427.html

你可能感兴趣的文章
静态内部类
查看>>
localStorage使用总结
查看>>
计算一年中的第几天
查看>>
iOS 一句话获取日期和星期几
查看>>
【javascript】Lazy Load, 延迟加载图片的 jQuery 插件
查看>>
Percona XtraDB Cluster高可用与状态快照传输(PXC 5.7 )
查看>>
OBJECT_ID 技巧整理
查看>>
Date日期类,Canlendar日历类,Math类,Random随机数学类
查看>>
java中forName()的作用
查看>>
解决oracle_4031错误的方法
查看>>
C# Out,Ref 学习总结
查看>>
CentOS 7.4如何安装Python3
查看>>
instanceof
查看>>
activity的四种模式
查看>>
z-index
查看>>
git 和github
查看>>
Vue的路由
查看>>
RESTful API
查看>>
mysql之select(二)
查看>>
万能分页存储过程
查看>>