当前位置: 代码网 > it编程>软件设计>数据结构 > 【数据结构与算法】第十七、十八章:加权无向图、最小生成树(切分定理、贪心算法、Prim算法

【数据结构与算法】第十七、十八章:加权无向图、最小生成树(切分定理、贪心算法、Prim算法

2024年08月06日 数据结构 我要评论
17.1、边的表示加权无向图中的边不能简单的使用v-w两个顶点表示了,而必须要给边,因此可以使用来描述一条边17.2、加权无向图的实现/**@author 土味儿加权无向图*//***//***//***//**构造器*/// 初始化顶点数量// 初始化边数量// 初始化邻接表// 初始化邻接表中的空队列i < vNum;i++) {/**得到顶点数量@return*//**得到边数量@return*//**添加一条边v-w。

在这里插入图片描述

17.1、边的表示


加权无向图中的边不能简单的使用v-w两个顶点表示了,而必须要给边 关联一个权重值,因此可以使用 对象 来描述一条边

在这里插入图片描述

17.2、加权无向图的实现


  • api

在这里插入图片描述

  • 代码

package chapter17;

import chapter03.queue;

/**

  • @author 土味儿

  • date 2021/9/16

  • @version 1.0

  • 加权无向图

*/

public class edgeweightedgraph {

/**

  • 顶点
    数量

*/

private final int vnum;

/**

  • 边数量

*/

private int enum;

/**

  • 邻接表

*/

private queue[] adj;

/**

  • 构造器

  • @param vnum

*/

public edgeweightedgraph(int vnum) {

// 初始化顶点数量

this.vnum = vnum;

// 初始化边数量

this.enum = 0;

// 初始化邻接表

this.adj = new queue[vnum];

// 初始化邻接表中的空队列

for (int i = 0; i < vnum; i++) {

this.adj[i] = new queue();

}

}

/**

  • 得到顶点数量

  • @return

*/

public int getvnum(){

return vnum;

}

/**

  • 得到边数量

  • @return

*/

public int getenum(){

return enum;

}

/**

  • 添加一条边v-w

  • @param e

*/

public void addedge(edge e){

// 因为是无向图,让边e同时出现在e的两个顶点的邻接表中

int v = e.either();

int w = e.other(v);

this.adj[v].enqueue(e);

this.adj[w].enqueue(e);

// 边数量加1

enum++;

}

/**

  • 获取顶点v的所有相邻顶点

  • @param v

  • @return

*/

public queue adj(int v){

return this.adj[v];

}

/**

  • 获取加权无向图中的所有边

  • @return

*/

public queue edges(){

// 创建一个队列对象,存储所有的边

queue alledges = new queue<>();

// 遍历图中的每一个顶点,找到每个顶点的邻接表,邻接表中存储了该顶点关联的每一条边

for(int v=0;v<vnum;v++){

// 遍历顶点v的邻接表,找到每一条和v关联的边

for (edge e : adj(v)) {

// 每条边的两个顶点,一大一小,判断大小再添加,可以避免重复

if(e.other(v) < v){

alledges.enqueue(e);

}

}

}

return alledges;

}

}

18、最小生成树

==================================================================

18.1、定义及相关约定


  • 图的生成树 是它的一棵含有其 所有顶点无环连通子图,一副加权无向图的最小生成树,是它的一棵权值(树中所有边的权重之和)最小的生成树

在这里插入图片描述

  • 只考虑连通图

在这里插入图片描述

  • 所有边的权重都各不相同

18.2、最小生成树原理


1)树的性质

  • 用一条边连接树中的任意两个顶点都会产生 一个新的环

在这里插入图片描述

  • 从树中删除任意一条边,将会得到 两棵独立的树

在这里插入图片描述

2)切分定理

  • 切分
  • 横切边

在这里插入图片描述

  • 切分定理

在这里插入图片描述

  • 注意

在这里插入图片描述

3)贪心算法

贪心算法是计算图的最小生成树的基础算法,它的基本原理就是 切分定理

使用切分定理找到最小生成树的一条边,不断的重复直到找到最小生成树的所有边

如果图有 v 个顶点,那么需要找到 v-1 条边,就可以表示该图的最小生成树

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4)prim算法

  • prim算法的切分规则

在这里插入图片描述

1、prim算法api设计

在这里插入图片描述

2、prim算法的实现原理

prim算法始终将图中的顶点切分成两个集合,最小生成树顶点非最小生成树顶点,通过不断的重复做某些操作,可以逐渐将非最小生成树中的顶点加入到最小生成树中,直到所有的顶点都加入到最小生成树中

在这里插入图片描述

在这里插入图片描述

3、代码

package chapter18;

import chapter03.queue;

import chapter07.indexminpriorityqueue;

import chapter17.edge;

