【数据结构与算法】图遍历算法 ( 深度优先搜索代码示例 )

news2024/11/25 4:48:56

文章目录

  • 一、深度优先搜索算法
  • 二、完整代码示例
    • 完整代码示例
    • 执行结果





一、深度优先搜索算法



深度优先搜索算法步骤 : 将 深度优先搜索 算法步骤 转为代码 ;

  • ① 访问初始结点 : 访问 初始结点 v , 并将该 初始结点 v 标记为 " 已访问 " ; 设置一个 访问标记 数组 , 数组元素个数与 顶点个数相同 ;
	/**
	 * 判定顶点是否被访问
	 */
	private boolean[] isVisted;
  • ② 查找邻接节点 : 查找 初始结点 v 的 第一个 邻接节点 w ;
    /**
     * 获取结点的第一个邻接结点
     * @param index
     * @return 如果存在 邻接结点 返回对应下标 , 如果不存在返回 -1
     */
    public int getFirstNeighbor(int index) {
        for (int i = 0; i < vertexList.size(); i++) {
            if (edges[index][i] > 0) {
                return i;
            }
        }
        return -1;
    }
  • ③ 邻接节点是否存在 :
    • 如果 w 结点存在 , 执行 ④ 操作 判断该 结点 是否被访问 ;
    • 如果 w 结点 不存在 , 回到 ① 查找 初始结点 v 的下一个 邻接节点 ;
    /**
     * 已知 v1 结点有一个邻接结点 v2, 找到 v2 之后的下一个 v1 的邻接结点
     * @param v1
     * @param v2
     * @return 如果找到邻接结点 返回其索引 , 反之返回 -1
     */
    public int getNextNeighbor(int v1, int v2) {
        for (int i = v2 + 1; i < vertexList.size(); i++) {
            if (edges[v1][i] > 0) {
                return i;
            }
        }
        return -1;
    }
  • ④ 邻接节点是否被访问 :
    • 如果 w 结点存在 并且 没有被访问 , 那么 对 w 结点 进行 深度优先遍历 , 将 w 结点 作为 新的 初始结点 v , 从 ① 步骤开始执行 ;
    • 如果 w 结点存在 但是 被访问了 , 那么 查找 w 结点的 下一个 邻接节点 , 转到步骤 ③ 执行 ;
    /**
     * 递归核心函数, 给定一个初始结点, 找到其第一个邻接结点, 如果该邻接结点没有被访问,
     * 将新结点作为 初始结点 , 进行递归遍历
     * @param isVisted
     * @param i
     */
    public void dfs(boolean[] isVisted, int i) {
        // 访问初始结点
        System.out.println("Visit Vertex : " + getVertexByIndex(i));
        // 设置 i 结点已访问
        isVisted[i] = true;
        // 查找 i 结点的第一个邻接结点 w
        int w = getFirstNeighbor(i);
        // 如果不存在 第一个邻接结点 则返回 -1
        // 如果存在 , 返回 该结点 索引
        while (w != -1) {
            // 确保找到的 第一个 邻接结点 没有访问过
            if (!isVisted[w]) {
                // 以 w 为初始结点 , 进行递归
                dfs(isVisted, w);
            }
            // 如果 第一个 邻接结点 已访问
            // 那么找到 i 作为初始结点 , w 作为 第一个邻接结点 , 之后的 第二个邻接结点
            w = getNextNeighbor(i, w);
        }
    }

遍历的入口函数 : 一般情况下只需要一个结点 , 就可以将所有的结点遍历完毕 ;

    /**
     * 遍历入口函数
     */
    public void dfs() {
        for (int i = 0; i < getNumberOfVertex(); i++) {
            if (!isVisted[i]) {
                dfs(isVisted, i);
            }
        }
    }




二、完整代码示例



完整代码示例

import java.util.ArrayList;
import java.util.Arrays;

public class Graph {

    /**
     * 图顶点
     */
    private ArrayList<String> vertexList;

    /**
     * 图的邻接矩阵
     */
    private int[][] edges;

    /**
     * 图中边的数据
     */
    private int numOfEdges;

    /**
     * 判定顶点是否被访问
     */
    private boolean[] isVisted;

