算法入门篇十 图

图的存储方式

  • 临接表
  • 临接矩阵

表达

  • 点集/边集
  • 有向图/无向图

Graph(大结构就是图)(包含点集合和边集合)

import java.util.HashMap;
import java.util.HashSet;public class Graph {public HashMap<Integer, Node> nodes;//点集合public HashSet<Edge> edges;//边集合public Graph() {nodes = new HashMap<>();edges = new HashSet<>();}
}

Node(点集合) 

import java.util.ArrayList;public class Node {public int value;//数值public int in;//入度public int out;//出度public ArrayList<Node> nexts;//从当前点出发,连接的数据点(出度连接的点)public ArrayList<Edge> edges;//从当前点出发,连接的边(出度的边)public Node(int value) {this.value = value;in = 0;out = 0;nexts = new ArrayList<>();edges = new ArrayList<>();}
}

Edge(边集合)

 public class Edge {public int weight;//边的权重public Node from;//有向边public Node to;//有向边public Edge(int weight, Node from, Node to) {this.weight = weight;this.from = from;this.to = to;}}

接口函数(将未知的题目类型转化为我们所熟知的类型,如上图所示)

public class GraphGenerator {// matrix 所有的边// N*3 的矩阵// [weight, from节点上面的值,to节点上面的值]//example//【7,0,1】第一个代表from,第二个代表to,第三个代表weight//【6,1,2】//【4,2,0】public static Graph createGraph(Integer[][] matrix) {Graph graph = new Graph();for (int i = 0; i < matrix.length; i++) { // from:matrix[0][0], to:matrix[0][1]  权重(weight):matrix[0][2]Integer from = matrix[i][0];Integer to = matrix[i][1];Integer weight = matrix[i][2];if (!graph.nodes.containsKey(from)) {//将未出现的from放入点集合graph.nodes.put(from, new Node(from));}if (!graph.nodes.containsKey(to)) {//将未出现的to放入点集合graph.nodes.put(to, new Node(to));}Node fromNode = graph.nodes.get(from);//获取from点Node toNode = graph.nodes.get(to);//获取to点Edge newEdge = new Edge(weight, fromNode, toNode);//创建边fromNode.nexts.add(toNode);//from邻居fromNode.out++;//出度++toNode.in++;//入度++fromNode.edges.add(newEdge);//将边放到我所拥有的边集合里面graph.edges.add(newEdge);//放入边值}return graph;}}

图的遍历

宽度优先遍历

代码 

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;public class Code01_BFS {// 从node出发,进行宽度优先遍历public static void bfs(Node node) {if (node == null) {return;}Queue<Node> queue = new LinkedList<>();HashSet<Node> set = new HashSet<>();//防止数据重复queue.add(node);set.add(node);while (!queue.isEmpty()) {Node cur = queue.poll();System.out.println(cur.value);for (Node next : cur.nexts) {if (!set.contains(next)) {set.add(next);queue.add(next);}}}}}

深度优先遍历

代码

import java.util.HashSet;
import java.util.Stack;public class Code02_DFS {public static void dfs(Node node) {if (node == null) {return;}Stack<Node> stack = new Stack<>();//保证深度的路径HashSet<Node> set = new HashSet<>();stack.add(node);set.add(node);System.out.println(node.value);while (!stack.isEmpty()) {Node cur = stack.pop();for (Node next : cur.nexts) {if (!set.contains(next)) {stack.push(cur);stack.push(next);set.add(next);System.out.println(next.value);break;}}}}}

拓扑排序算法

  • 要求是有向图,入度为0的节点,且没有环

代码

package class06;import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;public class Code03_TopologySort {// directed graph and no looppublic static List<Node> sortedTopology(Graph graph) {// key:某一个node// value:剩余的入度HashMap<Node, Integer> inMap = new HashMap<>();// 入度为0的点,才能进这个队列Queue<Node> zeroInQueue = new LinkedList<>();for (Node node : graph.nodes.values()) {inMap.put(node, node.in);if (node.in == 0) {zeroInQueue.add(node);}}// 拓扑排序的结果,依次加入resultList<Node> result = new ArrayList<>();while (!zeroInQueue.isEmpty()) {Node cur = zeroInQueue.poll();result.add(cur);for (Node next : cur.nexts) {inMap.put(next, inMap.get(next) - 1);if (inMap.get(next) == 0) {zeroInQueue.add(next);}}}return result;}
}

Kruskal算法(并查集)

无向图

  • 加最小的边,只要不形成环,就加上,否则不加入

代码

package class06;import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.Stack;//undirected graph only
public class Code04_Kruskal {public static class MySets{public HashMap<Node, List<Node>>  setMap;public MySets(List<Node> nodes) {for(Node cur : nodes) {List<Node> set = new ArrayList<Node>();set.add(cur);setMap.put(cur, set);}}public boolean isSameSet(Node from, Node to) {//判断from和to是否在一个集合List<Node> fromSet  = setMap.get(from);List<Node> toSet = setMap.get(to);return fromSet == toSet;//内存地址}public void union(Node from, Node to) {//List<Node> fromSet  = setMap.get(from);List<Node> toSet = setMap.get(to);for(Node toNode : toSet) {fromSet.add(toNode);setMap.put(toNode, fromSet);}}}// Union-Find Setpublic static class UnionFind {// key 某一个节点, value key节点往上的节点private HashMap<Node, Node> fatherMap;// key 某一个集合的代表节点, value key所在集合的节点个数private HashMap<Node, Integer> sizeMap;public UnionFind() {fatherMap = new HashMap<Node, Node>();sizeMap = new HashMap<Node, Integer>();}public void makeSets(Collection<Node> nodes) {fatherMap.clear();sizeMap.clear();for (Node node : nodes) {fatherMap.put(node, node);sizeMap.put(node, 1);}}private Node findFather(Node n) {Stack<Node> path = new Stack<>();while(n != fatherMap.get(n)) {path.add(n);n = fatherMap.get(n);}while(!path.isEmpty()) {fatherMap.put(path.pop(), n);}return n;}public boolean isSameSet(Node a, Node b) {return findFather(a) == findFather(b);}public void union(Node a, Node b) {if (a == null || b == null) {return;}Node aDai = findFather(a);Node bDai = findFather(b);if (aDai != bDai) {int aSetSize = sizeMap.get(aDai);int bSetSize = sizeMap.get(bDai);if (aSetSize <= bSetSize) {fatherMap.put(aDai, bDai);sizeMap.put(bDai, aSetSize + bSetSize);sizeMap.remove(aDai);} else {fatherMap.put(bDai, aDai);sizeMap.put(aDai, aSetSize + bSetSize);sizeMap.remove(bDai);}}}}public static class EdgeComparator implements Comparator<Edge> {@Overridepublic int compare(Edge o1, Edge o2) {return o1.weight - o2.weight;}}public static Set<Edge> kruskalMST(Graph graph) {UnionFind unionFind = new UnionFind();unionFind.makeSets(graph.nodes.values());PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());for (Edge edge : graph.edges) { // M 条边priorityQueue.add(edge);  // O(logM)}Set<Edge> result = new HashSet<>();while (!priorityQueue.isEmpty()) { // M 条边Edge edge = priorityQueue.poll(); // O(logM)if (!unionFind.isSameSet(edge.from, edge.to)) { // O(1)result.add(edge);unionFind.union(edge.from, edge.to);}}return result;}
}

prim算法

无向图

代码

package class06;import java.util.Comparator;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.Set;// undirected graph only
public class Code05_Prim {public static class EdgeComparator implements Comparator<Edge> {@Overridepublic int compare(Edge o1, Edge o2) {return o1.weight - o2.weight;}}public static Set<Edge> primMST(Graph graph) {// 解锁的边进入小根堆PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());HashSet<Node> set = new HashSet<>();Set<Edge> result = new HashSet<>(); // 依次挑选的的边在result里for (Node node : graph.nodes.values()) { // 随便挑了一个点// node 是开始点if (!set.contains(node)) {set.add(node);for (Edge edge : node.edges) { // 由一个点,解锁所有相连的边priorityQueue.add(edge);}while (!priorityQueue.isEmpty()) {Edge edge = priorityQueue.poll(); // 弹出解锁的边中,最小的边Node toNode = edge.to; // 可能的一个新的点if (!set.contains(toNode)) { // 不含有的时候,就是新的点set.add(toNode);result.add(edge);for (Edge nextEdge : toNode.edges) {priorityQueue.add(nextEdge);}}}}//break;}return result;}// 请保证graph是连通图// graph[i][j]表示点i到点j的距离,如果是系统最大值代表无路// 返回值是最小连通图的路径之和public static int prim(int[][] graph) {int size = graph.length;int[] distances = new int[size];boolean[] visit = new boolean[size];visit[0] = true;for (int i = 0; i < size; i++) {distances[i] = graph[0][i];}int sum = 0;for (int i = 1; i < size; i++) {int minPath = Integer.MAX_VALUE;int minIndex = -1;for (int j = 0; j < size; j++) {if (!visit[j] && distances[j] < minPath) {minPath = distances[j];minIndex = j;}}if (minIndex == -1) {return sum;}visit[minIndex] = true;sum += minPath;for (int j = 0; j < size; j++) {if (!visit[j] && distances[j] > graph[minIndex][j]) {distances[j] = graph[minIndex][j];}}}return sum;}public static void main(String[] args) {System.out.println("hello world!");}}

 Dijkstra算法(单元最远路径算法)

  • 要求没有权值为负的边

代码

package class06;import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;// no negative weight
public class Code06_Dijkstra {public static HashMap<Node, Integer> dijkstra1(Node head) {// 从head出发到所有点的最小距离// key : 从head出发到达key// value : 从head出发到达key的最小距离// 如果在表中,没有T的记录,含义是从head出发到T这个点的距离为正无穷HashMap<Node, Integer> distanceMap = new HashMap<>();distanceMap.put(head, 0);// 已经求过距离的节点,存在selectedNodes中,以后再也不碰HashSet<Node> selectedNodes = new HashSet<>();Node minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes);while (minNode != null) {int distance = distanceMap.get(minNode);for (Edge edge : minNode.edges) {Node toNode = edge.to;if (!distanceMap.containsKey(toNode)) {distanceMap.put(toNode, distance + edge.weight);} else {distanceMap.put(edge.to, Math.min(distanceMap.get(toNode), distance + edge.weight));}}selectedNodes.add(minNode);minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes);}return distanceMap;}public static Node getMinDistanceAndUnselectedNode(HashMap<Node, Integer> distanceMap, HashSet<Node> touchedNodes) {Node minNode = null;int minDistance = Integer.MAX_VALUE;for (Entry<Node, Integer> entry : distanceMap.entrySet()) {Node node = entry.getKey();int distance = entry.getValue();if (!touchedNodes.contains(node) && distance < minDistance) {minNode = node;minDistance = distance;}}return minNode;}public static class NodeRecord {public Node node;public int distance;public NodeRecord(Node node, int distance) {this.node = node;this.distance = distance;}}public static class NodeHeap {private Node[] nodes; // 实际的堆结构// key 某一个node, value 上面数组中的位置private HashMap<Node, Integer> heapIndexMap;// key 某一个节点, value 从源节点出发到该节点的目前最小距离private HashMap<Node, Integer> distanceMap;private int size; // 堆上有多少个点public NodeHeap(int size) {nodes = new Node[size];heapIndexMap = new HashMap<>();distanceMap = new HashMap<>();size = 0;}public boolean isEmpty() {return size == 0;}// 有一个点叫node,现在发现了一个从源节点出发到达node的距离为distance// 判断要不要更新,如果需要的话,就更新public void addOrUpdateOrIgnore(Node node, int distance) {if (inHeap(node)) {distanceMap.put(node, Math.min(distanceMap.get(node), distance));insertHeapify(node, heapIndexMap.get(node));}if (!isEntered(node)) {nodes[size] = node;heapIndexMap.put(node, size);distanceMap.put(node, distance);insertHeapify(node, size++);}}public NodeRecord pop() {NodeRecord nodeRecord = new NodeRecord(nodes[0], distanceMap.get(nodes[0]));swap(0, size - 1);heapIndexMap.put(nodes[size - 1], -1);distanceMap.remove(nodes[size - 1]);// free C++同学还要把原本堆顶节点析构,对java同学不必nodes[size - 1] = null;heapify(0, --size);return nodeRecord;}private void insertHeapify(Node node, int index) {while (distanceMap.get(nodes[index]) < distanceMap.get(nodes[(index - 1) / 2])) {swap(index, (index - 1) / 2);index = (index - 1) / 2;}}private void heapify(int index, int size) {int left = index * 2 + 1;while (left < size) {int smallest = left + 1 < size && distanceMap.get(nodes[left + 1]) < distanceMap.get(nodes[left])? left + 1: left;smallest = distanceMap.get(nodes[smallest]) < distanceMap.get(nodes[index]) ? smallest : index;if (smallest == index) {break;}swap(smallest, index);index = smallest;left = index * 2 + 1;}}private boolean isEntered(Node node) {return heapIndexMap.containsKey(node);}private boolean inHeap(Node node) {return isEntered(node) && heapIndexMap.get(node) != -1;}private void swap(int index1, int index2) {heapIndexMap.put(nodes[index1], index2);heapIndexMap.put(nodes[index2], index1);Node tmp = nodes[index1];nodes[index1] = nodes[index2];nodes[index2] = tmp;}}// 改进后的dijkstra算法// 从head出发,所有head能到达的节点,生成到达每个节点的最小路径记录并返回public static HashMap<Node, Integer> dijkstra2(Node head, int size) {NodeHeap nodeHeap = new NodeHeap(size);nodeHeap.addOrUpdateOrIgnore(head, 0);HashMap<Node, Integer> result = new HashMap<>();while (!nodeHeap.isEmpty()) {NodeRecord record = nodeHeap.pop();Node cur = record.node;int distance = record.distance;for (Edge edge : cur.edges) {nodeHeap.addOrUpdateOrIgnore(edge.to, edge.weight + distance);}result.put(cur, distance);}return result;}}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/447202.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

超文本传输协议

超文本传输协议 超文本传输协议超文件传输协定(HTTP&#xff0c;HyperTextTransfer Protocol)是因特网上应用最为广泛的一种网络传输协定。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。 目录 介绍请求信息请求方法安全方法超…

利用MFC调用libvlc.dll作一个简单的播放器

简单介绍MFC调用libvlc.dll作一个简单的播放器&#xff0c;抛砖引玉&#xff0c;各位VC达人继续深入研究&#xff0c;Jeremiah对VC确实不太感兴趣&#xff0c;所以就不做太深入的研究了。2009.10.29修改&#xff1a;加入clip_children属性设置。参开第1步。环境&#xff1a; …

使用Remix编写Solidity语言的小例子

设置数值/取数值/加法运算 讲解 uint默认使用256位数的整型view表示这个函数仅仅对于数据仅仅是读取&#xff0c;没有修改操作returns(uint )&#xff0c;如果单纯指定uint&#xff0c;返回的是函数体内的return值&#xff0c;如果包含uint sum,uint SAD_a&#xff0c;那么返…

RTP协议栈简介

流媒体指的是在网络中使用流技术传输的连续时基媒体&#xff0c;其特点是在播放前不需要下载整个文件&#xff0c;而是采用边下载边播放的方式&#xff0c;它是视频会议、IP电话等应用场合的技术基础。RTP是进行实时流媒体传输的标准协议和关键技术&#xff0c;本文介绍如何在L…

使用多线程的方式调用chineseocr_API

ChineseOCR在线API 网页链接 界面 提供多种接口调用方式&#xff0c;比如在线调用、Javascript api调用、curl api调用和python api调用四种方式&#xff0c;本次使用javascript api调用的方式进行OCR识别代码 import glob import base64 import os import requests import …

开源好代码 音视频

VirtualDub 一、简介 图1VirtualDub主界面 VirtualDub是一款开源的音视频捕获、处理软件。VirtualDub也可称为一款多媒体编辑软件&#xff0c;因为它包含了多媒体输入、编辑、处理、输出等各个环节&#xff0c;但是作者并未将它定位为一款多媒体编辑软件&#xff08;参见官网&a…

深入理解Solidity 二

Solidity数据位置 所有复杂的数据类型&#xff0c;即数组、结构和映射类型&#xff0c;都会有一个额外属性“数据位置”&#xff0c;用来指定数据的存储位置&#xff0c;即数据是存储在memory还是存储在storage里面根据上下文环境&#xff0c;IDE会自动指定数据的默认存储位置…

VOIP简介

一、什么是VOIP VOIP全称为&#xff08;VoiceOver Internet Protocol&#xff09;&#xff0c;是一种利用Internet网络进行语音通信的技术&#xff0c;更通俗一点说&#xff0c;就是IP电话。就是以IP分组交换网为传输平台&#xff0c;对模拟的语音信号进行编码压缩&#xff0c…

深入理解Solidity 三

Solidity函数声明和类型 函数的值类型有两类&#xff1a;内部&#xff08;internal&#xff09;类型和外部&#xff08;external&#xff09;类型内部函数只可以在当前合约内部被调用&#xff08;即在当前代码块内&#xff0c;包括内部库函数和继承函数&#xff09;&#xff0c…

安装solc模块4.25版本

使用国产阿里云的cnpm 如果不知道cnpm 参考链接 安装solc模块4.25版本 npm i solc0.4.25 --save -g查看安装是否成功 可以配置软连接使用solc&#xff0c;我的没有配置 solcjs --version

在pycharm中使用conda虚拟环境(conda虚拟环境是已经创建好的),解决python安装包文件很费劲的问题

查看conda的虚拟环境 使用PyCharm连接conda创建的虚拟环境&#xff0c;需要一个前提就是虚拟环境必须存在&#xff0c;使用conda env list命令查看虚拟环境列表打开PyCharm软件 打开pycharm&#xff0c;选择File->setting->Project:****->Project Interperter&#…

完成一个H.265/HEVC码流分析工具

经过大约一个月左右的业余时间&#xff0c;终于初步完成一个H.265/HEVC码流分析工具。时间包括平时的周末、晚上&#xff0c;以及调休的集中时间。当然&#xff0c;中秋回家过节不写代码。截至今天&#xff0c;经过多种H.265序列测试&#xff0c;也有各种工具对比&#xff0c;基…

Golomb及指数哥伦布编码原理介绍及实现

文章来源&#xff1a; https://www.cnblogs.com/wangguchangqing/p/6297792.html &#xff0c; 写的不错&#xff0c;转发出来。 2017年的第一篇博文。 本文主要有以下三部分内容&#xff1a; 介绍了Golomb编码&#xff0c;及其两个变种&#xff1a;Golomb-Rice和Exp-Golo…

解决ipfs 出现Error: can‘t publish while offline: pass `--allow-offline` to override的问题

原因 出现这个问题的原因是因为&#xff0c;ipfs未与公网上的节点相互连接&#xff0c;因此此时处于离线状态 使用场景 部署自己的博客&#xff0c;后期的改动&#xff0c;累计追加在同一个地址&#xff0c;这个地址是唯一的&#xff0c;也就是创建ipfs生成的ID号 步骤 1&…

安装ipfs-http-client出现constants@0.1.2 install: node build.js > index.browser.js错误的解决办法

错误截图 原先的命令 npm install --save-dev ipfs-http-client 修改后的命令 npm install --save-dev ipfs-http-client --unsafe-permtrue --allow-root

安装ipfs-api的命令变了,最新版的命令如下

原先使用的命令安装ipfs-api npm install --save-dev ipfs-api 现在使用的命令安装ipfs-api npm install --save-dev ipfs-http-client 官方文档 参考教程 官方文档

区块链相关问题 理解

本博客针对区块链的部分问题进行详解&#xff0c;希望帮助大家对于区块链有一个更好的理解 1&#xff0c;如果散布虚假交易&#xff0c;怎么整&#xff1f;&#xff08;谁欠我XXX比特币&#xff09; 1&#xff0c;可以发起虚假交易&#xff0c;但是很难被全网的节点接收并写入…

区块链的相关知识点

1&#xff0c;密码学原理 密码学原理 1&#xff0c;collision resistance 哈希函数 &#xff0c;目前还是很安全的&#xff0c;没有找到任何不同的内容其哈希是一致的情形。哈希碰撞&#xff08;这个在数学上面是没法证明的&#xff0c;都是日常的实践表明&#xff0c;无法找…

使用MAC 编译合约的时候报错:

编译报错的显示内容如下&#xff1a; Error: EACCES: permission denied, mkdir /Users/chy/Documents/ipfslearn/ipfs_eth_img/client/src/contracts 最简单的解决方法 原因分析&#xff1a;执行的权限不够 解决办法&#xff1a;升级权限 使用命令 chmod 777 项目的文件夹使…

最新,使用truffle框架之后,安装ipfs的api包文件的命令变化

原因 项目文件路径变化了&#xff0c;不是先前直接在项目文件夹里面直接执行安装ipfs的命令了&#xff0c;需要切换到client文件夹下面执行 路径不对&#xff0c;会出现错误&#xff0c;错误提示如下 切换到正确的路径之后&#xff0c;使用命令 npm install --save ipfs-http-…