import chapter17.edgeweightedgraph;

/**

  • @author 土味儿

  • date 2021/9/17

  • @version 1.0

  • 最小生成树prim算法

*/

public class primmst {

/**

  • 最小边

  • 索引代表顶点

  • 值表示当前顶点到最小生成树之间的最小边

*/

private edge[] edgeto;

/**

  • 最小边的权重

  • 索引代表顶点

  • 值表示当前顶点到最小生成树之间的最小边的权重

*/

private double[] distto;

/**

  • 索引代表顶点

  • 如果当前顶点已经在树中,则值为true,否则为false

*/

private boolean[] marked;

/**

  • 存放树中顶点与非树中顶点的有效横切边

*/

private indexminpriorityqueue pq;

/**

  • 构造器

  • 根据加权无向图创建最小生成树

  • @param g

*/

public primmst(edgeweightedgraph g) {

// 初始化edgeto

this.edgeto = new edge[g.getvnum()];

// 初始化distto

this.distto = new double[g.getvnum()];

for (int i = 0; i < g.getvnum(); i++) {

// 默认值:正无穷大

this.distto[i] = double.positive_infinity;

}

// 初始化marked

this.marked = new boolean[g.getvnum()];

// 初始化pq

pq = new indexminpriorityqueue(g.getvnum());

// 默认让顶点0进入到树中,但是树中只有一个顶点0,因此,顶点0没有和任何顶点相连,所以distto对应位置处的值为0.0

distto[0] = 0.0;

pq.insert(0,0.0);

// 遍历索引最小优先队列,拿到最小横切边对应的顶点,把该顶点加入到最小树中

while(!pq.isempty()){

visit(g, pq.delmin());

}

}

/**

  • 获取最小生成树的所有边

  • @return

*/

public queue edges(){

// 创建队列对象

queue alledges = new queue<>();

// 把edgeto中非null的值加入队列

for (int i = 0; i < edgeto.length; i++) {

if(edgeto[i] != null){

alledges.enqueue(edgeto[i]);

}

}

return alledges;

}

/**

  • 将顶点v添加到最小生成树中,并更新数据

  • @param g

  • @param v

*/

private void visit(edgeweightedgraph g,int v){

// 把顶点v添加到最小生成树中

marked[v] = true;

// 更新数据

for (edge e : g.adj(v)) {

// 获取边e的另外一个顶点w(当前顶点v)

int w = e.other(v);

// 判断另一个顶点是否在树中,如果在树中,不做处理;如果不在树中,更新数据

if(marked[w]){

// 继续下次循环;不是退出,不能用break

continue;

}

// 比较权重:判断边e的权重是否小于 w到最小树中已存在的最小边的权重

if(e.getweight() < distto[w]){

// 更新数据

edgeto[w] = e;

distto[w] = e.getweight();

if(pq.contains(w)){

pq.changeitem(w, e.getweight());

}else{

pq.insert(w, e.getweight());

}

}

}

}

}

  • 测试

package chapter18;

import chapter03.queue;

import chapter17.edge;

import chapter17.edgeweightedgraph;

import org.junit.test;

import java.io.bufferedreader;

import java.io.ioexception;

import java.io.inputstreamreader;

/**

  • @author 土味儿

  • date 2021/9/17

  • @version 1.0

  • 测试prim最小生成树

*/

public class primmsttest {

@test

public void test() throws ioexception {

// 准备一幅加权无向图

bufferedreader br = new bufferedreader(new inputstreamreader(primmsttest.class.getclassloader().getresourceasstream(“min_create_tree_test.txt”)));

// 顶点数量

int total = integer.parseint(br.readline());

// 加权无向图

edgeweightedgraph g = new edgeweightedgraph(total);

// 边的数量

int edges = integer.parseint(br.readline());

// 依次读取边

for (int i = 0; i < edges; i++) {

string line = br.readline();

string[] s = line.split(" ");

int v = integer.parseint(s[0]);

int w = integer.parseint(s[1]);

double weight = double.parsedouble(s[2]);

// 创建加权无向边

edge edge = new edge(v, w, weight);

// 向图中加入边

g.addedge(edge);

}

// 创建prim最小生成树对象

primmst primmst = new primmst(g);

// 得到最小生成树

queue alledges = primmst.edges();

// 输出

for (edge e : alledges) {

int x = e.either();

int y = e.other(x);

double w = e.getweight();

system.out.println(x + " - " + y + " : " + w);

}

}

}

  • min_create_tree_test.txt

8

16

4 5 0.35

4 7 0.37

5 7 0.28

0 7 0.16

1 5 0.32

0 4 0.38

2 3 0.17

1 7 0.19

0 2 0.26

1 2 0.36

1 3 0.29

2 7 0.34

6 2 0.40

3 6 0.52

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com