    /**
     *  构造器
     * @param n 顶点个数
     */
    public Graph(int n) {
        // 创建 n x n 邻接矩阵
        edges = new int[n][n];
        // 初始化顶点容器
        vertexList = new ArrayList<>(n);
        // 边数量统计
        numOfEdges = 0;
        // 顶点是否被访问标志位
        isVisted = new boolean[n];
    }

    /**
     * 插入顶点
     * @param vertex 顶点名称
     */
    public void insertVertex(String vertex) {
        vertexList.add(vertex);
    }

    /**
     * 插入边
     * @param v1 起始顶点索引
     * @param v2 终止顶点索引
     * @param weight 顶点的权重
     */
    public void insertEdge(int v1, int v2, int weight) {
        edges[v1][v2] = weight;
        edges[v2][v1] = weight;

        // 边的数量增加 1
        numOfEdges++;
    }

    /**
     * 获取结点个数
     * @return
     */
    public int getNumberOfVertex() {
        return vertexList.size();
    }

    /**
     * 获取边的个数
     * @return
     */
    public int getNumberOfEdges() {
        return numOfEdges;
    }

    /**
     * 获取指定节点的索引值
     * @param i
     * @return
     */
    public String getVertexByIndex(int i) {
        return vertexList.get(i);
    }

    /**
     * 获取 v1 到 v2 的权值
     * @param v1
     * @param v2
     * @return
     */
    public int getWeight(int v1, int v2) {
        return edges[v1][v2];
    }

    /**
     * 打印邻接矩阵
     */
    public void showGraph() {
        for (int i = 0; i < edges.length; i++) {
            System.out.println(Arrays.toString(edges[i]));
        }
    }

