首页 > 编程语言 >数据结构与算法-图

数据结构与算法-图

时间:2024-03-17 20:58:51浏览次数:18  
标签:return int public 算法 vertexList 数据结构 节点 isVisited

引言

        在计算机科学领域,数据结构和算法是程序员工具箱中的两大瑰宝。其中,图(Graph) 是一种极其重要的非线性数据结构,它以节点和边的概念描述实体间复杂的关系网络。本文将对图的数据结构进行详尽解析,探讨其基本概念、操作以及实际应用场景。

一、什么是图?

        图 是由一组顶点(或称为节点)以及连接这些顶点的边构成的抽象数据类型。根据边的特性,图可以进一步分为无向图和有向图:

  • 无向图 中每条边没有方向,表示两个顶点之间的关系是对称的。
  • 有向图 中的边具有方向性,从一个顶点指向另一个顶点,表示单向依赖或流向关系。

此外,根据边是否有权重,又可将图划分为带权图和无权图。

二、图的基本操作

  1. 创建图:初始化图结构,包括创建空图、添加顶点和边等操作。
  2. 遍历图:主要有深度优先搜索(DFS)、广度优先搜索(BFS)两种方式,用于访问图中所有顶点或寻找特定路径。
  3. 查找路径:如Dijkstra算法求最短路径,Floyd-Warshall算法求任意两点间的最短路径,A*搜索算法在启发式指导下寻找最优路径等。
  4. 判断连通性:检查图中是否存在从一个顶点到另一个顶点的路径。
  5. 拓扑排序:对于有向无环图(DAG),按依赖关系进行排序。

三、图的应用场景

  1. 社交网络:用户之间的好友关系、关注关系可以用图来建模,便于进行好友推荐、社区发现等任务。
  2. 交通网络:地图上的道路系统、城市间航班或铁路线路可用图表示,方便计算最佳出行路线。
  3. 网页链接结构:互联网上的网页通过超链接形成巨大的有向图,搜索引擎正是利用此结构进行网页抓取和排名计算(PageRank算法)。
  4. 电路设计:电路中的各个元件及其连接关系可以通过图来描绘,辅助分析电路功能及故障排查。
  5. 生物信息学:基因调控网络、蛋白质相互作用网络等复杂生物学系统也可用图来刻画。

四、图算法的实际应用案例

  • Google PageRank:使用有向有权图模型量化网页的重要性,并据此优化搜索结果排序。
  • Facebook的朋友推荐系统:基于社交网络图构建算法,实现朋友推荐功能。
  • GPS导航系统:采用图数据结构处理地理信息,实时规划出最优行驶路径。

五、图的代码实践   

1.创建图(邻接矩阵)

 

public class Graph {

    private ArrayList<String> vertexList;   //存储定点的集合
    private int[][] edges;     //存储图对应的领接矩阵
    private int numOfEdges;    //边的数目

    public static void main(String[] args) {
        int n = 5;
        String[] vertexs = {"A", "B", "C", "D", "E"};
        Graph graph = new Graph(n);
        for (String vertex : vertexs) {
            graph.addVertex(vertex);
        }
        graph.addEdge(0, 1, 1);
        graph.addEdge(0, 2, 1);
        graph.addEdge(1, 2, 1);
        graph.addEdge(1, 3, 1);
        graph.addEdge(1, 4, 1);

        graph.show();
    }

    public Graph(int n) {
        edges = new int[n][n];
        vertexList = new ArrayList<String>(n);
        numOfEdges = 0;
    }

    //    添加定点
    public void addVertex(String vertex) {
        vertexList.add(vertex);
    }

    //    返回下标对应数据
    public String getValueByIndex(int i) {
        return vertexList.get(i);
    }

    //    返回下标对应数据
    public String getValueByIndex(int i) {
        return vertexList.get(i);
    }

//    添加边

    /**
     * @param v1     顶点的下标
     * @param v2     顶点的下标
     * @param weight 权值
     */
    public void addEdge(int v1, int v2, int weight) {
        edges[v1][v2] = weight;
        edges[v2][v1] = weight;
        numOfEdges++;
    }

    //    得到边的数目
    public int getNumOfEdges() {
        return numOfEdges;
    }

    //    得到边的权值
    public int getWeight(int v1, int v2) {
        return edges[v1][v2];
    }

    //    展示图的邻接矩阵
    public void show() {
        for (int[] edge : edges) {
            System.out.println(Arrays.toString(edge));
        }
    }
}

2.图的邻接矩阵结果 

3.图的深度优先遍历 

思路:

1.访问初始节点v,并标记节点v已访问

2.查找节点v的第一个邻接节点w

3.若w存在,则继续执行4,若其不存在,则回到1,将从v的下一个节点继续

4.若w未被访问,对w进行深度优先遍历递归(即把w当做另一个v,然后进行123)

5.查找节点v的w邻接节点的下一个邻接节点,在进行步骤3

代码 

1,辅助方法
    //    得到第一个邻接节点的下标w

    /**
     * @param index
     * @return 如果存在返回对应下标,否则-1
     */
    public int getFirstNeighbor(int index) {
        for (int j = 0; j < vertexList.size(); j++) {
            if (edges[index][j] > 0) {
                return j;
            }
        }
        return -1;
    }

    //    根据前一个邻接接节点的下标获取下一个邻接节点
    public int getNextNeighbor(int v1, int v2) {
        for (int j = v2 + 1; j < vertexList.size(); j++) {
            if (edges[v1][j] > 0) {
                return j;
            }
        }
        return -1;
    }
