小结构与小算法:利用树结构求集合的幂集
来源:互联网 发布:淘宝提醒买家付款 编辑:程序博客网 时间:2024/05/01 14:22
求集合的幂集,这个问题本身并不难理解,至少在写程序时我们可以很容易就想到穷举法,然后就算是用很暴力的心态很粗暴地去编码都能够写出一个能有漂亮输出结果的程序,但闲得蛋疼的我想试下能不能让穷举法不那么粗暴,然后这个世界上就诞生了一段代码几张稿纸和一篇令人蛋疼的CSDN博文。
在弄清问题的本质后接下来就要考虑如何用计算机世界的语言去描述问题对象本身,在这里的问题对象当然就是“集合”,我们要求的是集合的幂集,也就是一个由集合的全体子集构成的集合,所以我们希望这个数据结构既能描述集合本身又同时能将集合的所有子集表现出来,就算只是很隐含地表现。只要找到这么一个数据结构,那么就可以按某种算法遍历该结构并输出其中所有元素,最后神奇地发现它输出的刚好就是集合的幂集。
数据结构很简单,是Tree,
算法也很简单:树结构某种遍历算法
首先假设我们遭遇了这么一个集合{0,1,2,3},完了它说要是我们不把它的子集求出来它就要对我们怎样怎样,好吧,只能怪我RP不好遇上这种事,还连累了大家。
我们先用树结构描述该集合以及它的一切子集:
0
┣1
┃┣2━3
┃┗3
┣2━3
┗3
上面那棵树我们不妨称它为"幂集树",下面给出幂集树的构造方法
给定如下集合{0,1,2,3},构造一棵幂集树。
1.根据集合元素的顺序从高到低为元素设置优先级,这里0的优先级最高,3的优先级最低。
2.按优先级从低到高的顺序构造幂集树,算法伪代码如下:
for(e : set.iterator().end())//逆序遍历集合元素 if(e == 集合中优先级最低的元素){ e.createSubTree(); //将该元素单独作为一棵只有一个节点的子树 } else{ e.createSubTree();//以该元素为根节点建立一棵子树 //按优先级从高到低的顺序遍历set中比元素e优先级低的元素 Iterator begin = set.iterator(e) + 1;//begin代表位于e相邻下一位的迭代器位置 Iterator end = set.iterator().end();//end代表集合中最后一个元素 for(e1 : set.iterator_From_To(begin,end)){ e.addSubTree(e1.getTreePointer()); } } }
以上算法中,假设元素的数据类型有一个tree成员。
3.取集合中第一个 元素的tree数据成员,即可得该集合的幂集树。
这样的话集合就出来了,而且该集合的所有子集也出现在了里面,不多也不少,当然要让所有子集现身我们还需要一个算法运行于该数据结构之上
这个算法剽窃于树的后序遍历算法,其实这么说也不大严格,但至少在遍历路径上我觉得它和后序遍历算法最接近,附上代码:
private void getAllSubset(TreeNode head){ route.add(head); for(TreeNode tn :route) System.out.print(tn.data + " "); System.out.println(); for(TreeNode kid : head.children) getAllSubset(kid); route.pollLast();}
我把这个函数命名为getAllSubset,其中route是一个链表,记录遍历路径,head是遍历开始的父节点,基本思想如下:从父节点开始按后序遍历的路径进行遍历,每到一个节点就将其加入route,接下来输出route的内容,然后对该节点的所有子叶节点递归调用getAllSubset方法,最后将该节点从route中删除。不过这样还不是算法的全部,因为少了该方法的调用方式,那么继续附上代码:
for(int i = 0; i <subsetTree.size(); i++) getAllSubset(subsetTree.get(i));
subsetTree就是上面的树结构,其实是只一个链表,只是通过在每个节点中添加指向同类型数据的引用,让这些引用指向subsetTree链表中的其它节点,从而在逻辑上将一个链表变成树结构,算法最顶层的思想就是:对subsetTree中的每一个元素调用getAllSubset,无论该元素是不是树的根节点,无论该元素是谁的子节点,无论该元素有无子节点,一视同仁地全部抓去当getAllSubset的参数。
然后输出如下:
0
0 1
0 1 2
0 1 2 3
0 1 3
0 2
0 2 3
0 3
1
1 2
1 2 3
1 3
2
2 3
3
集合{0,1,2,3}的所有子集都在上面,应该没错吧。什么,还少了一个空集?好吧好吧这个空集是皇帝的新空集,只有聪明人才看得到,如果你和我一样也看不到那我也木有办法,同病相怜吧。
以下全部源代码:
import java.util.LinkedList;public class GetSubset { private LinkedList<TreeNode>subsetTree =new LinkedList<TreeNode>(); private LinkedList<TreeNode>route =new LinkedList<TreeNode>(); public GetSubset(LinkedList<Integer> set){ for(Integer data : set){ subsetTree.add(new TreeNode(data)); } for(int i = 0; i <subsetTree.size(); i++){ int j = i; while(++j <subsetTree.size()){ subsetTree.get(i).addChild(j); } } for(int i = 0; i <subsetTree.size(); i++){ getAllSubset(subsetTree.get(i)); } } privatevoid getAllSubset(TreeNode head){ //System.out.println("[" + head.data + "]"); route.add(head); for(TreeNode tn :route) System.out.print(tn.data +" "); System.out.println(); for(TreeNode kid : head.children) getAllSubset(kid); route.pollLast(); } privateclass TreeNode{ Integer data; LinkedList<TreeNode> children; TreeNode(Integer data){ this.data = data; children =new LinkedList<TreeNode>(); } void addChild(int i){ children.add(subsetTree.get(i)); } } publicstaticvoid main(String[] args){ LinkedList<Integer> set =new LinkedList<Integer>(); for(int i = 0; i < 18; i++){ set.add(new Integer(i)); } GetSubset gss = new GetSubset(set); }}
- 小结构与小算法:利用树结构求集合的幂集
- C的小算法集合
- 掌握Applet 类与Applet小程序的基本结构,能够编写Applet小程序;
- JavaCard小应用程序结构
- JavaCard小应用程序结构
- 结构体小技巧
- JavaCard小应用程序结构
- 小试结构体
- 小用结构体
- 小试结构体
- 结构体小知识
- 结构体小知识
- 简单的自定义标签实现树结构的小功能
- 结构体下嵌套结构体的小例子
- 获取表结构的小技巧
- JVM 内存结构的一张小图
- 结构体偏移的小技巧
- 修改表结构的小知识
- 加勒比的伤感爱情日志分享:如果你知道我也爱你
- Android 秒表
- Java编程中“为了性能”需做的26件事
- HDU 2579 Dating with girls(2)
- 指针数组和数组指针的使用
- 小结构与小算法:利用树结构求集合的幂集
- 花花公子推荐伤感qq日志:乖不哭,我拜你
- 【作废】Inventor 二次开发学习指南入门到精通(含Inventor最新二次开发教程下载)
- 苏沫沫的原创伤感日志发布:我爱你比爱自己更过分
- SQLite学习
- 访问JSP文件或者Servlet文件时提示下载的解决方法
- OpenCV 下的图像任意角度的旋转
- 测试基础---测试用例设计之边界值
- Eclipse+Tomcat+MySQL+MyEclipse(详细设置)