graph.java

来自「1.程序基于java语言。运行要求java运行环境。即就使jdk1.2以上。否则」· Java 代码 · 共 302 行

JAVA
302
字号
package bfs;

import java.io.*;
import java.util.StringTokenizer;
import javax.swing.JTextArea;
import javax.swing.JOptionPane;
import java.util.Vector;

/**
 * <p>Title: 基于java语言的图的广度遍历</p>
 *
 * <p>Description: 版权所有严禁盗版</p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: 中南大学计算机0304班 </p>
 *
 * @author 李阳辉
 * @version 1.0
 */
/**
 * 该类是对图的定义
 *
 * 采用邻接矩阵表示
 */

public class Graph {
    private int kind; //图的类型
    private int[][] adjMatrix = new int[50][50]; //图的邻接矩阵,最大为50
    private int vex_num, arc_num; //当前的顶点数和弧数
    private boolean[] visited = new boolean[50]; //访问标志数组


    private BufferedReader input; //用来读文件
    private Vector queue = new Vector(); //用一个向量来做队列
    private Vector stack = new Vector(); //用一个向量来做堆栈
    public Graph() {
    }

    //从文件初始化图
    public void readGraph(String fileName, int kind) {
        //先进行初始化。
        this.kind = kind;
        for (int i = 0; i < 50; i++) {
            for (int j = 0; j < 50; j++) {
                adjMatrix[i][j] = 0;
            }
        }
        vex_num = arc_num = 0;
        try { //利用缓冲流读取文件内容
            input = new BufferedReader(new FileReader(fileName));
            System.out.println("成功打开文件");
        } catch (FileNotFoundException ex) {
            System.out.println(ex);
        }
        try {
            String line;
            while ((line = input.readLine()) != null) {
                StringTokenizer t = new StringTokenizer(line, " "); //分开头和尾
                int head = Integer.parseInt(t.nextToken()); //得到边的头
                int cauda = Integer.parseInt(t.nextToken()); //得到边的尾
                if (head >= vex_num) { //得到一个有多少个顶点
                    vex_num = head;
                }
                if (cauda >= vex_num) { //得到一个有多少个顶点
                    vex_num = cauda;
                }
                arc_num++; //弧数加 1
                adjMatrix[head - 1][cauda - 1] = 1; //把弧填入邻接矩阵中
                if (kind != JOptionPane.YES_OPTION) { //为无向图时
                    adjMatrix[cauda - 1][head - 1] = 1;
                }
            }
            input.close(); //关闭文件,停止文件读入;
        } catch (IOException ex1) {
            System.out.println(ex1);
        }
    }

    //输出相应的图的数据
    public void printGraph(JTextArea showArea) {
        showArea.append("\n");
        showArea.append("你输入的图的数据:\n");
        //顶点数边数
        showArea.append("     一共用" + vex_num + "个顶点; 和" + arc_num + "条边;\n");
        showArea.append("     边的数据为:\n");
        //从邻接矩阵中读出边的数据
        boolean flag = false; //先判断i是否存在邻接点,有则打印其边,否则跳过
        for (int i = 0; i < vex_num; i++) {
            for (int j = 0; j < vex_num; j++) {
                if (adjMatrix[i][j] != 0) {
                    flag = true;
                    break;
                }
            }
            if (flag == true) {
                showArea.append("               " + (i + 1) + "-->");
                for (int j = 0; j < vex_num; j++) {
                    if (adjMatrix[i][j] != 0) {
                        showArea.append((j + 1) + ", ");
                    }
                }
                showArea.append("\n"); //往下移行
            }
            flag = false; //对标志归位;
        }
    }

