【数据结构】图结构及其遍历方式

简介: 【数据结构】图结构及其遍历方式

一、图的概述

1、图的概念

图是一种数据结构,其中结点可以具有零个或多个相邻元素。两个结点之间的连接称为边。(结点也可以称为顶点)

2、图的基本概念

  1. 顶点(vertex)
  2. 边(edge)
  3. 路径
  4. 无向图:顶点之间的连接没有方向
  5. 有向图:顶点之间的连接有方向
  6. 带权图(网):边带权值的图

3、图的实现方式

图的表示方式有两种:二维数组表示(邻接矩阵);链表表示(邻接表)

1)邻接矩阵

邻接矩阵是表示图形中顶点之间相邻关系的矩阵(二维数组),对于n个顶点的图而言,矩阵是的row 和col 表示的是 1..n个点。

2)邻接表

邻接矩阵需要为每个顶点都分配n 个边的空间,其实有很多边都是不存在,会造成空间的一定损失。

邻接表的实现只关心存在的边,不关心不存在的边。因此没有空间浪费,邻接表由数组+链表组成。

二、深度优先搜索(dfs)

深度优先遍历,从初始访问结点出发,初始访问结点可能有多个邻接结点,深度优先遍历的策路就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点。

每次都在访问完当前结点后首先访问当前结点的第一个邻接结点。

这样的访问策略是优先往纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问。

深度优先搜索是一个递归的过程

三、广度优先搜索(bfs)

图的广度优先搜索(Broad First Search),类似于一个分层搜索的过程,广度优先遍历需要使用一个队列以保持访问过的结点的顺序,以便按这个顺序来访问这些结点的邻接结点

void bfs(起始点) {
    将起始点放入队列中;
    标记起点访问;
    while(如果队列不为空){
        访问队首元素x;
        删除队首元素;
        for(x的相邻点) {
            if(没被标记) {
                加入队尾并标记; 
            } 
        } 
    } 
    队列为空,广搜结束; 
}

四、图的代码实现

package work.rexhao.graph;


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

/**
 * 图的基础及dfs、bfs遍历
 *
 * @author 王铭颢
 * @Date 2022/7/11 22:26
 */
public class Graph {
   
    int[][] edges;      // 邻接矩阵
    int n;              // 节点个数
    List<String> vertex;// 顶点名称
    boolean[] flag;     // 记录是否被访问过

    public static void main(String[] args) {
   
        Graph graph = new Graph(5);
        String[] strs = {
   "a", "b", "c", "d", "e"};
        graph.addVertex(strs);

        graph.addEdges(0, 1, 1);  // a -- b
        graph.addEdges(0, 2, 1);  // a -- c
        graph.addEdges(2, 3, 1);  // c -- d
        graph.addEdges(0, 4, 1);  // a -- e

        graph.showGraph();
        System.out.println("-----------");

        graph.dfs();
        graph.bfs();
    }

    /**
     * 广度优先遍历
     */
    private void bfs() {
   
        flag = new boolean[n];
        System.out.print("bfs:");
        ArrayQueue queue = new ArrayQueue(n);

        queue.addQueue(0);
        while (!queue.isEmpty()) {
   
            // 出队列
            int i = queue.getQueue();
            System.out.print(getValueByIndex(i));
            // 标记
            flag[i] = true;
            // 把该节点连接的节点加入队列
            for (int j = 0; j < n; j++) {
   
                if (!flag[j] && edges[i][j] != 0) {
   
                    queue.addQueue(j);
                }
            }
        }

        System.out.println();
    }


    /**
     * 深度优先遍历
     */
    public void dfs() {
   
        flag = new boolean[n];
        System.out.print("dfs:");
        for (int i = 0; i < n; i++) {
   
            dfs(i);
        }
        System.out.println();
    }

    public void dfs(int i) {
   
        // 标记过 -> return
        if (flag[i]) {
   
            return;
        }
        // 没被标记 -> 输出该节点 -> 标记
        System.out.print(getValueByIndex(i));
        flag[i] = true;
        // 找到该节点的后续节点
        for (int j = 0; j < n; j++) {
   
            if (edges[i][j] != 0) {
   
                dfs(j);
            }
        }
    }

    /**
     * 构造器
     *
     * @param n 节点个数
     */
    Graph(int n) {
   
        this.n = n;
        edges = new int[n][n];
        vertex = new ArrayList<>(n);
    }

    /**
     * 添加节点名称
     *
     * @param strs 节点名称数组
     */
    public void addVertex(String[] strs) {
   
        vertex.addAll(Arrays.asList(strs));
    }

