图结构——数据结构与算法学习

为何要有图呢?

其实就是对于线性表和树的补充,线性表和树只能表示一对一的关系,而图可以表示多对多的关系。

关于图的基本解释

完全图、连通图、非连通图、连通分量

图的两种表示方式

  1. 邻接矩阵

  1. 邻接表

图的两种搜索方式

辅助理解资源

深度优先搜索与广度优先搜索

深度优先搜索

原理:
首先把一条路径上的纵向节点挖掘完毕,然后再进行横向访问。(借助递归实现)

具体步骤:
1) 访问初始结点 v,并标记结点 v 为已访问。
2) 查找结点 v 的第一个邻接结点 w。
3) 若 w 存在,则继续执行 4,如果 w 不存在,则回到第 1 步,将从 v 的下一个结点继续。
4) 若 w 未被访问,对 w 进行深度优先遍历递归(即把 w 当做另一个 v,然后进行步骤 123)。
5) 查找结点 v 的 w 邻接结点的下一个邻接结点,转到步骤 3。

广度优先搜索

原理:
先找到一个节点的全部邻接节点,再根据节点的顺序依次遍历。(使用队列进行完成)

具体步骤:
1) 访问初始结点 v 并标记结点 v 为已访问。
2) 结点 v 入队列
3) 当队列非空时,继续执行,否则算法结束。
4) 出队列,取得队头结点 u。
5) 查找结点 u 的第一个邻接结点 w。
6) 若结点 u 的邻接结点 w 不存在,则转到步骤 3;否则循环执行以下三个步骤:
6.1 若结点 w 尚未被访问,则访问结点 w 并标记为已访问。
6.2 结点 w 入队列
6.3 查找结点 u 的继 w 邻接结点后的下一个邻接结点 w,转到步骤 6。

深度优先vs广度优先

代码实现

package Graph;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Stack;

public class Graph {
    //因为此时没有被实例化,在内存中是不存在的
    private ArrayList<String> vertexlist;//存储顶点集合
    private int edges[][];//图对应的凝结矩阵
    private int numOfEdges;//定义边的数目
    public boolean[] isVisited;//定义是否被访问的数组

    public static void main(String[] args) {
        int n = 8;
        String Vertexs[] = {"1","2","3","4","5","6","7","8"};
        Graph graph = new Graph(n);
        for (String vertex : Vertexs) {
            graph.insertVertex(vertex);
        }
        //更新边的关系
        graph.insertEdge(0, 1, 1);
        graph.insertEdge(0, 2, 1);
        graph.insertEdge(1, 3, 1);
        graph.insertEdge(1, 4, 1);
        graph.insertEdge(3, 7, 1);
        graph.insertEdge(4, 7, 1);
        graph.insertEdge(2, 5, 1);
        graph.insertEdge(2, 6, 1);
        graph.insertEdge(5, 6, 1);
        graph.showGraph();
        System.out.println("深度遍历");
        graph.dfs();
        System.out.println();
        System.out.println("广度遍历");
        graph.bfs();
        System.out.println("test");
        System.out.println("广度测试");
        graph.dfs2();
    }

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

    //图中常用的方法
    public int getNumOfVertex(){
        return vertexlist.size();
    }
    //显示图对应的矩阵
    public void showGraph(){
        for (int[] edge : edges) {
            System.out.println(Arrays.toString(edge));
        }
    }
    //得到边的数目
    public int getNumOfEdges(){
        return numOfEdges;
    }
    //返回节点下标对应的数据
    public String getValueByIndex(int i){
        return vertexlist.get(i);
    }
    //返回v1 和 v2的权值
    public int getWeight(int v1,int v2){
        return edges[v1][v2];
    }
    //插入结点
    public void insertVertex(String vertex){
        vertexlist.add(vertex);
    }
    //添加边
    public void insertEdge(int v1,int v2,int weight){
        edges[v1][v2] = weight;
        edges[v2][v1] = weight;
        numOfEdges++;
    }
    //根据索引得到第一个凝结结点的下标
    public int getFirstNeighbor(int index){
        for (int i = 0; i < vertexlist.size(); i++) {//从0开始确保最先得到索引为0的节点
            if(edges[index][i] > 0){
                return i;
            }
        }
        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;
    }

    //深度优先遍历算法
    public void dfs(boolean[] visited,int i){
        System.out.print(getValueByIndex(i) + "->");
        isVisited[i] = true;
        int w = getFirstNeighbor(i);
        while(w != -1){
            if(!isVisited[w]){
                dfs(isVisited,w);
            }
            w = getNextNeighbor(i,w);//一个节点遍历完转向下一个节点
        }
    }
    //对每一个节点为初始节点的情况都进行遍历,考虑到费连通图的情况
    public void dfs(){
        isVisited = new boolean[vertexlist.size()];
        for (int i = 0; i < getNumOfVertex(); i++) {
            if(!isVisited[i]){
                dfs(isVisited,i);
            }
        }
    }
    //广度优先遍历算法
    private void bfs(boolean[] isVisited,int i){
        int u;
        int w;
        LinkedList linkedList = new LinkedList();
        System.out.print(getValueByIndex(i)+ "->");
        isVisited[i] = true;
        linkedList.addLast(i);
        while(!linkedList.isEmpty()){
            u = (Integer)linkedList.removeFirst();
            w = getFirstNeighbor(u);
            while(w != -1){
                if(!isVisited[w]){
                    System.out.print(getValueByIndex(w) +"->");
                    isVisited[w] = true;
                    linkedList.addLast(w);
                }
                w = getNextNeighbor(u,w);
            }
        }
    }
    public void bfs() {
        isVisited = new boolean[vertexlist.size()];
        for(int i = 0; i < getNumOfVertex(); i++) {
            if(!isVisited[i]) {
                bfs(isVisited, i);
            }
        }
    }
    //使用栈结构实现深度优先遍历(将C语言改成java语言)
    public void dfs_stack(boolean[] visited,int i){
        System.out.println(getValueByIndex(i) + "->");
        isVisited[i] = true;
        Stack<Integer> stack = new Stack<Integer>();//循环时用来放节点,类似于递归时的向上return
        int w = getFirstNeighbor(i);
        int k,v;
        k = i;//表示父节点的代指
        v = w;//v代表的是i的临界节点
        while(v != -1){
            while(true){
                w = getFirstNeighbor(k);//表示得到第一个初始节点
                if(w == -1){
                    break;
                }
                k = w;
                System.out.println(getValueByIndex(w)+"-");
            }
            v = getNextNeighbor(i,v);
        }
    }
    //对每一个节点为初始节点的情况都进行遍历,考虑到费连通图的情况
    public void dfs2(){
        isVisited = new boolean[vertexlist.size()];
        for (int i = 0; i < 1; i++) {
            if(!isVisited[i]){
                dfs(isVisited,i);
            }
        }
    }
}

posted @   深海之燃  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示