首页 > 其他分享 >图结构 Graph primary

图结构 Graph primary

时间:2024-04-03 18:45:16浏览次数:13  
标签:遍历 String Graph primary source 邻接 adjacencyList 节点 结构

目录


图结构 (英文:Graph Structure)

图的定义:
在数据的逻辑结构中,如果结构中的某一个节点的前驱和后继的个数不加限制,则称这种数据结构为图结构(图形结构、Graph)。

图形结构是一种比树形结构更复杂的非线性结构。区别在于:

  • 在树形结构中,结点间具有分支层次关系,每一层上的结点只能和上一层中的至多一个结点相关,但可能和下一层的多个结点相关。
  • 而在图形结构中,任意两个结点之间都可能相关,即结点之间的邻接关系可以是任意的。

图的应用场景

网络安全:
利用图数据模型可以表示网络中的实体(如用户、设备、网络节点)及其之间的复杂关系,从而更好地分析网络安全威胁、检测网络攻击和异常行为。例如,可以利用图数据库存储网络设备之间的连接关系、用户之间的交互行为等,通过对图数据的查询和分析,发现潜在的网络攻击路径和恶意行为。

金融风控:
金融领域中存在大量的实体和关系数据,如用户、账户、交易、资产等。利用图数据库可以将这些实体和关系以图的形式存储和管理,便于进行风险评估、欺诈检测、信用评级等任务。

例如,通过对用户之间的社交关系、交易行为的分析,可以发现潜在的欺诈行为和风险交易。

社交网络:
社交网络中的用户、好友关系、兴趣标签等可以抽象为图数据,利用图数据库可以快速查询和分析社交网络中的用户关系、兴趣匹配、信息传播等。

例如,可以利用图数据库存储用户之间的社交关系,通过对图数据的查询和分析,发现用户之间的共同兴趣和社交网络中的影响力节点。

生物医学:
生物医学领域中的分子结构、蛋白质相互作用、基因组数据等可以表示为图数据。利用图数据库可以存储和管理这些图数据,便于进行药物研发、疾病诊断、基因分析等任务。

例如,通过对分子结构的图数据进行分析,可以发现药物分子的潜在活性和副作用。

推荐系统:
推荐系统中的用户、物品、兴趣等可以表示为图数据,利用图数据库可以存储和管理这些图数据,进行个性化推荐、用户兴趣挖掘等任务。

例如,通过对用户兴趣的图数据进行分析,可以发现用户的潜在兴趣和推荐相似的物品。

以上是图的应用场景的简要介绍,图数据库在处理复杂的实体关系和关联数据时具有优势,能够有效地存储、查询和分析大规模的图数据。

图的概念和分类

  • 顶点(也叫点、节点):A、B、C、...

  • 边(也称作弧):顶点和顶点之间的连线

  • 无向图:边没有方向的图称为无向图

  • 有向图:顶点和顶点之间的边有方向

  • 带权图:边带有权值,权值指的是边的值

  • 无向无权图

  • 无向有权图

  • 有向无权图

  • 有向带权图

图的操作

存储

图的存储方式有:
1. 邻接表(链表)(本文就演示这种方式,其它方式可以自己操作一下)
2. 邻接矩阵(就是二维数组)
3. 关联矩阵
4. 邻接多重表
5. 十字链表等....
(不同的存储结构,在不同地特定的场景下可能更加适用。选择合适的存储方式取决于图的类型、规模以及需要进行的操作。)

定义结构体:

package graph;

import java.awt.*;
import java.util.*;
import javax.swing.*;


class Graph extends JPanel {

    //adjacencyList 充当了存储图结构信息的核心数据结构的角色。通过对它进行操作,我们就可以构建和表示给定的图。
    //adjacencyList 使用HashMap和LinkedList实现了邻接表的数据结构 ,思考为什么不用ArrayList?
    /**
     * adjacencyList 是这个代码中定义的一个 HashMap<String, LinkedList<String>> 类型的成员变量,用于表示图的邻接表数据结构。
     * <p>
     * 在图论中,邻接表是一种常用的存储图的方式。对于每个节点,我们使用一个链表来存储与该节点相邻的节点
     * 在这个实现中,adjacencyList 的:
     * 键(key)是节点的标签(String类型)
     * 值(value)是一个 LinkedList<String>对象,表示与该节点相邻的所有节点的标签列表。
     * <p>
     * 例如,对于图中的节点 A,它与 B 和 C 相邻,那么 adjacencyList 中就会有一个条目:
     * "A" -> ["B", "C"]
     * <p>
     * <p>
     * 这样,我们就可以通过查询 adjacencyList.get("A") 来获取与节点 A 相邻的所有节点的列表。
     * <p>
     * 使用邻接表来表示图有以下优点:
     * 1.方便存储无序的、不连续的边信息。
     * 2.对于稀疏图(边的数量远小于节点数量的平方)来说,邻接表比邻接矩阵更节省空间。
     * 3.添加或删除边的操作比较简单和高效。
     */
    private HashMap<String, LinkedList<String>> adjacencyList;

