符号图

在典型应用中,图都是通过文件或者网页定义的,使用的是字符串而非整数来表示和指代顶点。为了适应这样的应用,我们定义了拥有以下性质的输入格式:

  • 用指定的分隔符来隔开顶点名;
  • 每一行都表示一组边的集合,每一条边都连接着这一行的第一个名称表示的顶点和其他名称所表示的顶点;
  • 顶点总数V和边的总数E都是隐式定义的。

如图所示表示的是一个小型运输系统的模型,其中表示每个顶点的是美国机场的代码,连接它们的边则表示顶点之间的航线。
在这里插入图片描述

API

用符号作为顶点名的图的API:

API功能
SymbolGraph(String filename, String delim)根据filename指定的文件构造图,使用delim来分隔顶点名
boolean contains(String key)key是一个顶点吗
int index(String key)key的索引
String name(int v)索引v的顶点名
Graph G()隐藏的Graph对象

实现

SymbolGraph用到了以下三种数据结构:

  • 一个符号表st,键的类型为String(顶点名),值的类型为int(索引);
  • 一个数组keys[],用作反向索引,保存每个顶点索引所对应的顶点名;
  • 一个Graph对象G,它使用索引来引用图中顶点。

在这里插入图片描述

SymbolGraph会遍历两遍数据来构造以上数据结构,这主要是因为构造Graph对象需要顶点总数V。

测试用例

用最少的边找到一种从一个机场到达另一个机场的方法:
其中符号表用到了SequentialSearchST,无向图用到了Graph,广度优先搜索用到了BreadthFirstPaths

package section4_1;

import section3_1.SequentialSearchST;

public class SymbolGraph {

    private SequentialSearchST<String, Integer> st;
    private String[] keys;
    private Graph G;

    public SymbolGraph(String[] data,String sp) {
        //构造索引
        st = new SequentialSearchST<>();
        int idx = 0;
        while (idx < data.length) {
            String[] a = data[idx].split(sp);
            for (int i = 0;i < a.length;i++) {
                if (!st.contains(a[i])) {
                    st.put(a[i],st.size());
                }
            }
            idx++;
        }

        //反向索引
        keys = new String[st.size()];
        for (String name : st.keys()) {
            keys[st.get(name)] = name;
        }

        //构造图
        G = new Graph(st.size());
        idx = 0;
        while (idx < data.length) {
            String[] a = data[idx].split(sp);
            int v = st.get(a[0]);
            for (int i = 1;i < a.length;i++) {
                G.addEdge(v,st.get(a[i]));
            }
            idx++;
        }
    }

    public boolean contains(String s) {
        return st.contains(s);
    }

    public int index(String s) {
        return st.get(s);
    }

    public String name(int v) {
        return keys[v];
    }

    public Graph G() {
        return G;
    }

    public static void main(String[] args) {

        String[] data = {
                "JFK MCO",
                "ORD DEN",
                "ORD HOU",
                "DFW PHX",
                "JFK ATL",
                "ORD DFW",
                "ORD PHX",
                "ATL HOU",
                "DEN PHX",
                "PHX LAX",
                "JFK ORD",
                "DEN LAS",
                "DFW HOU",
                "ORD ATL",
                "LAS LAX",
                "ATL MCO",
                "HOU MCO",
                "LAS PHX"
        };
        SymbolGraph sg = new SymbolGraph(data," ");
        Graph G = sg.G();

        String source = "JFK";
        if (!sg.contains(source)) {
            System.out.println(source + "not in database.");
            return;
        }
        int s = sg.index(source);
        BreadthFirstPaths bfs = new BreadthFirstPaths(G,s);

        String sink = "LAS";
        if (sg.contains(sink)) {
            int t = sg.index(sink);
            if (bfs.hasPathTo(t)) {
                for (int v : bfs.pathTo(t)) {
                    System.out.println(sg.name(v));
                }
            } else {
                System.out.println("not connected");
            }
        } else {
            System.out.println("not in database.");
        }
    }
}

在这里插入图片描述

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