通过深度优先算法来找出有向图的树边,后向边,前向边,横跨边

2023-12-06 07:08

本文主要是介绍通过深度优先算法来找出有向图的树边,后向边,前向边,横跨边,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

**通过深度优先算法来找出有向图的树边,后向边,前向边,横跨边(Java实现)

**

package graph;import java.io.IOException;
import java.util.Scanner;public class ListCycle 
{private class ENode {int ivex;       // 该边所指向的顶点的位置ENode nextEdge; // 指向下一条弧的指针}// 邻接表中表的顶点private class VNode {int color;//顶点颜色;int d;//初始时间戳;int f;//结束时间戳;char data;          // 顶点信息ENode firstEdge;    // 指向第一条依附该顶点的弧VNode pre;};int time;private VNode[] mVexs;  // 顶点数组/* * 创建图(自己输入数据)*/public ListCycle() {// 输入"顶点数"和"边数"System.out.printf("input vertex number: ");int vlen = readInt();System.out.printf("input edge number: ");int elen = readInt();if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {System.out.printf("input error: invalid parameters!\n");return ;}// 初始化"顶点"mVexs = new VNode[vlen];for (int i = 0; i < mVexs.length; i++) {System.out.printf("vertex(%d): ", i);mVexs[i] = new VNode();mVexs[i].data = readChar();mVexs[i].firstEdge = null;}// 初始化"边"//mMatrix = new int[vlen][vlen];for (int i = 0; i < elen; i++) {// 读取边的起始顶点和结束顶点System.out.printf("edge(%d):", i);char c1 = readChar();char c2 = readChar();int p1 = getPosition(c1);int p2 = getPosition(c2);// 初始化node1ENode node1 = new ENode();node1.ivex = p2;// 将node1链接到"p1所在链表的末尾"if(mVexs[p1].firstEdge == null)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);}}/** 创建图(用已提供的矩阵)** 参数说明:*     vexs  -- 顶点数组*     edges -- 边数组*/public ListCycle(char[] vexs, char[][] edges) {// 初始化"顶点数"和"边数"int vlen = vexs.length;int elen = edges.length;// 初始化"顶点"mVexs = new VNode[vlen];for (int i = 0; i < mVexs.length; i++) {mVexs[i] = new VNode();mVexs[i].data = vexs[i];mVexs[i].firstEdge = null;}// 初始化"边"for (int i = 0; i < elen; i++) {// 读取边的起始顶点和结束顶点char c1 = edges[i][0];char c2 = edges[i][1];// 读取边的起始顶点和结束顶点int p1 = getPosition(edges[i][0]);int p2 = getPosition(edges[i][1]);// 初始化node1ENode node1 = new ENode();node1.ivex = p2;// 将node1链接到"p1所在链表的末尾"if(mVexs[p1].firstEdge == null)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);}}/** 将node节点链接到list的最后*/private void linkLast(ENode list, ENode node) {ENode p = list;while(p.nextEdge!=null)p = p.nextEdge;p.nextEdge = node;}/** 返回ch位置*/private int getPosition(char ch) {for(int i=0; i<mVexs.length; i++)if(mVexs[i].data==ch)return i;return -1;}/** 读取一个输入字符*/private char readChar() {char ch='0';do {try {ch = (char)System.in.read();} catch (IOException e) {e.printStackTrace();}} while(!((ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z')));return ch;}/** 读取一个输入字符*/private int readInt() {Scanner scanner = new Scanner(System.in);return scanner.nextInt();}/** 深度优先搜索遍历图的递归实现*/private void DFS_visit(int i, boolean[] visited) {ENode node;//time= time+1;mVexs[i].d = ++time;mVexs[i].color=0;//1表示该节点颜色为灰色visited[i] = true;//System.out.printf("%c(%d) ", mVexs[i].data,mVexs[i].d);//颜色node = mVexs[i].firstEdge;while (node != null) {if (mVexs[node.ivex].color == -1) {System.out.println("("+i+","+node.ivex+")---树边");DFS_visit(node.ivex, visited);  }else if(mVexs[node.ivex].color == 0){System.out.println("("+i+","+node.ivex+")---后向边");}else{if(mVexs[i].color < mVexs[node.ivex].d)System.out.println("("+i+","+node.ivex+")---前向边");else if(mVexs[i].color > mVexs[node.ivex].d)System.out.println("("+i+","+node.ivex+")---横跨边");}     node = node.nextEdge;}mVexs[i].color=1;//time=time+1;mVexs[i].f = ++time;//System.out.printf("%c(%d) ", mVexs[i].data,mVexs[i].f);}/** 深度优先搜索遍历图*/public void DFS() {time = 0;boolean[] visited = new boolean[mVexs.length];       // 顶点访问标记// 初始化所有顶点都没有被访问for ( int i = 0; i <mVexs.length; i++){mVexs[i].color = -1;//初始化所有顶点都为白色mVexs[i].pre=null;visited[i] = false;}// System.out.printf("DFS: ");for (int j= 0; j < mVexs.length; j++) {if (!visited[j])DFS_visit(j, visited);}System.out.printf("\n");}/** 打印矩阵队列图*/public void print() {System.out.printf("List Graph:\n");for (int i = 0; i < mVexs.length; i++) {System.out.printf("%d(%c): ", i, mVexs[i].data);ENode node = mVexs[i].firstEdge;while (node != null) {System.out.printf("%d(%c) ", node.ivex, mVexs[node.ivex].data);node = node.nextEdge;}System.out.printf("\n");}}public static void main(String[] args) {char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};char[][] edges = new char[][]{{'A', 'B'}, {'B', 'C'}, {'B', 'E'}, {'B', 'F'}, {'C', 'E'}, {'D', 'C'}, {'E', 'B'}, {'E', 'D'}, {'F', 'G'}}; ListCycle pG;// 自定义"图"(输入矩阵队列)//pG = new ListDG();// 采用已有的"图"pG = new ListCycle(vexs, edges);pG.print();   // 打印图pG.DFS();     // 深度优先遍}}

这篇关于通过深度优先算法来找出有向图的树边,后向边,前向边,横跨边的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/460891

相关文章

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

深度解析Python中递归下降解析器的原理与实现

《深度解析Python中递归下降解析器的原理与实现》在编译器设计、配置文件处理和数据转换领域,递归下降解析器是最常用且最直观的解析技术,本文将详细介绍递归下降解析器的原理与实现,感兴趣的小伙伴可以跟随... 目录引言:解析器的核心价值一、递归下降解析器基础1.1 核心概念解析1.2 基本架构二、简单算术表达

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

Java MCP 的鉴权深度解析

《JavaMCP的鉴权深度解析》文章介绍JavaMCP鉴权的实现方式,指出客户端可通过queryString、header或env传递鉴权信息,服务器端支持工具单独鉴权、过滤器集中鉴权及启动时鉴权... 目录一、MCP Client 侧(负责传递,比较简单)(1)常见的 mcpServers json 配置

Maven中生命周期深度解析与实战指南

《Maven中生命周期深度解析与实战指南》这篇文章主要为大家详细介绍了Maven生命周期实战指南,包含核心概念、阶段详解、SpringBoot特化场景及企业级实践建议,希望对大家有一定的帮助... 目录一、Maven 生命周期哲学二、default生命周期核心阶段详解(高频使用)三、clean生命周期核心阶

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”