    /**
     * 添加边
     *
     * @param v1     节点1
     * @param v2     节点2
     * @param weight 权重
     */
    public void addEdges(int v1, int v2, int weight) {
   
        edges[v1][v2] = weight;
        edges[v2][v1] = weight;
    }

    /**
     * 打印邻接矩阵
     */
    public void showGraph() {
   
        for (int[] edge : edges) {
   
            for (int i : edge) {
   
                System.out.print(i + " ");
            }
            System.out.println();
        }
    }


    /**
     * 根据下标获取节点数据
     *
     * @param i 节点下标
     * @return 节点数据
     */
    public String getValueByIndex(int i) {
   
        return vertex.get(i);
    }
}

class ArrayQueue {
   
    private int maxSize; // 数组最大容量
    private int front; // 队列头
    private int rear; // 队列尾
    private int[] arr; // 队列的数据

    /**
     * 创建队列的构造器
     */
    public ArrayQueue(int arrMaxSize) {
   
        maxSize = arrMaxSize;
        arr = new int[arrMaxSize];
        front = -1;// 指向队列头的前一个位置
        rear = -1;// 指向队列尾
    }

    /**
     * 判断队列是否满
     */
    public boolean isFull() {
   
        return rear == maxSize - 1;
    }

    /**
     * 判断队列是否为空
     */
    public boolean isEmpty() {
   
        return rear == front;
    }

    /**
     * 添加队列数据
     */
    public void addQueue(int n) {
   
        if (isFull()) {
   
            System.out.println("队列满,添加失败!");
            return;
        }
        arr[++rear] = n;
    }

    /**
     * 出队列
     */
    public int getQueue() {
   
        if (isEmpty()) {
   
            // 抛出异常 -- 不需要写return
            throw new RuntimeException("队列空");
        }
        return arr[++front];
    }

    /**
     * 遍历
     */
    public void showQueue() {
   
        if (isEmpty()) {
   
            System.out.println("队列空!");
            return;
        }
        for (int i = 0; i < arr.length; i++) {
   
            System.out.printf("arr[%d] = %d\n", i, arr[i]);
        }
    }

    /**
     * 显示头数据(不取出)
     */
    public int headQueue() {
   
        if (isEmpty()) {
   
            throw new RuntimeException("队列空");
        }
        return arr[front + 1];
    }
}
目录
相关文章
|
18天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
60 16
|
5月前
|
存储 算法
【数据结构和算法】--- 二叉树(4)--二叉树链式结构的实现(2)
【数据结构和算法】--- 二叉树(4)--二叉树链式结构的实现(2)
38 0
|
5月前
|
存储 算法 Linux
【数据结构和算法】---二叉树(1)--树概念及结构
【数据结构和算法】---二叉树(1)--树概念及结构
51 0
|
1月前
|
存储 编译器 C++
【初阶数据结构】掌握二叉树遍历技巧与信息求解:深入解析四种遍历方法及树的结构与统计分析
【初阶数据结构】掌握二叉树遍历技巧与信息求解:深入解析四种遍历方法及树的结构与统计分析
|
1月前
探索顺序结构:栈的实现方式
探索顺序结构:栈的实现方式
|
1月前
|
存储 算法
数据结构与算法学习十六:树的知识、二叉树、二叉树的遍历(前序、中序、后序、层次)、二叉树的查找(前序、中序、后序、层次)、二叉树的删除
这篇文章主要介绍了树和二叉树的基础知识,包括树的存储方式、二叉树的定义、遍历方法(前序、中序、后序、层次遍历),以及二叉树的查找和删除操作。
25 0
|
1月前
|
存储 算法
【数据结构】二叉树——顺序结构——堆及其实现
【数据结构】二叉树——顺序结构——堆及其实现
|
2月前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
2月前
|
存储 机器学习/深度学习 C语言
数据结构基础详解(C语言): 树与二叉树的基本类型与存储结构详解
本文介绍了树和二叉树的基本概念及性质。树是由节点组成的层次结构,其中节点的度为其分支数量,树的度为树中最大节点度数。二叉树是一种特殊的树,其节点最多有两个子节点,具有多种性质,如叶子节点数与度为2的节点数之间的关系。此外,还介绍了二叉树的不同形态,包括满二叉树、完全二叉树、二叉排序树和平衡二叉树,并探讨了二叉树的顺序存储和链式存储结构。
|
4月前
|
存储
【数据结构】树和二叉树的概念及结构
数据结构——树和二叉树的概念及结构
77 3
【数据结构】树和二叉树的概念及结构

热门文章

最新文章

下一篇
无影云桌面