集束算法的理解上相对来说还是比较简单的,该算法不是求解最优解而是尽可能的靠近最优解的算法。当集束层级达到12层以上每个子节点不超过5个时,节点数最高可达到了30W个节点左右,而需要从此得出最优解可能用穷尽法来算尽节点数也未尝是“最优”了。

这边推荐比较好去理解此算法的两篇博客。

集束搜索1    集束搜索2

下面具体用代码来说明吧!看集束算法上有分别使用图和树的模型来演示算法规则,此处只实现了树形模型,图形的大同小异就不实现了。

第一步,定义集束实体BEAM

import java.io.Serializable;/*** 集束算法的实体Bean,每个元素的定义* 集束bean中包含了 名称 概率值 哪个层级 该层级对应的集合号**/
public class Beam implements Serializable {/** 集束名称*/private String beamName;/** 集束值*/private Double beamValue;/** 集束层级*/private Integer beamLevel;/** 集束同一层级对应的那个集合号 1 2 3 4*/private Integer beamNo;/** 当前集束bean的父集束bean*/private Beam parentBeam;public Beam() {super();}public Beam(String beamName, Double beamValue, Integer beamLevel, Integer beamNo) {super();this.beamName = beamName;this.beamValue = beamValue;this.beamLevel = beamLevel;this.beamNo = beamNo;}public String getBeamName() {return beamName;}public void setBeamName(String beamName) {this.beamName = beamName;}public Double getBeamValue() {return beamValue;}public void setBeamValue(Double beamValue) {this.beamValue = beamValue;}public Integer getBeamLevel() {return beamLevel;}public void setBeamLevel(Integer beamLevel) {this.beamLevel = beamLevel;}public Integer getBeamNo() {return beamNo;}public void setBeamNo(Integer beamNo) {this.beamNo = beamNo;}public Beam getParentBeam() {return parentBeam;}public void setParentBeam(Beam parentBeam) {this.parentBeam = parentBeam;}
}

第二步,定义父子集束关系

import java.util.List;public class TreeBeam {/** 父层-集束号 规则 1-1第一层的第一个集束集合号*/private String parentBeamNo;/** 当前层-集束集合号 规则 1-1第一层的第一个集束集合号*/private String nowBeamNo;/** 集束beam的集合*/private List<Beam> beamList;public TreeBeam(String parentBeamNo, String nowBeamNo, List<Beam> beamList) {super();this.parentBeamNo = parentBeamNo;this.nowBeamNo = nowBeamNo;this.beamList = beamList;}public String getParentBeamNo() {return parentBeamNo;}public void setParentBeamNo(String parentBeamNo) {this.parentBeamNo = parentBeamNo;}public String getNowBeamNo() {return nowBeamNo;}public void setNowBeamNo(String nowBeamNo) {this.nowBeamNo = nowBeamNo;}public List<Beam> getBeamList() {return beamList;}public void setBeamList(List<Beam> beamList) {this.beamList = beamList;}
}

第三步,初始化集束集合,该集束为树形结构

