20162307 实验四 图的实现与应用

20162307 实验四 图的实现与应用

北京电子科技学院(BESTI)

实 验 报 告

课程:程序设计与数据结构

班级:1623

姓名:张韵琪

学号:20162307

指导教师:娄嘉鹏老师、王志强老师

实验日期:2017年11月15号

实验密级:非密级

实验时间:五天

必修/选修:必修

实验名称:图的实现与应用

实验仪器:电脑

实验目的与要求:

  • 目的:

     学习查找与排序的应用,实现和分析
    
  • 要求:
    1.没有Linux基础的同学建议先学习《Linux基础入门(新版)》《Vim编辑器》 课程
    2.完成实验、撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等)、解决办法(空洞的方法如“查网络”、“问同学”、“看书”等一律得0分)以及分析(从中可以得到什么启示,有什么收获,教训等)。报告可以参考范飞龙老师的指导
    3. 严禁抄袭,有该行为者实验成绩归零,并附加其他惩罚措施。


实验内容、步骤



一、实验要求


用邻接矩阵实现无向图(边和顶点都要保存),实现在包含添加和删除结点的方法,添加和删除边的方法,size(),isEmpty(),广度优先迭代器,深度优先迭代器
给出伪代码,产品代码,测试代码(不少于5条测试)


一、实验步骤


  • 1.邻接矩阵
    边的存储方案沿袭于树的树组实现方式,将一维数组替换为二维数组,这里称为邻接矩阵
  • 2.无向图
    在无向图中,边是双向的。
  • 3.用邻接矩阵实现无向图(边和顶点都要保存),实现在包含添加和删除结点的方法,添加和删除边的方法

 public AbstractGraph() {
        //初始化矩阵,一维数组,和边的数目
        int n = 0;
        edges = new int[n][n];
        vertexList = new ArrayList ( n );
        numOfEdges = 0;
    }

    //得到结点的个数
    public int getNumOfVertex() {
        return vertexList.size ();
    }

    //得到边的数目
    public int getNumOfEdges() {
        return numOfEdges;
    }

    //返回结点i的数据
    public Object getValueByIndex(int i) {
        return vertexList.get ( i );
    }

    //返回v1,v2的权值
    public int getWeight(int v1, int v2) {
        return edges[v1][v2];
    }

    //插入结点
    public void insertVertex(Object vertex) {
        vertexList.add ( vertex );
    }

    //插入边
    public void insertEdge(int v1, int v2, int weight) {
        edges[v1][v2] = weight;
        numOfEdges++;
    }

    //删除边
    public void deleteEdge(int v1, int v2) {
        edges[v1][v2] = 0;
        numOfEdges--;
    }

4.size(),isEmpty()方法

 public int size(){
        return seqList.getSize ();
    }


    public boolean isEmpty() {
        Graph <T> node = null;
        if (node == null)
            return false;
        return true;
    }

5.广度优先迭代器,深度优先迭代器

        public void iteratorBFS(int startIndex){
            Deque<Map<String, Object>> nodeDeque = new ArrayDeque<Map<String, Object>>();
                Map<String, Object> node = new HashMap<String, Object>();
            nodeDeque.add(node);
            while (!nodeDeque.isEmpty()) {
                node = nodeDeque.peekFirst();
                System.out.println(node);
                    //获得节点的子节点,对于二叉树就是获得节点的左子结点和右子节点
                List<Map<String, Object>> children = (List <Map <String, Object>>) node;
                if (children != null && !children.isEmpty()) {
                    for (Map child : children) {
                        nodeDeque.add(child);
                    }
                }
            }
        }
        public void iteratorDFS(){
            Stack<Map<String, Object>> nodeStack = new Stack<Map<String, Object>>();
            Map<String, Object> node = new HashMap<String, Object>();
            nodeStack.add(node);
            while (!nodeStack.isEmpty()) {
                node = nodeStack.pop();
                System.out.println(node);
                //获得节点的子节点,对于二叉树就是获得节点的左子结点和右子节点
                List<Map<String, Object>> children = (List <Map <String, Object>>) node;
                if (children != null && !children.isEmpty()) {
                    for (Map child : children) {
                        nodeStack.push(child);
                    }
                }
            }
        }