2.dfs算法
    //    深度优先遍历算法
    private void dfs(boolean[] isVisited, int i) {
//        首先访问该节点
        System.out.print(getValueByIndex(i) + "->");
//        访问了给他设置访问
        isVisited[i] = true;
//        查找i节点第一个邻接节点w
        int w = getFirstNeighbor(i);
        while (w != -1) {
            if (!isVisited[w]) {
                dfs(isVisited, w);
            }
//            如果w已经被访问
            w = getNextNeighbor(i, w);
        }
    }

    //    对dfs进行一个重载遍历所有的节点
    public void dfs() {
        isVisited = new boolean[5];
        for (int i = 0; i < vertexList.size(); i++) {
            if (!isVisited[i]) {
                dfs(isVisited, i);
            }
        }
    }

4.图的广度优先

思路:

1.访问初始节点v,并标记节点v已访问

2.节点v入队列

3.当队列非空时,继续执行,否则算法结束

4.出队列,取得队列头结点u

5.查找节点u的第一个邻接节点w

6.若w不存在,则进行步骤3,否则循环执行下三个步骤

        6.1若w未被访问,则访问节点w并标记已访问

        6.2节点w入队列

        6.3查找u的继w邻接节点后的下一个邻接节点w,再进行步骤6

代码 

1.bfs算法
//    对一个节点进行广度优先遍历
    public void bfs(boolean[] isVisited, int i) {
        int u; //表示队列的头结点对应的下标
        int w; //邻接节点
//        队列,记录节点访问的顺序
        LinkedList queue = new LinkedList();
        System.out.print(getValueByIndex(i) + "->");
        isVisited[i] = true;
        queue.addLast(i);
        while (!queue.isEmpty()) {
            u = (Integer)queue.removeFirst();
            w = getFirstNeighbor(u);
            while (w != -1) {
                if (!isVisited[w]) {
                    System.out.print(getValueByIndex(w) + "->");
                    isVisited[w] = true;
                    queue.addLast(w);
                }
                w = getNextNeighbor(u, w);
            }
        }
    }

//    遍历所有的节点广度优先
    public void bfs() {
        isVisited = new boolean[5];
        for (int i = 0; i < vertexList.size(); i++) {
            if (!isVisited[i]) {
                bfs(isVisited, i);
            }
        }
    }

5.dfs和bfs代码运行结果

六、总结 

        图作为复杂网络关系的有效模型,在现代计算机科学中扮演着至关重要的角色。理解并熟练掌握图相关的数据结构与算法,不仅能帮助我们解决众多实际问题,更能提升我们在复杂系统分析和设计方面的综合能力。无论是理论研究还是软件开发实践,图都是每一位计算机科学家和技术开发者必须掌握的核心知识点。

 

标签:return,int,public,算法,vertexList,数据结构,节点,isVisited
From: https://blog.csdn.net/m0_62988332/article/details/136661982

相关文章

  • 中国大学MOOC-陈越、何钦铭-数据结构-起步能力自测题
    自测-1打印沙漏本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印*****************所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相......
  • 算法练习第二十四天|77. 组合
    组合classSolution{List<List<Integer>>result=newArrayList();List<Integer>path=newArrayList();publicList<List<Integer>>combine(intn,intk){backtrace(n,k,1);returnresult;}......
  • 机器人路径规划:基于迪杰斯特拉算法(Dijkstra)的机器人路径规划(提供Python代码)
    迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻......
  • 数据结构之顺序表(C语言版)
    顺序表是数据结构中最基本的一种线性表,它以一段连续的存储空间来存储数据元素,元素之间的顺序由它们在内存中的位置来决定。在C语言中,我们通常使用数组来实现顺序表。目录顺序表的结构定义顺序表的基本操作应用实例顺序表的结构定义首先,我们需要定义一个结构体来表......
  • C++算法学习心得八.动态规划算法(5)
    1.买卖股票的最佳时机(121题)题目描述:给定一个数组prices,它的第 i个元素 prices[i]表示一支给定股票第i天的价格。你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取......
  • C++算法学习心得八.动态规划算法(4)
    1.零钱兑换(322题)题目描述:给定不同面额的硬币coins和一个总金额amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。你可以认为每种硬币的数量是无限的。示例 1:输入:coins=[1,2,5],amount=11输出:3解......
  • 力扣大厂热门面试算法题 39-41
    39.组合总和,40.组合总和II,41.缺失的第一个正数,每题做详细思路梳理,配套Python&Java双语代码,2024.03.17 可通过leetcode所有测试用例。目录39.组合总和解题思路完整代码PythonJava40.组合总和II解题思路完整代码PythonJava41.缺失的第一个正数解题思路完......
  • 数据结构知识总结笔记------第四章:串(1)串的定义、存储结构、基本操作
    1、串的定义串是由零个或者多个字符组成的有限序列。串中字符的个数称为串的长度,含有零个元素的串叫空串。在C语言中,可以用以下语句定义一个名为str的串。charstr[]="abcdef";说明:串通常用一个字符数组来表示。从这个角度来讲,数组str内存储的字符为’a’、‘b’、‘c’......
  • 【算法与数据结构】堆排序&&TOP-K问题之深入解析二叉树(三)
    文章目录......
  • 数据结构ArrayList之杨辉三角庖丁解牛!
    题外话先给大家露一手我对杨辉三角的理解,虽说标题是庖丁解牛,但是还是虚心请教一下大家,有什么意见都可以提出!正题思维逻辑先画个杨辉三角,有几点需要大家注意一下1.杨辉三角其实在代码里就是一个二维数组,图中i代表行但是是从0开始的,而j则代表每行的元素2.如果想......