    /**
     *下面方法完成对图的DFS遍历。
     *
     *一个完全的基于非递归的算法
     */
    public void DFS(JTextArea showArea) {
        showArea.append("现在开始用DFS遍历图:\n");
        stack.clear(); //保证堆栈为空。
        for (int i = 0; i < 50; i++) {
            visited[i] = false;
        }
        int parent = -1;
        for (int v = 0; v < this.vex_num; v++) {
            if (!visited[v]) { //v点尚未访问
                visited[v] = true; //设定标志
                showArea.append("访问" + (v + 1) + "顶点;\n");
                stack.add(new Integer(v)); //把该点加入堆栈中
                showArea.append("把" + (v + 1) + "顶点加入堆栈中;\n");
                while (!stack.isEmpty()) {
                    int currentVex = ((Integer) stack.lastElement()).intValue(); //得到栈顶元素
                    showArea.append("访问" + (currentVex + 1) + "顶点的邻接点 ;\n");
                    int adjVex;
                    showArea.append("检查" + (currentVex + 1) +
                                    "的邻接点和其他顶点之间是否存在环路.\n");
                    for (adjVex = 0; adjVex < vex_num; adjVex++) {
                        if (adjMatrix[currentVex][adjVex] != 0 &&
                            adjVex != parent) { //看是否存在回路
                            if (visited[adjVex] == true &&
                                stack.indexOf(new Integer(adjVex)) >= 0) {
                                showArea.append("检查到" + (adjVex + 1) +
                                                "顶点时停止存在环路!!!\n");
                                JOptionPane.showMessageDialog(null, "存在环路!");
                                for (int i = 0; i < vex_num; i++) {//把图归位,使之能够多次使用
                                    visited[i] = false;
                                }
                                stack.clear();
                                return;
                            }

                        } //否则访问并压堆栈中
                        if (adjMatrix[currentVex][adjVex] != 0 &&
                            adjVex != parent && visited[adjVex] != true) {
                            visited[adjVex] = true;
                            stack.add(new Integer(adjVex)); //把该邻接点压入堆栈中
                            showArea.append("把顶点" + (adjVex + 1) + "压入堆栈。\n");
                            parent = currentVex;
                            break;
                        }
                    }
                    //没有邻接点出栈
                    if (adjVex == vex_num) {
                        parent = currentVex;
                        showArea.append((currentVex + 1) + "顶点弹出堆栈;\n");
                        stack.remove(stack.lastElement()); //弹出栈顶元素
                    }
                } //while
            } //if
        } //for
        showArea.append("DFS访问停止,没有发现环路!!!\n");
        JOptionPane.showMessageDialog(null, "没有环路!!!");
        for (int i = 0; i < vex_num; i++) {
            visited[i] = false;
        }
        stack.clear();
    }

    //对图进行BFS访问实录,一个完全的非递归的算法。
    public void BFS(JTextArea showArea) {
        showArea.append("现在开始用BFS访问该图:\n");
        for (int i = 0; i < vex_num; i++) { //对图的BFS后把图归位.
            visited[i] = false;
        }
        queue.removeAllElements();
        for (int v = 0; v < this.vex_num; ++v) {
            if (!visited[v]) { //v点尚未访问
                visited[v] = true;
                showArea.append("访问" + (v + 1) + "顶点;\n");
                queue.add(new Integer(v)); //加入队列中
                showArea.append("把" + (v + 1) + "顶点加入队列中;\n");
                while (!queue.isEmpty()) {
                    int currentVex = ((Integer) queue.get(0)).intValue(); //得到队头元素
                    queue.remove(queue.remove(0)); //队头元素出队列
                    showArea.append((currentVex + 1) + "顶点出队列;\n");
                    showArea.append("访问" + (currentVex + 1) + "顶点的邻接点 ;\n");
                    for (int adjVex = 0; adjVex < vex_num; adjVex++) { //访问它的邻接点
                        //当它的邻接点还没有被访问时,进行访问.
                        if (!visited[adjVex] &&
                            adjMatrix[currentVex][adjVex] != 0) {
                            showArea.append("访问" + (adjVex + 1) + "顶点;\n");
                            visited[adjVex] = true; //标志已经访问此顶点
                            showArea.append("把" + (adjVex + 1) +
                                            "顶点加入队列中;\n");
                            queue.add(new Integer(adjVex)); //把它压入队列中
                        } //if
                    } //for
                } //while
            } //if
        } //for
        showArea.append("BFS访问完成!!!\n");
        //完成对图的BFS后把图归位.
        for (int i = 0; i < vex_num; i++) {
            visited[i] = false;
        }
        queue.removeAllElements();
    }