一、实验结果



二、实验要求


用十字链表实现无向图(边和顶点都要保存),实现在包含添加和删除结点的方法,添加和删除边的方法,size(),isEmpty(),广度优先迭代器,深度优先迭代器
给出伪代码,产品代码,测试代码(不少于5条测试)


二、实验步骤


1.十字链表
把邻接表与逆邻接表结合起来,即有向图的一种存储方法十字链表(Orthogonal List)。

2.对十字链表的理解
入弧表示入边表头指针,指向该顶点的入边表中第一个结点;
出弧表示出边表头指针,指向该顶点的出边表中第一个结点;
弧尾是指弧起点在顶点的下标,
弧头是指弧终点在顶点表中的下标,
同弧头是指入边表指针域,指向终点相同的下一条边
同弧尾是指出边表指针域,指向起点相同的下一条边。
如果是网,还可以再增加一个weight域来存储权值。

  1. 用十字链表实现无向图(边和顶点都要保存),实现在包含添加和删除结点的方法,添加和删除边的方法

public static void insertEdge(Edge <Integer> edge, List <Vertex <Integer, Integer>> vertexList) {
        int fromVertexIndex = edge.fromVertexIndex;
        int toVertexIndex = edge.toVertexIndex;
        Vertex <Integer, Integer> fromVertex = vertexList.get ( fromVertexIndex );
        Vertex <Integer, Integer> toVertex = vertexList.get ( toVertexIndex );

        if (fromVertex.firstOut == null) {
            //插入到顶点的出边属性
            fromVertex.firstOut = edge;
        } else {
            // 插入到edge的nextSameFromVertex属性
            Edge <Integer> tempEdge = fromVertex.firstOut;
            //找到最后一个Edge
            while (tempEdge.nextSameFromVertex != null) {
                tempEdge = tempEdge.nextSameFromVertex;
            }
            tempEdge.nextSameFromVertex = edge;
        }
        if (toVertex.firstIn == null) {
            //插入到顶点的入边属性
            toVertex.firstIn = edge;
        } else {
            // 插入到edge的nextSameToVertex属性
            Edge <Integer> tempEdge = toVertex.firstIn;
            //找到最后一个Edge
            while (tempEdge.nextSameToVertex != null) {
                tempEdge = tempEdge.nextSameToVertex;
            }
            tempEdge.nextSameToVertex = edge;
        }
    }

    public void removeVertex(List <Vertex <Integer, Integer>> vertexList){
        if (!isEmpty ()){
            for (int index=0;index<vertexList.size();index++){
                vertexList.remove ( index );
            }

            }

    }

    public void removeEdge(Edge<Integer> edge){
        if (!isEmpty ()){
            edgeCollection.remove ( edge );
        }

    }

4.size(),isEmpty()


public boolean isEmpty() {
        ArrayList <Vertex <Integer, Integer>> vertexList = new ArrayList <> ();
        vertexList = null;
        if (vertexList == null)
            return true;
        return false;
    }

public int size() {
        Edge <Integer> edge = null;
        List <Vertex <Integer, Integer>> vertexList = null;
        int fromVertexIndex = edge.fromVertexIndex;
        int toVertexIndex = edge.toVertexIndex;
        Vertex <Integer, Integer> fromVertex = vertexList.get ( fromVertexIndex );
        Vertex <Integer, Integer> toVertex = vertexList.get ( toVertexIndex );
        if (edge != null && fromVertex != null && toVertex != null)
            return vertexList.size ();

        return vertexList.size ();
    }