package com.george.easylearn.algorithm.beam;import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;/*** 集束工厂的作用:* 1.定义好每个元素的信息,包括元素的概率值* 2.定义每个元素的层级关系* 3.定义每个元素可衍生出元素个数(随机或者固定)* 4.定义每个层级中元素集中包含beam的个数* 5.将上述定义好的元素存储到Map集合中 key 层级 value 为List<TreeBeam>**/
public class TreeBeamMap implements BeamMap{// 定义该集束的层级private final Integer levelCount = 6;// 集束的值范围 1-100之间private final Integer beamValueRange = 100;// 每次衍生出元素是否随机或者固定个数private boolean randFlag = true;// 每次衍生出元素的随机个数为1-5个private Integer randCount = 5;// 每次衍生出元素个数 默认固定2个也可根据随机来获取private Integer beamCount = 3;// 每个集束集中包含beam的个数private final Integer beamListCount = 6;// 定义每个元素的名称private char beamName = 'a';// 存储个元素层级的beam元素 key-Integer层数 key-String层数+集合号 规则为1-1 第一层的一个集合 0-表示其实层无父层级private Map<Integer, List<TreeBeam>> beamListMap = new HashMap<>();public TreeBeamMap(){// 初始化第一层的集束数据集initBeamListMap();// 从第二层开始推算后面的元素for (int i = 1; i < levelCount; i++) {// 获取上一层的集束集合号个数long lastLevelCount = beamListMap.get(i).stream().filter(distinctByKey(TreeBeam::getNowBeamNo)).count();// 上一层int lastBeamLevel = i;// 当前层int nowBeamLevel = i + 1;int nowBeanListNo = 0;for (int j = 0; j < lastLevelCount; j++) {// 集合编号int lastBeanListNo = j + 1;// 定义该层元素集合个数if (randFlag){Random random = new Random();beamCount = random.nextInt(randCount)+1;}// 集合当前层 集束Map集合List<TreeBeam> treeBeams = beamListMap.get(nowBeamLevel);if (treeBeams == null){treeBeams = new ArrayList<>();}for (int m = 0; m < beamCount; m++){List<Beam> beamList = new ArrayList<>();nowBeanListNo = nowBeanListNo + 1;for (int k = 0; k < beamListCount; k++){Random random = new Random();Double beamValue = random.nextInt(beamValueRange)+1.0;Beam beam = new Beam(String.valueOf((char)(beamName + k)), beamValue, nowBeamLevel, nowBeanListNo);beamList.add(beam);}String parentBeamListName = lastBeamLevel + "-" + lastBeanListNo;String beamListName = nowBeamLevel + "-" + nowBeanListNo;TreeBeam tempTreeBeam = new TreeBeam(parentBeamListName, beamListName, beamList);treeBeams.add(tempTreeBeam);beamListMap.put(nowBeamLevel, treeBeams);}}}}/*** 初始化第一层的集束数据集*/private void initBeamListMap(){// 初始化第一层的元素,只有一个List<TreeBeam> firstTreeBeams = new ArrayList<>();List<Beam> firstBeams = new ArrayList<>();for (int i = 0; i < beamListCount; i++){Random random = new Random();Double beamValue = random.nextInt(beamValueRange)+1.0;Beam beam = new Beam(String.valueOf((char)(beamName + i)), beamValue, 1, 1);firstBeams.add(beam);}// 规则为1-1 第一层的一个集合 0-表示其实层无父层级String parentBeamListName = "0-1";String beamListName = "1-1";TreeBeam treeBeam = new TreeBeam(parentBeamListName, beamListName, firstBeams);firstTreeBeams.add(treeBeam);beamListMap.put(1, firstTreeBeams);}/*** 根据TreeBeam对象中的nowBeamNo当前层的* @param keyExtractor* @param <T>* @return*/public <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor){Set<Object> distSet = ConcurrentHashMap.newKeySet();return t -> distSet.add(keyExtractor.apply(t));}/*** 输出树形的集束集合*/@Overridepublic void showBeamMap(){System.out.println("集束集合展示如下:");for (int levelTemp : beamListMap.keySet()) {System.out.println("层数:"+levelTemp);System.out.println("父集束号||当前集束号||集束名称-集束值 ");List<TreeBeam> tempMap = beamListMap.get(levelTemp);for (TreeBeam treeBeamTemp : tempMap) {List<Beam> beamTemp = treeBeamTemp.getBeamList();for (int i = 0; i < beamTemp.size(); i++) {Beam v = beamTemp.get(i);System.out.println(treeBeamTemp.getParentBeamNo()+"||"+v.getBeamLevel()+"-"+v.getBeamNo()+"||"+v.getBeamName()+"-"+v.getBeamValue()+" ");}}}}public Integer getLevelCount() {return levelCount;}public Map<Integer, List<TreeBeam>> getBeamListMap() {return beamListMap;}
}

第四步,实现集束算法的规则,抓取策略尤为重要