    /**
     * 获取结点的第一个邻接结点
     * @param index
     * @return 如果存在 邻接结点 返回对应下标 , 如果不存在返回 -1
     */
    public int getFirstNeighbor(int index) {
        for (int i = 0; i < vertexList.size(); i++) {
            if (edges[index][i] > 0) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 已知 v1 结点有一个邻接结点 v2, 找到 v2 之后的下一个 v1 的邻接结点
     * @param v1
     * @param v2
     * @return 如果找到邻接结点 返回其索引 , 反之返回 -1
     */
    public int getNextNeighbor(int v1, int v2) {
        for (int i = v2 + 1; i < vertexList.size(); i++) {
            if (edges[v1][i] > 0) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 递归核心函数, 给定一个初始结点, 找到其第一个邻接结点, 如果该邻接结点没有被访问,
     * 将新结点作为 初始结点 , 进行递归遍历
     * @param isVisted
     * @param i
     */
    public void dfs(boolean[] isVisted, int i) {
        // 访问初始结点
        System.out.println("Visit Vertex : " + getVertexByIndex(i));
        // 设置 i 结点已访问
        isVisted[i] = true;
        // 查找 i 结点的第一个邻接结点 w
        int w = getFirstNeighbor(i);
        // 如果不存在 第一个邻接结点 则返回 -1
        // 如果存在 , 返回 该结点 索引
        while (w != -1) {
            // 确保找到的 第一个 邻接结点 没有访问过
            if (!isVisted[w]) {
                // 以 w 为初始结点 , 进行递归
                dfs(isVisted, w);
            }
            // 如果 第一个 邻接结点 已访问
            // 那么找到 i 作为初始结点 , w 作为 第一个邻接结点 , 之后的 第二个邻接结点
            w = getNextNeighbor(i, w);
        }
    }

    /**
     * 遍历入口函数
     */
    public void dfs() {
        for (int i = 0; i < getNumberOfVertex(); i++) {
            if (!isVisted[i]) {
                dfs(isVisted, i);
            }
        }
    }

    public static void main(String[] args) {
        // 创建图
        Graph graph = new Graph(5);

        // 添加顶点
        graph.insertVertex("A");
        graph.insertVertex("B");
        graph.insertVertex("C");
        graph.insertVertex("D");
        graph.insertVertex("E");

        // 添加边
        graph.insertEdge(0, 1, 1);  // AB
        graph.insertEdge(0, 2, 1);  // AC

        graph.insertEdge(1, 0, 1);  // BA
        graph.insertEdge(1, 2, 1);  // BC
        graph.insertEdge(1, 3, 1);  // BD
        graph.insertEdge(1, 4, 1);  // BE

        graph.insertEdge(2, 1, 1);  // CA
        graph.insertEdge(2, 2, 1);  // CB

        graph.insertEdge(3, 1, 1);  // DB

        graph.insertEdge(4, 1, 1);  // EB

        // 打印临街矩阵
        graph.showGraph();

        // 深度优先搜索遍历
        graph.dfs();
    }
}

执行结果

> Task :Graph.main()
[0, 1, 1, 0, 0]
[1, 0, 1, 1, 1]
[1, 1, 1, 0, 0]
[0, 1, 0, 0, 0]
[0, 1, 0, 0, 0]
Visit Vertex : A
Visit Vertex : B
Visit Vertex : C
Visit Vertex : D
Visit Vertex : E

在这里插入图片描述

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

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

相关文章

《C++ Primer》 第九章 顺序容器

《C Primer》 第九章 顺序容器 9.1 顺序容器概述 容器&#xff1a;特定类型对象的集合 顺序容器类型 vector 可变大小数组&#xff0c;支持快速随机访问&#xff0c;在尾部之外的位置插入或删除元素可能很慢deque 双端队列。支持快速随机访问。在头尾位置插入/删除速度很快…

【2022-09-14】米哈游秋招笔试三道编程题

第一题&#xff1a;最短子串 题目描述 米小游拿到了一个字符串&#xff0c;她想截取一个连续子串&#xff0c;使得该子串中包含至少k个连续的“mihoyo”。 你可以帮米小游求出最短的子串长度&#xff0c;以及对应的子串位置吗&#xff1f; 输入描述 第一行输入两个正整数n…

产品父子流程技术方案设计

产品父子流程技术方案设计 一、整体设计 根据业务需求分析&#xff0c;产品涉及法人代表及实控人风控决策流程调用&#xff0c;旨在降低风险&#xff0c;提高行内线上贷款业务风险决策的能力。 二、业务流程 1.业务流程图 2.交易流程 在授信交易切面入口处对法人代表及实控…

Spark性能优化三 checkpoint

&#xff08;一&#xff09;checkpoint介绍 checkpoint&#xff0c;是Spark提供的一个比较高级的功能。有时候&#xff0c;我们的Spark任务&#xff0c;比较复杂&#xff0c;从初始化RDD开始&#xff0c;到最后整个任务完成&#xff0c;有比较多的步骤&#xff0c;比如超过10个…

关于flex盒子padding-right/margin-right不生效

错误代码实例&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"width…

论文投稿指南——中文核心期刊推荐(科学、科学研究)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

element input 输入框校验

element input 输入框校验 很久之前有写过一篇&#xff1a;element 输入框只可以输入正整数 在这里对它进行补充 校验input输入框是否符合 以下是常用的一些&#xff1a; 限制输入中文&#xff1a;/^[\u4e00-\u9fa5]$/ const checkName (rule, value, callback) > {if…

逆约瑟夫问题

约瑟夫问题可以说十分经典&#xff0c;其没有公式解也是广为人知的~ 目录 前言 一、约瑟夫问题与逆约瑟夫问题 1.约瑟夫问题 2.逆约瑟夫问题 二、思考与尝试&#xff08;显然有很多失败&#xff09; 问题分析 尝试一&#xff1a;递归/递推的尝试 尝试二&#xff1a;条件…

Doris入门篇-分区分桶实验

简介 测试分区分桶效果。 分区的基本操作 添加分区 ALTER TABLE v2x_olap_database.government_car ADD PARTITION p20221203 VALUES LESS THAN ("2022-12-04");动态分区表不能添加分区&#xff0c;需要转为手动分区表。 查看分区 show partitions from <表…

【深度估计】单目深度估计

文章目录什么是深度估计&#xff1f;什么是视差深度估计与三维重建单目深度估计研究历程单目深度估计方法传统方法基于线索线性透视聚焦/散焦度天气散射阴影纹理遮挡高度运动线索基于物体自身运动基于摄像机的运动基于机器学习参数学习方法开创性工作改进加入语义信息条件随机场…

《工业机器视觉检测123》(1.1) 目标检测样本类别不平衡的问题(持续更新...)

部分内容转载自&#xff1a;https://www.cnblogs.com/inchbyinch/p/12642760.html 参考分类任务中解决类别不平衡的办法&#xff1a; 1 什么是类别不平衡问题&#xff1f; 类别不平衡&#xff08;class-imbalance&#xff09;&#xff0c;也叫数据倾斜&#xff0c;数据不平衡…

Tomcat面试问题总结

1.Tomcat是什么&#xff1f;Tomcat 服务器Apache软件基金会项目中的一个核心项目&#xff0c;是一个免费的开放源代码的Web 应用服务器&#xff0c;属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发和调试JSP 程序的首…

EasyCVR视频融合平台的视频处理与AI智能分析流程实操案例介绍

EasyCVR基于云边端一体化架构&#xff0c;能支持海量视频的轻量化接入与汇聚管理。在视频能力上&#xff0c;可提供视频监控直播、视频轮播、视频录像、云存储、回放与检索、智能告警、服务器集群、语音对讲、云台控制、电子地图、平台级联等。 除了视频能力之外&#xff0c;将…

浅谈设备防漏扫

场景描述 随着社会的信息化&#xff0c;互联网安全被国家越来越重视&#xff0c;漏洞扫描&#xff08;简称漏扫&#xff09;业务也在被规范列入企事业单位的信息安全的标准中。 从安全角度来看&#xff0c;漏扫本身是为用户的用网安全做保障&#xff0c;避免木马、病毒等通过…

vue中点击空白处改变dom状态实现显隐,监听dom(addEventListener)

需求来源&#xff1a;点击铃铛之后弹出右侧抽屉&#xff0c;实现文件下载 现在是点击小铃铛出现弹框没问题&#xff0c;点击关闭图标关闭弹框也没问题&#xff0c;但是点击空白区域消失不了&#xff0c;这个时候需要dom监听属性document.addEventListener来实现需求了 主要是用…

c++学习笔记之基础

目录前言零碎知识点C核心内存分区引用函数类和对象对象的初始化和清理构造函数和析构函数构造函数的分类和调用拷贝构造函数的调用时机深拷贝与浅拷贝初始化列表类对象作为类的成员静态成员C对象模型和this指针成员变量和成员函数分开存储this指针空指针访问成员函数const修饰成…

IDEA2022 配置spark开发环境

本人强烈建议在 linux环境下 学习 spark&#xff01;&#xff01;&#xff01; Introduction Apache Spark是一个快速且通用的分布式计算引擎&#xff0c;可以在大规模数据集上进行高效的数据处理&#xff0c;包括数据转换、数据清洗、机器学习等。在本文中&#xff0c;我们将…

NDK C++ map容器

map容器// TODO map容器 #include <iostream> #include <map>using namespace std;int main() {// TODO map<int, string>按key值排序&#xff0c;同一个key不可以重复插入map<int, string> map1;map1.insert(pair<int, string>(1, "111&qu…

ChatGPT没有API?OpenAI官方API带你起飞

目录ChatGPT没有API&#xff1f;OpenAI官方API带你起飞安装 OpenAI 的 API 库包装个函数包装个UIChatGPT没有API&#xff1f;OpenAI官方API带你起飞 前段时间ChatGPT爆火&#xff0c;OpenAI 的 GPT API也被大家疯狂调用&#xff0c; 但其实这个API是基于GPT3的&#xff0c;和基…

【RabbitMQ】Producer之mandatory、alternative exchange、TTL - 基于AMQP 0-9-1(一)

RabbitMQ系列文章&#xff0c;前几篇介绍了基础概念&#xff0c;AMQP 0-9-1 协议&#xff0c;和服务端安装&#xff0c;准备工作都完成后&#xff0c;就开始着手开发了。这篇文章主要介绍RabbitMQ生产者的开发&#xff0c;包括Producer、Message常见的参数&#xff0c;读完这篇…