    public Graph() {
        adjacencyList = new HashMap<>();
        // 添加节点
        addNode("A");
        addNode("B");
        addNode("C");
        addNode("D");
        addNode("E");
        // 添加边
        addEdge("A", "B");
        addEdge("A", "C");
        addEdge("B", "C");
        addEdge("B", "E");
        addEdge("C", "D");
    }

    //addNode方法用于添加节点
    public void addNode(String label) {
        adjacencyList.putIfAbsent(label, new LinkedList<>());
    }

    //addEdge方法用于添加边
    //addEdge的功能是向邻接表中添加两个顶点之间的边。
    public void addEdge(String source, String destination) {
        // 首先检查 source 和 destination 节点是否都存在于 adjacencyList 中。
        //      如果有任何一个节点不存在,则不执行后续操作,因为我们不能在不存在的节点之间添加边。
        if (adjacencyList.containsKey(source) && adjacencyList.containsKey(destination)) {
            //如果两个节点都存在,则执行以下步骤:
            //这一行代码获取与 source 节点相关联的邻接表(LinkedList<String>),并将 destination 节点的标签添加到该邻接表中。这表示从 source 节点出发,可以到达 destination 节点。
            adjacencyList.get(source).add(destination);
            // 这一行代码获取与 destination 节点相关联的邻接表,并将 source 节点的标签添加到该邻接表中。这表示从 destination 节点出发,也可以到达 source 节点。
            adjacencyList.get(destination).add(source);
        }
        /**
         * 这段代码的目的是在无向图中添加一条边。由于无向图的边是双向的,因此需要在两个节点的邻接表中都添加对方的节点标签。
         *
         * 例如,如果我们执行 addEdge("A", "B")操作,则在 adjacencyList 中会有以下的更新:
         *  "A" -> ["B"]
         *  "B" -> ["A"]
         *  这表示节点 A 和节点 B 之间存在一条边,它们是相互可达的。
         */
    }

    //查询指定节点的相邻节点
    public void queryNode(String label) {
        if (adjacencyList.containsKey(label)) {
            System.out.print("Node " + label + " is connected to: ");
            for (String neighbor : adjacencyList.get(label)) {
                System.out.print(neighbor + " ");
            }
            System.out.println();
        } else {
            System.out.println("Node " + label + " does not exist in the graph.");
        }
    }
    
    // 下面是一些绘图代码,不需要关注,和图结构关系不大。
    //在paintComponent方法中,我首先定义了每个节点的位置坐标,然后遍历邻接表,绘制节点和连线。
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        HashMap<String, Point> nodePositions = new HashMap<>();
        nodePositions.put("A", new Point(100, 100));
        nodePositions.put("B", new Point(300, 50));
        nodePositions.put("C", new Point(100, 200));
        nodePositions.put("D", new Point(200, 200));
        nodePositions.put("E", new Point(400, 200));

        for (String node : adjacencyList.keySet()) {
            Point pos = nodePositions.get(node);
            drawNode(g, node, pos.x, pos.y);
        }

        for (String source : adjacencyList.keySet()) {
            Point sourcePos = nodePositions.get(source);
            for (String destination : adjacencyList.get(source)) {
                Point destPos = nodePositions.get(destination);
                drawLine(g, sourcePos.x, sourcePos.y, destPos.x, destPos.y);
            }
        }
    }

    private void drawNode(Graphics g, String label, int x, int y) {
        g.setColor(Color.BLUE);
        g.fillOval(x - 20, y - 20, 40, 40);
        g.setColor(Color.WHITE);
        g.drawString(label, x - 5, y + 5);
    }

    private void drawLine(Graphics g, int x1, int y1, int x2, int y2) {
        g.setColor(Color.BLACK);
        g.drawLine(x1, y1, x2, y2);
    }

    /**
     * drawNode方法用于绘制一个带标签的圆形节点。
     * drawLine方法用于绘制连接两个节点的线段。
     * 在main方法中,创建并显示Graph的实例。
     *
     * @param args
     */
    public static void main(String[] args) {
        JFrame frame = new JFrame("Graph");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(600, 400);
        frame.add(new Graph());
        frame.setVisible(true);
    }
}

输出:

查询

两种遍历方式:

  1. 深度优先遍历(DFS——Depth First Search)
  2. 广度优先遍历(BFS——Breath First Search)