import java.util.*;
import java.util.stream.Collectors;/*** 集束算法的工厂类和实现集束算法的算法步进部分* 1.定义集束算法的宽度(即从集束集合号对应的集合中取值最大的数量)* 2.根据父集束的key获取子集束的集合,而后根据子集束中集束值最大的两个集束集合* 3.将此父集束再赋值给上述最大值的那两个子集束来作为父集束* 例如:父集束key为 2-2 对应的集束List个数为5个 最大值分别为 42 86 59 72 69 其中 72和86为最大则取出他们对应的集束List作为下一个父类提供下一层使用* 4.以此类推,最终追溯到最后一层后得出,每条路径的总值,再将各个总值进行比较得出最佳的路径。*/
public class TreeBeamSearch implements BeamSearch{// 集束抓取宽度 少于patchCount则算该集合个数private final int patchCount = 5;// 存储路径元素的集合, key为父集束序号(随着层级递进而变动),List为路径集合private Map<String, List<Beam>> pathMap = new HashMap<>();// 集束集合private TreeBeamMap treeBeamMap;public TreeBeamSearch(TreeBeamMap treeBeamMap) {super();this.treeBeamMap = treeBeamMap;}public void searchTreeBeamMap(){// 获取该树形集束的层数int levelCount = treeBeamMap.getLevelCount();// 获取该树形集束的所有集合Map<Integer, List<TreeBeam>> beamMap = treeBeamMap.getBeamListMap();// 初始化第一层的抓取TreeBeam treeBeam = beamMap.get(1).get(0);ArrayList<Beam> tempList = new ArrayList();// 从第一层开始获取出父集束号,根据父集束号来抓取子集束号最大值的固定个数for (int i = 1; i < levelCount; i++) {// 获取第i层的集束集合 将当前层作为父集束集合List<TreeBeam> treeBeams = beamMap.get(i);// 如果层数过多和分支过多时,遍历则过于缓慢 筛选掉父节点不在路径集合中的集束treeBeams = treeBeams.stream().filter(v -> pathMap.keySet().contains(v.getNowBeamNo())).collect(Collectors.toList());patchBeamByParentTreeBeams(beamMap, treeBeams, i);}// 统计出每条路径的总值,并求出最佳路径totalMaxBeamValueOfTreeBeam();}/*** 首先判断该父集束号 是否在路径中 不在路径中说明不是候选路径* 根据父集束号依次获取子集束集合并添加到集合内 先移除父集束 后添加子集束到路径集合中* @param* @param beamMap* @param parentTreeBeams* @param beamLevel 父集束的层号*/private void patchBeamByParentTreeBeams(Map<Integer, List<TreeBeam>> beamMap, List<TreeBeam> parentTreeBeams, int beamLevel) {for (TreeBeam partTreeBeam : parentTreeBeams) {// 获取子集束集合List<TreeBeam> treeBeams = beamMap.get(beamLevel + 1);// 先排序集合,获取当前tempList中最大值的那前两个子集束集合sortTreeBeamList(tempList);addMaxBeamValueToPathMap(tempList, partTreeBeam.getNowBeamNo());}}/*** 添加tempList中最大值的那前两个子集束集合到路径集合* @param treeBeams* @param parentBeamNo*/private void addMaxBeamValueToPathMap(List<TreeBeam> treeBeams, String parentBeamNo) {for (int i = 0; i < treeBeams.size(); i++) {TreeBeam treeBeam = treeBeams.get(i);if (i >= patchCount){break;}if (treeBeam != null){// 先获取父集束对应的集合List<Beam> parBeamList = pathMap.get(treeBeam.getParentBeamNo());beamList.add(getBeamByMaxBeamValue(treeBeam.getBeamList()));// 添加当前集束集合pathMap.put(treeBeam.getNowBeamNo(), beamList);}}// 移除父集束pathMap.remove(parentBeamNo);}/*** 统计出每条路径的总值,并求出最佳路径*/public void totalMaxBeamValueOfTreeBeam(){Map<String, Double> valueMap = new HashMap<>();System.out.println("集束集合中候选路径展示如下:");for (String pathKey : pathMap.keySet()) {List<Beam> treeBeamList = pathMap.get(pathKey);// 统计每条路径中集束最大值的那条路径的sum值,添加到map集合中Double sumBeamValue = treeBeamList.stream().collect(Collectors.summingDouble(Beam::getBeamValue));valueMap.put(pathKey, sumBeamValue);// 打印各个路径以及对应的值System.out.println("候选路径的值为:" + sumBeamValue);printTreeBeamPath(pathKey);}// 比较各个路径中的那个最大值。Map.Entry<String, Double> maxEntry = sortMapByValue(valueMap, 0);String bestPath = maxEntry.getKey();// 打印出最佳路径System.out.println("集束集合中最佳路径展示如下:");System.out.println("最佳路径的值为:" + maxEntry.getValue());printTreeBeamPath(bestPath);}/*** 获取最大的那个Beam集束* @param beamList* @return*/private Beam getBeamByMaxBeamValue(List<Beam> beamList) {Optional<Beam> beam = beamList.stream().collect(Collectors.maxBy(Comparator.comparingDouble(Beam::getBeamValue)));return beam.get();}/*** 打印各个路径以及对应的值* @param beamNo*/private void printTreeBeamPath(String beamNo) {// 获取该路径的集束集合List<Beam> beamList = pathMap.get(beamNo);// 对集束集合按路径从小到大进行排序sortBeamListByPath(beamList);System.out.print("路径顺序为: ");beamList.stream().forEach(beam-> {String beamListName = beam.getBeamLevel() + "-" + beam.getBeamNo();System.out.print(beamListName + ":"+ beam.getBeamValue() + " ");});System.out.println();}/*** 使用Collections.sort的Comparator比较器将“树形集束”中的节点按F值从大到小排序* @param treeBeamList*/private void sortTreeBeamList(List<TreeBeam> treeBeamList){Collections.sort(treeBeamList, (n1, n2) -> {if (getBeamByMaxBeamValue(n1.getBeamList()).getBeamValue() < getBeamByMaxBeamValue(n2.getBeamList()).getBeamValue()){return 1;}return -1;});}/*** 按集束的路径值从小到大进行排序* @param beamList*/private void sortBeamListByPath(List<Beam> beamList) {Collections.sort(beamList, (b1, b2) -> {if (b1.getBeamLevel() > b2.getBeamLevel() || b1.getBeamNo() < b2.getBeamNo()){return 1;}return -1;});}/*** flag = 1 正序 从小到大* flag = 0 倒序 从大到小* @param map* @param flag* @return*/private static <K, V extends Comparable<? super V>> Map.Entry<K, V> sortMapByValue(Map<K, V> map, int flag) {return map.entrySet().stream().sorted((o1, o2) -> flag == 1 ? o1.getValue().compareTo(o2.getValue()) : o2.getValue().compareTo(o1.getValue())).collect(Collectors.toList()).get(0);}
}

