求最小函数依赖以及结果为3NF的保持函数依赖分解---Java实现
2016-11-30 17:01
267 查看
最近看到的《数据库原理及应用》的两个关于关系模式的算法,稍微实现了一下。
我的思路差不多都写在注释里了,就先上代码吧:
总之不忍吐嘈一个Java代码愣是被我写成了面向过程的风格,还是基本功不扎实啊。
我的思路差不多都写在注释里了,就先上代码吧:
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION; import javax.lang.model.type.ArrayType; import javax.lang.model.util.SimpleTypeVisitor6; import javax.print.DocFlavor; import java.util.*; import java.util.stream.Collector; /** * Created by coder-z on 16-11-25. */ public class Leastcloset { public static Set<Character> U=new HashSet<Character>(); public static Map<String,HashSet<Character>> F=new HashMap<String,HashSet<Character>>(); public static Set<Character> L=new HashSet<Character>(); public static Set<Character> R=new HashSet<Character>(); public static List<Set<Character>> TriNF=new LinkedList<Set<Character>>(); public static String key=null; /** * 获得主键 * @return */ public static Set<Character> getPriKey() { Set<Character> result=new HashSet<Character>(); for(String key:F.keySet()) { Iterator it=F.get(key).iterator(); for(char ch:key.toCharArray()) { L.add(ch); while(it.hasNext()) { char chr=(char)it.next(); R.add(chr); } } } for(char element:U) { if(R.contains(element)) continue; result.add(element); } key=ArrayToString(result); return result; } /** * 初始化数据:将键值对拆分成字符集合 * @param src */ //(a-(f=t=a),c-d,d-f) 需要分解 public static void initData(String src) { U.addAll(new HashSet<Character>(Arrays.asList('C','T','H','R','S','G'))); String[] tuples=src.split(","); for(String str:tuples) { HashSet&l 4000 t;Character> characterSet=new HashSet<>(); String[] temp=str.split("-"); for(char ch:temp[1].toCharArray()) { characterSet.add(ch); } F.put(temp[0],characterSet); } } /** * 求闭包,直接使用尾递归更新数据 * 思路:遍历键值对的键集合,检查现有闭包是否涵盖每个键集合的字符串,如果涵盖,则递归更新数据,重新遍历检查,直到所有的键集合被遍历完成 * 同时,为了不重复访问,用visited记录 * @param src * @param visited 已经访问过的键集合 * @return */ public static TreeSet<Character> getCloset(String src,Set<String> visited) { TreeSet<Character> closet=new TreeSet<Character>(); for(char ch:src.toCharArray()) { closet.add(ch); } if(visited.size()==F.keySet().size()||closet.size()==U.size()) return new TreeSet<>(U); for(String key:F.keySet()) { if(contains(key,src)) continue; Iterator<Character> it=F.get(key).iterator(); if(contains(key,ArrayToString(closet))&&!visited.contains(key)) { while(it.hasNext()) { Character ch=it.next(); closet.add(ch); } visited.add(key); return getCloset(ArrayToString(closet),visited); } } return closet; } /** * 求src是否是trg的子串,即src是否被trg包含(不考虑顺序和连续性) * @param src * @param trg * @return */ public static boolean contains(String src,String trg) { int tag=0; for(char ch:src.toCharArray()) { for(char chr:trg.toCharArray()) if(chr==ch) { tag++; break; } } return tag==src.length(); } /** * 字符型集合和字符串类型转换 * @param set * @return */ public static String ArrayToString(Set<Character> set) { //原来是treeSet,现在换成接口 StringBuffer buf=new StringBuffer(); for(char c:set) { buf.append(c); } return buf.toString(); } public static void leftPan() { Set<String> keySet=F.keySet(); Iterator<String> its=keySet.iterator(); HashSet<String> needCut=new HashSet<String>(); while(its.hasNext()) { String key=its.next(); Iterator<Character> it=F.get(key).iterator(); for(char ch:key.toCharArray()) { while(it.hasNext()) { Character chr=it.next(); if(contains(key,ArrayToString(getCloset(ch+"",new HashSet<>())))) { needCut.add(key); } } } } for(String cut:needCut) { F.remove(cut); } } /** * 求最小函数依赖集的主函数 * 思路:遍历键值对中的每一个键,分别求其闭包,如果闭包内含有对应的值,则消除该键值对 * */ public static void getFmin() { TreeSet<Character> closet; HashSet<String> needCut=new HashSet<String>(); for(String key:F.keySet()) { HashSet<Character> temp=F.get(key); System.out.println(temp); Iterator<Character> it=temp.iterator(); while(it.hasNext()) { Character ch=it.next(); if (ArrayToString(getCloset(key,new HashSet<>())).contains(ch+"")) { it.remove(); if(temp.isEmpty()) needCut.add(key); } } } for(String cut:needCut){ F.remove(cut); } // leftPan(); } /** * * @param set * @return 返回该集合是否只包含主键内容 */ public static boolean isFomatSet(Set<Character> set) { if("".equals(key)) throw new IllegalArgumentException("no key words!"); return collectionEquals(CharacterOut(key),set); } /** * 比较两个集合中的元素是否完全相同 * @param c1 * @param c2 * @return */ public static boolean collectionEquals(Collection<Character> c1,Collection<Character> c2) { if(c1.isEmpty()||c2.isEmpty()||c1.size()!=c2.size()) return false; Iterator it1=c1.iterator(); Iterator it2=c2.iterator(); while(it1.hasNext()&&it2.hasNext()) { if(it1.next()!=it2.next()) return false; } return true; } public static Set<Character> CharacterOut(String src) { Set<Character> result=new HashSet<Character>(); for(char ch:src.toCharArray()) result.add(ch); if(F.containsKey(src)) { for(Character ch:F.get(src)) { result.add(ch); } } return result; } /** * 根据集合中的字符返回含有该集合字符所组成的键的集合 * @param characters * @return 返回键的集合,键的元素是由字符集合中元素组成的 */ public static Set<String> getKeySet(Collection<Character> characters) { Set<String> keySet = new HashSet<>(); for(String key:F.keySet()) { if(collectionEquals(CharacterOut(key),characters)) keySet.add(key); } return keySet; } /** * 函数依赖分解的主要逻辑: * 遍历键集合,寻找选中所有由集合carpet中的字符组成的键keySet,然后消除reaminder中keySet中所有对应的值,直到找到主键为止 * 其中使用递归同样是为了更新数据 * @param remainder 剩余字符集合 * @param carpet 目前选中的键的字符集合 * @param visited 已访问过的键集合 * @return 尾递归 */ public static Set<Character> decompose(Set<Character> remainder,Set<Character> carpet,Set<String> visited) { if(!carpet.isEmpty()) TriNF.add(new HashSet<Character>(carpet)); //加入分解集合 if(isFomatSet(carpet)) //如果选中的字符集就是主键,则结束 return carpet; else carpet.clear(); Set<Character> remainders=remainder; Set<Character> carpets=carpet; Set<String> visiteds=visited; for(String keyStr:F.keySet()) { if(!visited.isEmpty()&&visited.contains(keyStr)) //如果数据该键已经被访问过则跳过 continue; else visited.add(keyStr); Iterator it=F.get(keyStr).iterator(); for(char c:keyStr.toCharArray()) { //手动装载选中的键 carpet.add(c); } while(it.hasNext()) { carpet.add((Character)it.next()); //装载对应的值,形成选中集合 } for(String keyS:getKeySet(carpet)) { for(Character ch:F.get(keyS)) { remainder.remove(ch); } } return decompose(remainder,carpet,visited); //数据更新 } return null; //结束整个流程 } public static void main(String...args) { Scanner input=new Scanner(System.in); String src=input.nextLine(); initData(src); getFmin(); System.out.println(F); TriNF.add(getPriKey()); System.out.println(TriNF); decompose(U, new HashSet<Character>(),new HashSet<String>()); System.out.println(TriNF); } }
总之不忍吐嘈一个Java代码愣是被我写成了面向过程的风格,还是基本功不扎实啊。
相关文章推荐
- 二、转换成3NF的保持函数依赖的分解
- 转换成3NF的保持无损连接和函数依赖的分解
- 1.转换成3NF的保持函数依赖的分解
- 三、转换成3NF的保持无损连接和函数依赖的分解
- 分解成3NF保持函数依赖且为无损连接的算法
- 具有无损性连接和保持函数依赖的3NF分解C++实现
- 【数据库】转换成3NF的保持无损连接和函数依赖的分解
- 分解成3NF的保持函数依赖的分解算法:
- 2.转换成3NF的保持无损连接和函数依赖的分解
- 关系规范化之满足第三范式3NF的函数依赖保持分解算法
- 【数据库】转换成3NF的保持函数依赖的分解
- 转换成3NF的保持无损连接和函数依赖的分解
- 动态函数调用实现下列操作,输入2个数以及操作符计算结果。 @ 求最大公约数 $求最小公倍数 - 求差 + 求和 等等
- Java中异或运算实现两个整数的交换以及其功能函数实现
- 实现一个用分子分母的格式来表示有理数的结构体rational以及相关的函数,rational结构体之间可以做加减乘除运算,运算的结果仍然是rational
- java 实现BufferedImage和ImageReader两种方式获取图片宽高、判断图片类型、获取图片大小工具类代码以及测试响应结果
- 求无向连通图的最小割点详解以及java源代码实现
- Java实现文件重命名 以及file类的其他函数讲解
- javascript中bind()函数实现和应用以及多次bind的结果和参数位置的思考
- 单向链表的Java实现,以及相关函数。