只需要大概了解,这里不深度讲解两种遍历方式。

广度优先介绍:
广度优先遍历也叫层序遍历,先遍历第一层(节点 1),再遍历第二层(节点 2,3,4),第三层(5,6,7,8),第四层(9,10)。

深度优先介绍:
从根结点出发,一直向左子节点走,直到左子节点不存在然后返回到上一个节点走这个节点的右子节点,然后一直往右子节点走,同样的也是走不通为止就返回。很显然这种一路走到黑,黑了就回头的方式,就是深度优先遍历的过程。


查询一个节点的相关节点:
这个 queryNode() 方法实际上并不是在执行图的深度优先搜索(DFS)或广度优先搜索(BFS)遍历算法。它只是简单地输出指定节点的所有直接相邻节点,而不涉及对整个图进行遍历。

在这个代码中,我们使用 HashMap 和 LinkedList 构建了一个邻接表来表示图的结构。
对于每个节点,我们使用一个 LinkedList 来存储与它直接相连的所有节点的标签。

当调用 queryNode(String label) 时,它会首先检查 label 是否存在于 adjacencyList 中。
如果存在,则直接遍历该节点对应的 LinkedList,输出其中包含的所有相邻节点的标签。
这个过程实际上只是对一个线性数据结构(LinkedList)进行了简单的遍历,而不涉及对整个图进行深度或广度优先的系统遍历。

public static void main(String[] args) {
  Graph graph = new Graph();
  // 查询指定节点的相邻节点
  graph.queryNode("B");
}

输出:
Node B is connected to: A C E

标签:遍历,String,Graph,primary,source,邻接,adjacencyList,节点,结构
From: https://www.cnblogs.com/mysticbinary/p/18112092

相关文章

  • MySQL索引背后的数据结构及算法原理
    摘要本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题。特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等。为了避免混乱,本文将只关注于BTree索引,因为这是平常使用MyS......
  • python常见数据结构及方法
    Python提供了多种内置的数据结构,这些数据结构非常灵活且功能强大,能够满足各种程序设计需求。下面是一些最常用的Python数据结构及其内置方法的详细说明:1.列表(List)列表是Python中最基本的数据结构之一。列表可以包含不同类型的元素,包括另一个列表。常用内置方法:append(x......
  • 【数据结构与算法篇】动态顺序表实战项目:通讯录
    【数据结构与算法】动态顺序表实战项目:通讯录......
  • c语言---- 结构体
    1.怎么定义一个结构体:1.struct这个变量名就是跟电脑说明,我是一个结构体。2.在struct后面的名字是要大写开头的。3.在大括号结束了,一定要加分号;​​2.结构体数组就是跟之前的数组一样的,就是名字前面的变量改成了结构的,还有里面的数,跟二维数组差不多:​​3.结......
  • 散列表结构-new
    <!DOCTYPEhtml><htmllang="en"><head>  <metacharset="UTF-8">  <metahttp-equiv="X-UA-Compatible"content="IE=edge">  <metaname="viewport"content="width=d......
  • map-字典结构-new
    <!DOCTYPEhtml><htmllang="en"><head>  <metacharset="UTF-8">  <metahttp-equiv="X-UA-Compatible"content="IE=edge">  <metaname="viewport"content="width=d......
  • 栈结构-stack-new
    <!DOCTYPEhtml><htmllang="en"><head>  <metacharset="UTF-8">  <metahttp-equiv="X-UA-Compatible"content="IE=edge">  <metaname="viewport"content="width=d......
  • 计算机组成与系统结构-第3章 运算方法和运算部件 上
    文章目录3.1高级语言和机器指令中的运算3.1.1C语言程序中涉及的运算数据的运算3.1.2MIPS指令中涉及的运算3.2基本运算部件3.2.1全加器和加法器全加器(FullAdder,简称FA)串行进位加法器/行波进位加法器(carryrippleadder,CRA)。3.2.2并行进位加法器3.2.3带标志加法器3......
  • 深入理解数据结构第二弹——二叉树(2)——堆排序及其时间复杂度
    看这篇前请先把我上一篇了解一下:深入理解数据结构第一弹——二叉树(1)——堆-CSDN博客前言:相信很多学习数据结构的人,都会遇到一种情况,就是明明最一开始学习就学习了时间复杂度,但是在后期自己写的程序或者是做到哪个需要判断时间复杂度的题时,仍然判断不出来时间复杂度是多少,今......
  • 顺序结构、选择结构、循环结构
    一、顺序结构二、选择结构importjava.util.Scanner;publicclassifdemo{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);System.out.println("请输入内容:");Strings=scanner.nextLine();......