5.广度优先迭代器,深度优先迭代器


    public Iterator<T> iteratorBFS(int startIndex){            //广度优先遍历
            int currentVertex;
            LinkedQueue<Integer> traversalQueue = new LinkedQueue <Integer> ();
            ArrayIterator<T> iter =new ArrayIterator <T> ();
            if (!indexIsValid(startIndex)){
                return iter;
            }
            boolean[] visited =new boolean[numVertices];
            for (int vertexIndex=0;vertexIndex<numVertices;vertexIndex++)
                visited[vertexIndex]=false;traversalQueue.enqueue ( startIndex );
                visited[startIndex]=true;            
                while (!traversalQueue.isEmpty ()){
                    currentVertex=traversalQueue.dequeue ();
                    iter.add (vertices[currentVertex]);
                    for(int vertexIndex=0;vertexIndex<numVertices;vertexIndex++)
                        if (adjMatrix[currentVertex][vertexIndex]&&!visited[vertexIndex]){
                        traversalQueue.enqueue ( vertexIndex );
                        visited[vertexIndex]=true;                    
                    }
            }
                return iter;
        }

 public Iterator<T> iteratorDFS(int startIndex){            //广度优先遍历
            int currentVertex;
            LinkedStack<Integer> traversalStack = new LinkedStack <Integer> ();
            ArrayIterator<T> iter =new ArrayIterator <T> ();
            boolean[] visited=new boolean[numVertices];
            boolean found;

            if (!indexIsValid(startIndex)){
                return iter;
            }
            for(int vertexIdx = 0;vertexIdx<numVertices; vertexIdx++){
               visited[vertexIdx] =false;
            }
            traversalStack.push(startIndex);
            iter.add(vertices[startIndex]);
            visited[startIndex]=true;
            
                while (!traversalStack.isEmpty ()){
                    currentVertex=traversalStack.peek ();
                    found=false;
                    for(int vertexIdx=0; vertexIdx <numVertices&&!found; vertexIdx ++)
                        if (adjMatrix[currentVertex][vertexIdx]&&!visited[vertexIdx]){
                        traversalStack.push ( vertexIdx );
                        iter.add(vertices[vertexIdx]);
                        visited[vertexIdx]=true;
                        found=true;                    
                    }
                if(!found&&! traversalStack.isEmpty())
                        traversalStack.pop();
            }
                return iter;
        }


二、实验结果



三、实验要求


实现PP19.9

给出伪代码,产品代码,测试代码(不少于5条测试)


三、实验步骤


19.9
创建计算机网络路由系统
输入网路中点到点的线路
以及每条线路使用的费用
系统输出网络中各点之间最便宜的路径
指出不相同的所有位置


public class RoutingSystem {

    private class Vertex {
        private String vertexLabel;         //顶点标识
        private List <Edge> adjEdges;       //与该顶点邻接的边(点)
        private int dist;                   //顶点间距离
        private Vertex preNode;

        public Vertex(String vertexLabel) {
            this.vertexLabel = vertexLabel;
            adjEdges = new LinkedList <> ();
            dist = Integer.MAX_VALUE;
            preNode = null;
        }
    }

    private class Edge {
        private Vertex endVertex;

        public Edge(Vertex endVertex) {
            this.endVertex = endVertex;
        }
    }

    private Map <String, Vertex> nonDirectedGraph;
    private Vertex startVertex;//图的起始顶点

    public RoutingSystem(String graphContent) {
        nonDirectedGraph = new LinkedHashMap <> ();
        buildGraph ( graphContent );
    }

    private void buildGraph(String graphContent) {
        String[] lines = graphContent.split ( "\n" );

        String startNodeLabel, endNodeLabel;
        Vertex startNode, endNode;
        for (int i = 0; i < lines.length; i++) {
            String[] nodesInfo = lines[i].split ( "," );
            startNodeLabel = nodesInfo[1];
            endNodeLabel = nodesInfo[2];

            endNode = nonDirectedGraph.get ( endNodeLabel );
            if (endNode == null) {
                endNode = new Vertex ( endNodeLabel );
                nonDirectedGraph.put ( endNodeLabel, endNode );
            }

            startNode = nonDirectedGraph.get ( startNodeLabel );
            if (startNode == null) {
                startNode = new Vertex ( startNodeLabel );
                nonDirectedGraph.put ( startNodeLabel, startNode );
            }
            Edge e = new Edge ( endNode );
            //对于无向图而言,起点和终点都要添加边
            endNode.adjEdges.add ( e );
            startNode.adjEdges.add ( e );
        }
        startVertex = nonDirectedGraph.get ( lines[0].split ( "," )[1] );//总是以文件中第一行第二列的那个标识顶点作为源点
    }