    public void shortestPath(JTextArea showArea) {
        //一开始输入出发顶点和结束顶点
        String input = JOptionPane.showInputDialog("请输入出发点");
        int start = Integer.parseInt(input);
        input = JOptionPane.showInputDialog("请输入结束顶点");
        int end = Integer.parseInt(input);
        //判断是否输入正确.
        if (start > vex_num || end > vex_num) {
            JOptionPane.showMessageDialog(null, "不存在这样的出发点或者结束点");
            return;
        }
        //判断是否是同一个顶点
        if (start == end) {
            JOptionPane.showMessageDialog(null, "请你不要输入相同的顶点");
            return;
        }
        //开始查找最短路径
        //下面的二元数组用来保存好路径
        boolean[][] path = new boolean[vex_num][vex_num];
        int currentVex = 0;
        showArea.append("现在开始利用BFS查找从" + start + "顶点到" + end + "顶点的最短路径:\n");
        //v点尚未访问
        visited[start - 1] = true;
        showArea.append("访问" + start + "顶点;\n");
        queue.add(new Integer(start - 1)); //加入队列中
        showArea.append("把" + start + "顶点加入队列中;\n");
        while (!queue.isEmpty()) {
            currentVex = ((Integer) queue.get(0)).intValue(); //得到队头元素
            queue.remove(queue.remove(0)); //队头元素出队列
            showArea.append((currentVex + 1) + "顶点出队列;\n");
            showArea.append("访问" + (currentVex + 1) + "顶点的邻接点 ;\n");
            for (int adjVex = 0; adjVex < vex_num; adjVex++) { //访问它的邻接点
                if (!visited[adjVex] &&
                    adjMatrix[currentVex][adjVex] != 0) {
                    path[currentVex][adjVex] = true; //存储路径
                    showArea.append("访问" + (adjVex + 1) + "顶点;\n");
                    visited[adjVex] = true; //标志已经访问此顶点
                    if (adjVex == end - 1) {
                        showArea.append("找到了" + end + "顶点;\n");
                        path(showArea, path, start, end); //把路径找出来
                        return;
                    }
                    showArea.append("把" + (adjVex + 1) + "顶点加入队列中;\n");
                    queue.add(new Integer(adjVex)); //把它压入队列中
                } //if
            } //for
        } //while
        //他们之间不存在路径,输出路径不存在
        showArea.append((currentVex + 1) + "顶点没有邻接点,BFS访问停止.\n");
        showArea.append("他们之间不存在路径!!!\n");
        JOptionPane.showMessageDialog(null, "他们之间相隔千山万水,永无重逢之日!!!");
    }

    private void path(JTextArea showArea, boolean path[][], int start,
                      int end) {
        int node = end - 1;
        int length = 0; //用来保存路径的长度;
        Vector pathNode = new Vector(); //用向量来保存路径;当作堆栈用。
        for (int i = 0; i < vex_num; i++) {
            if (path[i][node]) {
                pathNode.add(new Integer(i)); //压入堆栈
                node = i; //反方向逆回,找到上一个顶点
                length++;
                i = -1; //把扫描哨归零,但考虑到for会自动地加一。故回到-1
            }
            if (node == start - 1) {
                break;
            }
        }
        //把路径显示出来
        showArea.append("路径查找成功!!!\n");
        showArea.append("从" + start + "顶点到" + end + "顶点的最短路径长度为:" + length +
                        "\n");
        showArea.append("最短路径经过的节点为:\n");
        for (int i = pathNode.size() - 1; i >= 0; i--) {
            int currentVex = ((Integer) pathNode.get(i)).intValue(); //得到堆栈弹出的元素
            showArea.append((currentVex + 1) + "-->");
        }
        showArea.append(end + ".\n");
        //完成对图的查找后把图归位.
        for (int i = 0; i < vex_num; i++) {
            visited[i] = false;
        }
        queue.removeAllElements();
        queue.clear();
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?