以上就是所有的集束算法的核心代码,还是那种句算法就是一个思想的结晶,当你去思考后你才能发现它的美,以及美中不足的地方。小伙伴们还是自己去编写一遍吧,还是很有意思的。如果想要源码连接在此。代码

EasyLearn--JAVA实现32个经典算法设计(二):集束算法相关推荐

  1. 视频教程-算法设计与编算法设计与编程实践---基于leetcode的企业真题库程实践-C/C++

    算法设计与编算法设计与编程实践---基于leetcode的企业真题库程实践 夏曹俊:南京捷帝科技有限公司创始人,南京大学计算机硕士毕业,有15年c++跨平台项目研发的经验,领导开发过大量的c++虚拟仿 ...

  2. 计算机 五大算法类型,计算机算法设计五大常用算法的分析及实例.docx

    标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N] 标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N] 计算机算法设计五大常用算法的分析及实例 摘要 算 ...

  3. 算法设计之常见算法策略

    1 算法简介 1.1 算法的定义 ​ 算法(Algorithm)是对特定问题求解步骤的一种描述,它是指令的有限序列,其中每一条指令表示一个或多个操作. 1.2 算法的特性 ​ 1.有穷性(Finite ...

  4. 程序设计与算法(二)算法基础-郭炜 1.3.1 称硬币

    程序设计与算法(二)算法基础-郭炜 1.3.1 称硬币 有12枚硬币.其中有11枚真币和1枚假币.假币和真币重量不同,但不知道假币比真币轻还是重.现在,用一架天平称了这些币三次,告诉你称的结果,请你找 ...

  5. 算法设计:UNION-FIND算法实现

    在上周的算法设计课程中,我们学习了UNION-FIND算法,该算法用来对不相交集进行查询与合并操作,但任何优秀的算法都必须要用实际的代码来进行实现,接下来我们就来看看具体的代码实现 1. 不相关集数据 ...

  6. 算法设计与分析——算法思想总结

    算法设计与分析 1.分治法 分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同.递归的解这些子问题,然后将各子问题的解合并得到原问题的解. 分治法所能解 ...

  7. 算法设计与分析——算法基础初步了解

    算法的概念 算法:一个有计算步骤构成的序列,可以将一组输入值转换成相应的输出值.或可以用例解决一个明确的问题. 问题:输入及相应输出的描述: 算法的特点:确定性.可行性.输入和输出及有穷性. 正确的算 ...

  8. 算法设计与分析——算法学基础(三):渐进记号

    分类目录:<算法设计与分析>总目录 相关文章: 算法学基础(一):算法学概述 算法学基础(二):分析算法 算法学基础(三):渐进记号 第<算法学基础(二):分析算法>中定义了算 ...

  9. 计算机算法设计与分析——算法引论

    1.1 算法与程序 计算机算法 通俗定义:用计算机求解问题的方法或过程. 正式定义:算法是满足下述性质的 指令序列: 输入:有零个或多个外部量作为算法的输入 输出:至少产生一个量作为输出 确定性:组成 ...

最新文章

  1. NeurIPS | 2019 机器学习领域最新十篇论文,来自谷歌、Facebook、普林斯顿大学、斯坦福大学等团队的最新研究成果...
  2. 2010版CCNP教材一览【图文】
  3. ECharts+BaiduMap+HT for Web网络拓扑图应用
  4. 【NLP】NLP爱好者学习资源推荐汇总
  5. 什么是 SAP UI5 的 Component-preload.js, 什么是Minification和Ugification
  6. linux网络编程之通信协议格式
  7. 列模式 文本编辑器_UltraEdit 24.2 文本编辑器免费版
  8. iOS开发UI篇—Quartz2D使用(矩阵操作)
  9. dnf服务器地址修改,修改dnf单机服务器地址
  10. 西门子界面官方精美触摸屏+WINCC程序模板 西门子官方触摸屏程序模板,炫酷的扁平式动画效果
  11. qlv是什么格式的视频,怎么把qlv格式转换成mp4
  12. 树莓派4B无显示屏系统安装(Raspbian)
  13. 36个顶级数据分析方法与模型!
  14. 八皇后算法带给我们的启示吧
  15. 前序、中序、后序表达式
  16. org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction
  17. Android定位方式和测试方法,定位方式(d16)
  18. 聚焦边缘创新,Rancher推出全新开源力作Octopus
  19. HTML XHTML DHTML 的区别(转)
  20. django源码阅读 manage.py文件

热门文章

  1. 字符串去掉小数点后取整数
  2. 周鸿祎给360员工的一份信:不做打工者
  3. 一个效率很高的汉字转拼音首字母的函数(未测试)
  4. 常见工业相机及接口综述
  5. 网上书城项目的需求分析、数据库表设计及前端界面的编写(项目进度一)
  6. Java通过freemarker生成word文档
  7. android-ProGuard混淆
  8. 如何禁用手机自带的输入法软键盘
  9. oracle数据库修改计算机名,oracle 批改计算机名
  10. 初步认知Next.js中ISR/RSC/Edge Runtime/Streaming等新概念