    public void unweightedShortestPath() {
        unweightedShortestPath ( startVertex );
    }


    /*
     * 计算源点s到无向图中各个顶点的最短路径
     * 需要一个队列来保存图中的顶点,初始时,源点入队列,然后以广度的形式向外扩散求解其他顶点的最短路径
     */
    private void unweightedShortestPath(Vertex s) {
        //初始化
        Queue <Vertex> queue = new LinkedList <> ();
        s.dist = 0;
        queue.offer ( s );//将源点dist设置为0并入队列

        while (!queue.isEmpty ()) {
            Vertex v = queue.poll ();
            for (Edge e : v.adjEdges) {//扫描v的邻接边(点)
                if (e.endVertex.dist == Integer.MAX_VALUE) {//如果这个顶点(e.endVertex)未被访问(每个顶点只会入队列一次)
                    e.endVertex.dist = v.dist + 1;//更新该顶点到源点的距离
                    queue.offer ( e.endVertex );
                    e.endVertex.preNode = v;//设置该顶点的前驱顶点
                }//end if
            }//end for
        }//end while
    }

    //http://www.cnblogs.com/jmzz/archive/2011/09/26/2190722.html
 /*   public static int[] Dijsktra(int[][] weight,int start){
        //接受一个有向图的权重矩阵,和一个起点编号start(从0编号,顶点存在数组中)
        //返回一个int[] 数组,表示从start到它的最短路径长度
        String graphFilePath;
        graphFilePath = "/Users/zhangyunqi/Desktop/zyq.txt" ;
        String graphContent = FileUtil.read(graphFilePath, null);
        int n = graphContent.length ();      //顶点个数
        int[] shortPath = new int[n];   //存放从start到其他各点的最短路径
        int[] visited = new int[n];     //标记当前该顶点的最短路径是否已经求出,1表示已求出

        //初始化,第一个顶点求出
        shortPath[start] = 0;
        visited[start] = 1;

        for(int count = 1;count <= n - 1;count++)        //要加入n-1个顶点
        {
            int k = -1; //选出一个距离初始顶点start最近的未标记顶点
            int dmin = 1000;
            for(int i = 0;i < n;i++)
            {
                if(visited[i] == 0 && weight[start][i] < dmin)
                {
                    dmin = weight[start][i];
                    k = i;
                }
            }

            //将新选出的顶点标记为已求出最短路径,且到start的最短路径就是dmin
            shortPath[k] = dmin;
            visited[k] = 1;

            //以k为中间点想,修正从start到未访问各点的距离
            for(int i = 0;i < n;i++)
            {
                if(visited[i] == 0 && weight[start][k] + weight[k][i] < weight[start][i])
                    weight[start][i] = weight[start][k] + weight[k][i];
            }

        }

        return shortPath;
    }
*/
    //打印图中所有顶点到源点的距离及路径
    public void showDistance() {
        Collection <Vertex> vertexs = nonDirectedGraph.values ();
        for (Vertex vertex : vertexs) {
            System.out.print ( vertex.vertexLabel + "<--" );
            Vertex tmpPreNode = vertex.preNode;
            while (tmpPreNode != null) {
                System.out.print ( tmpPreNode.vertexLabel + "<--" );
                tmpPreNode = tmpPreNode.preNode;
            }
            String graphFilePath;
            graphFilePath = "/Users/zhangyunqi/Desktop/zyq.txt";
            String graphContent = FileUtil.read ( graphFilePath, null );
            System.out.println ( "两者之间的距离=" + vertex.dist );


        }
    }
}


三、实验结果


posted @ 2017-11-26 20:12  张韵琪  阅读(484)  评论(0编辑  收藏  举报