维特比算法的基础能够归纳为下面三点(吴军:数学之美):
一、若是几率最大的路径通过篱笆网络的某点,则从开始点到该点的子路径也必定是从开始到该点路径中几率最大的。
二、假定第i时刻有k个状态,从开始到i时刻的k个状态有k条最短路径,而最终的最短路径必然通过其中的一条。
三、根据上述性质,咱们在计算第i+1状态的最短路径时,只须要考虑从开始到当前的k个状态值的最短路径和当前状态值到第i+1状态值的最短java
篱笆网络node
以词网格为例,如何从词网格中找到最优结果算法
咱们只须要计算每一个箭头的分值,而后取整个路径分值最高的那条路径就是最优的分词结果网络
如何计算从“南”到“江”的最优路径优化
根据第三条性质:this
已这种方式计算“南”到“桥”全部路径,就能够取出最佳路径了。code
hanlp中的实现对象
/** * 维特比算法获取最优路径 * @param wordNet 词网格对象 第一个节点和最后一个节点都是 " " * @return Vertex为节点对象,返回最优路径的节点 */ private static List<Vertex> viterbi(WordNet wordNet) { // 避免生成对象,优化速度 LinkedList<Vertex> nodes[] = wordNet.getVertexes(); LinkedList<Vertex> vertexList = new LinkedList<Vertex>(); for (Vertex node : nodes[1]) { node.updateFrom(nodes[0].getFirst()); //先为第一个["南", "南京", "南京市"]节点 赋值(节点的from字段和分值weight) } for (int i = 1; i < nodes.length - 1; ++i) { // 第一层循环遍历全部竖线上的节点集合 ["南", "南京", "南京市"] LinkedList<Vertex> nodeArray = nodes[i]; if (nodeArray == null) continue; //节点集合若是为空,多是非中文的"长度占位",跳过 for (Vertex node : nodeArray) { // 第二层循环遍历竖线上节点集合中的元素 if (node.from == null) continue; //若是节点没有from说明不是路径上的元素,不计分 for (Vertex to : nodes[i + node.realWord.length()]) { // 第三层循环拿到当前竖线上节点集合的下一个竖线节点集合 to.updateFrom(node); //分别赋值(节点的from字段和分值weight) } } } Vertex from = nodes[nodes.length - 1].getFirst(); // 获取最后一个节点(" ") while (from != null) { // 通过updateFrom()方法 已经将每步的最优路径赋值到from上了,因此在这里直接从链表中取from就能够取出整个最优路径 vertexList.addFirst(from); from = from.from; } return vertexList; }
updateFrom()方法get
public void updateFrom(Vertex from) { double weight = from.weight + MathTools.calculateWeight(from, this); // 计算from节点到当前节点的分值 此值越低越优 if (this.from == null || this.weight > weight) { // 若是当前阶段没有from 或者 当前分值大于新的分值 则赋值 this.from = from; this.weight = weight; } }
维特比算法能够计算全部相似于可用这种网格形式表示的最佳路径,不单单用于分词数学