zoukankan      html  css  js  c++  java
  • 20162311 实验四-图的实现与应用 实验报告

    20162311 实验四-图的实现与应用 实验报告

    目录

    一、图的实现与应用-1

    (一) 实验目的

    (二) 实验过程

    1.创建VertexNode类和TripleEdge

    这两个类分别表示图的顶点和边。VertexNode类包含一个int类型变量key,表示顶点序号,T类型变量element,表示该顶点储存的元素。TripleEdge类包含一个int类型变量isExist,表示这条边是否存在,为0时不存在,为1时不存在;一个int类型变量weight,表示边的权重,初始默认为1。为什么不加上边的开始顶点和结束顶点的序号呢?这个问题在后面解释

    2.创建MatrixGraph

    方法实现

    构造方法

    首先我们用Arraylist来保存顶点,用一个二维数组matrix来保存边,这里解释下之前的为什么不加上边的开始顶点和结束顶点的序号,因为matrix[i][j]就表示序号为i的点到序号为j的点之间的边,因为是无向图,所以在添加matrix[i][j]的同时也要添加matrix[j][i],这个在之后的实现insertEdge()方法时会再讲。然后构造函数先实例化ArrayList和二维数组,数组大小先暂定50

     //count变量表示图中顶点的个数
        private int count, max;
    
        //表示邻接矩阵的二维数组的初始大小
        private final int SIZE = 50;
    
        //保存顶点结点
        private ArrayList<VertexNode<T>> vertexList;
    
        //用二维数组表示邻接矩阵
        private  TripleEdge matrix[][];
    
        //构造函数,初始化保存顶点的列表和表示邻接矩阵的二位数组
        public MatrixGraph()
        {
            vertexList = new ArrayList<>();
            matrix = new TripleEdge[SIZE][SIZE];
        }
    
    

    返回

    size()和isEmpty()方法

    然后先实现最简单的size()和isEmpty()方法,这个就不多解释了

     //返回图中顶点个数
        public int size()
        {
            return count;
        }
    
        //返回图是否为空
        public boolean isEmpty()
        {
            return (count == 0);
        }
    

    返回

    addVertex(int index,T x)方法
     //添加顶点,index为顺序下标,x为结点元素
        public void addVertex(int index,T x)
        {
            vertexList.add(new VertexNode<>(index,x));
            count++;
            if(index>=max)
               max=index+1;
            if(matrix.length == index)
                expandCapacity();
    
            for(int i = 0; i< max; i++)
            {
                if(!(getVertex(i)==null))
                {
                    matrix[index][i] = new TripleEdge();
                    matrix[i][index] = new TripleEdge();
                }
            }
        }
    

    解释一下上面的代码。传入顶点下标和顶点元素,将其加入vertexlList中,其中有一个max的整型变量,有很重要的作用,和count不同,count在删除顶点时会自减1,而max不会。设置这个max变量也是为了实现后面的方法能够更方便。同时也不是每次都自加1,而是当index>=max时把index加1的值赋给max(因为index从0开始,而max是从1开始)。我这里总体说一下我的构想。假设我们初始化下面这样一个二维数组来表示邻接矩阵,初始长度为50,那么初始化的时候每个元素都是null,表明此时图为空,对应的顶点也为空

    接下来我们添加元素,添加第一个元素时,把二维数组matrix[0][0]初始化为new TripleEdge(),就表明下标为0的顶点已经存在了,而此时matrix[0][0]的isExist是0,代表从0到0的边不存在。然后再添加一个顶点也是类似的,添加序号为i的顶点,那么相应的矩阵的第i行和第i列都要置为new TripleEdge()。如果要删除顶点,假设删除顶点的下标为i,那么矩阵的第i行和第i列元素都置为null,这样与之相关的边也删除了。总的来说,每个matrix中的元素都有三种状态(不考虑权重,下同),null表示边和相应的顶点都不存在,0表示顶点存在但是边不存在,1表示两个都存在。接下来我们假设0~4的顶点都添加好了,也添加了一些边,此时的max就是5,如果删去下标为2的顶点,max还是5,此时要再次添加下标为2的顶点,那么max还是5,但如果添加的元素下标是7呢?那此时max就变成8了。我把max理解为我们有效利用二维数组的最大长度。因为当max为5时,后面的行和列都是null,相当于不存在,没有用到。那当我们添加的顶点下标大于50怎么办?,那就要扩容

     //对二维数组扩容
        private void expandCapacity()
        {
            TripleEdge larger[][] = new TripleEdge[matrix.length*2][matrix.length*2];
    
            for(int i=0;i<matrix.length;i++)
                for (int j=0;j<matrix.length;j++)
                    larger[i][j] = matrix[i][j];
    
            matrix = larger;
        }
    

    扩容之后有一个for循环,有什么用呢?它的作用是初始化边。比如你添加了下标为2的顶点,那么matrix[0][2]matrix[2][2]和matrix[2][0]matrix[2][2]的元素都要初始化,但也是有条件的,如果这些元素中有的顶点不存在呢?所以加一个if(!(getVertex(i)==null)),这样就可以在其中随意添加和删除顶点了。

    返回

    removeVertex(int i)方法
     //删除下标为index的顶点
        public void removeVertex(int index) throws EmptyCollectionException
        {
            //如果为空,返回异常
            if(isEmpty())
                throw new EmptyCollectionException("graph");
                //如果该顶点不存在,返回异常
            else if(getVertex(index) == null)
                throw new ElementNotFoundException("graph");
            else
            {
                for (int i = 0; i < vertexList.size(); i++)
                    if (vertexList.get(i).getKey() == index)
                        vertexList.remove(i);
                //删除顶点后,把与其相关的边置为null
                for (int i = 0; i < max; i++)
                {
                    matrix[index][i] = null;
                    matrix[i][index] = null;
                }
                count--;
            }
        }
    

    这个比较简单,在vertexList中找到下标为index的元素,将其删除,然后把与之相关的边置为null,这里的循环就要用到max了。大家可以自己画个矩阵看看为什么是max

    返回

    insertEdge(int startIndex, int endIndex)方法
     //添加从下标为startIndex到下标为endIndex的顶点之间的边
        public void insertEdge(int startIndex, int endIndex)
        {
            matrix[startIndex][endIndex] = new TripleEdge(1);
            matrix[endIndex][startIndex] = new TripleEdge(1);
        }
    

    这里直接把相应的边初始化,把isExist变量设置为1,就代表边存在了。这里为什么不扩容呢?因为添加边之前肯定要先添加相应的顶点的,而在添加顶点的时候就已经扩容了(如果有必要的话),所以在这里就不需要了

    //添加带有权重的边
        public void insertEdge(int startIndex, int endIndex, int weight)
        {
            matrix[startIndex][endIndex] = new TripleEdge(1,weight);
            matrix[endIndex][startIndex] = new TripleEdge(1,weight);
        }
    

    我还顺便实现了一个添加带有权重的边,不过这个实验用不到,就不多说了

    返回

    removeEdge(int startIndex, int endIndex)方法
     //删除下标为startIndex到下标为endIndex的顶点之间的边
        public void removeEdge(int startIndex, int endIndex)
        {
            if((matrix[startIndex][endIndex] == null)||
                    (matrix[startIndex][endIndex].getIsExist() == 0))
            {
                System.out.println("This edge isn't exist!");
            }
            else
            {
                matrix[startIndex][endIndex] = new TripleEdge();
                matrix[endIndex][startIndex] = new TripleEdge();
            }
        }
    

    删除的话就把相应的边的isExist置为0,即重新初始化。

    返回

    toString()方法
    //返回图的邻接矩阵表示
        public String toString()
        {
            String result ="顶点下标 ";
            for(int i=0;i<max;i++)
                if(!(matrix[i][i] == null))
                    result += i+" ";
    
            result += "
    ";
            for (int i=0;i<max;i++)
            {
                if(!(matrix[i][i]==null))
                    result += "       "+i+" ";
    
                for (int j = 0; j < max; j++)
                {
                    TripleEdge edge = matrix[i][j];
                    if (!(edge == null))
                        result += edge.getIsExist()*edge.getWeight()+ " ";
                }
                if (!(matrix[i][max-1] == null))
                    result += "
    ";
            }
            return result;
        }
    

    把邻接矩阵打印出来,遇到为null的不打印,不为null的获取它的isExist*weight的值,我们这里weight默认为1,没什么影响。

    返回

    iteratorBFS(int startIndex)方法
    //返回无向图的广度优先迭代器
        public Iterator<T> iteratorBFS(int startIndex)
        {
            int currentVertex;
            LinkedQueue<Integer> traversalQueue = new LinkedQueue<>();
            ArrayIterator<T> iter = new ArrayIterator<>();
            if(!indexIsValid(startIndex))
                return iter;
    
            boolean visited[] = new boolean[max];
            for(int i=0;i<max;i++)
                visited[i] = false;
    
            traversalQueue.enqueue(startIndex);
            visited[startIndex] = true;
    
            while(!traversalQueue.isEmpty()){
                currentVertex = traversalQueue.dequeue();
                iter.add(getVertex(currentVertex).getElement());
                for (int i=0;i<max;i++)
                    if(!(matrix[currentVertex][i] == null))
                        if(!visited[i]&&
                                (matrix[currentVertex][i].getIsExist()==1))
                        {
                            traversalQueue.enqueue(i);
                            visited[i] = true;
                        }
            }
    
            return iter;
        }
    

    算法书上已经讲过了,就是按照书上的来,只不过一些if的条件和循环的条件改成了与我写的代码相适应的条件,原理是一样的。其中indexIsValid方法是自己实现的

    //判断下标是否有效
        private boolean indexIsValid(int index)
        {
            boolean valid = false;
            for(int i=0;i<vertexList.size();i++)
                if(vertexList.get(i).getKey()==index)
                    valid = true;
    
            return valid;
        }
    

    返回

    iteratorDFS(int startIndex)方法
    //返回无向图的深度优先迭代器
        public Iterator<T> iteratorDFS(int startIndex)
        {
            int currentVertex;
            LinkedStack<Integer> traversalStack = new LinkedStack<>();
            ArrayIterator<T> iter = new ArrayIterator<>();
            boolean visited[] = new boolean[max];
            boolean found;
    
            if(!indexIsValid(startIndex))
                return iter;
    
            for(int i=0;i<max;i++)
                visited[i] = false;
    
            iter.add(getVertex(startIndex).getElement());
            visited[startIndex] = true;
    
            while (!(iter.size() == count))
            {
                traversalStack.push(startIndex);
                while (!traversalStack.isEmpty())
                {
                    currentVertex = traversalStack.peek();
                    found = false;
                    for (int i = 0; i < max && !found; i++)
                    {
                        if (!(matrix[currentVertex][i]==null)&&
                                (matrix[currentVertex][i].getIsExist() == 1) && !visited[i])
                        {
                            traversalStack.push(i);
                            iter.add(getVertex(i).getElement());
                            visited[i] = true;
                            found = true;
                        }
                        if (!found && !traversalStack.isEmpty())
                        {
                            traversalStack.pop();
                        }
                    }
                }
            }
            return iter;
        }
    

    深度优先同广度优先,也是稍微修改一下书上的代码即可。

    返回

    getVertex和getEdge方法

    在MatrixGraph中我还实现了getVertex和getEdge方法,用来获得顶点和边,比较简单,是用来辅助其他方法实现的

    //返回下标为index的顶点,如果图为空,返回EmptyCollectionException
        public VertexNode<T> getVertex(int index) throws EmptyCollectionException
        {
            if(isEmpty())
                throw  new EmptyCollectionException("graph");
    
            VertexNode<T> result = null;
            for (int i=0;i<vertexList.size();i++)
            {
                if(vertexList.get(i).getKey()==index)
                {
                    result = vertexList.get(i);
                }
    
            }
            return result;
        }
    
     //返回下标为startIndex到下标为endIndex的顶点之间的边
        public TripleEdge getEdge(int startIndex, int endIndex)
        {
            return matrix[startIndex][endIndex];
        }
    

    返回

    测试截图

    (三) 代码链接

    返回目录

    二、图的实现与应用-2

    (一) 实验目的

    (二) 实验过程

    1.创建LinkedVertex类和LinkedEdge类

    改用十字链表实现无向图,那么顶点类和边类就要重新定义了。按照上图来重新定义,首先是LinkedVertex类。包含顶点下标,顶点元素,入弧和出弧

    package ExpFour;
    
    /**
     * Created by Administrator on 2017/11/22.
     */
    public class LinkedVertex<T>
    {
        private int key;
        private T element;
        private LinkedEdge<T> in, out;
    
        public LinkedVertex(int key,T element)
        {
            this.key = key;
            this.element = element;
            in = null;
            out = null;
        }
    
        public int getKey()
        {
            return key;
        }
    
        public void setKey(int key)
        {
            this.key = key;
        }
    
        public T getElement()
        {
            return element;
        }
    
        public void setElement(T element)
        {
            this.element = element;
        }
    
        public LinkedEdge<T> getIn()
        {
            return in;
        }
    
        public void setIn(LinkedEdge<T> in)
        {
            this.in = in;
        }
    
        public LinkedEdge<T> getOut()
        {
            return out;
        }
    
        public void setOut(LinkedEdge<T> out)
        {
            this.out = out;
        }
    
        public String toString()
        {
            return "("+key+","+element+")";
        }
    }
    
    

    然后是LinkedEdge类,包含弧尾下标,弧头下标,同弧头和同弧尾

    package ExpFour;
    
    /**
     * Created by Administrator on 2017/11/22.
     */
    public class LinkedEdge<T>
    {
        private int headIdx, tailIdx;
        private LinkedEdge<T> sameHead, sameTail;
    
        public LinkedEdge(int tailIdx,int headIdx)
        {
            this.tailIdx = tailIdx;
            this.headIdx = headIdx;
            sameHead = null;
            sameTail = null;
        }
    
        public LinkedEdge<T> getSameHead()
        {
            return sameHead;
        }
    
        public int getHeadIdx()
        {
            return headIdx;
        }
    
        public void setHeadIdx(int headIdx)
        {
            this.headIdx = headIdx;
        }
    
        public int getTailIdx()
        {
            return tailIdx;
        }
    
        public void setTailIdx(int tailIdx)
        {
            this.tailIdx = tailIdx;
        }
    
        public void setSameHead(LinkedEdge<T> sameHead)
        {
            this.sameHead = sameHead;
        }
    
        public LinkedEdge<T> getSameTail()
        {
            return sameTail;
        }
    
        public void setSameTail(LinkedEdge<T> sameTail)
        {
            this.sameTail = sameTail;
        }
    
        public String toString()
        {
            return "( 弧尾序号:"+ tailIdx +",弧头序号:"+ headIdx +")";
        }
    }
    

    2.创建Linkedgraph类

    方法实现

    构造方法、size()和isEmpty()

    这几个比较简单,和之前差不多,就不多说了

    public class LinkedGraph<T>
    {
        private int count;
    
        private ArrayList<LinkedVertex<T>> vertexList;
    
        private ArrayList<LinkedEdge<T>> edgesList;
    
        public LinkedGraph()
        {
            vertexList = new ArrayList<>();
            edgesList = new ArrayList<>();
        }
    
        public int size()
        {
            return count;
        }
    
        public boolean isEmpty()
        {
            return (count == 0);
        }
    

    返回

    addVertex(int index,T x)方法

    这个添加方法比邻接矩阵的简单,直接加到vertexList中即可

        //添加下标为index的顶点
        public void addVertex(int index,T e)
        {
            vertexList.add(new LinkedVertex<>(index,e));
            count++;
        }
    

    返回

    removeVertex(int i)方法

    原理和之前一样,删除顶点的同时要删除相关的边

    //删除下标为index的顶点
        public LinkedVertex<T> removeVertex(int index)
        {
            if(isEmpty())
                throw  new EmptyCollectionException("graph");
    
            LinkedVertex<T> result = null;
            for(int i=0;i<vertexList.size();i++)
                if (vertexList.get(i).getKey() == index)
                    result = vertexList.remove(i);
    
            for(int i=0;i<edgesList.size();i++)
            {
                LinkedEdge<T> edge = edgesList.get(i);
                if((edge.getHeadIdx()==index)||(edge.getTailIdx()==index))
                {
                    edgesList.remove(i);
                    i--;
                }
    
            }
    
            count--;
            return result;
        }
    
    

    在edgesList 中找到弧头序号为index或弧尾序号为index的边,将其删除即可

    返回

    insertEdge(int startIndex, int endIndex)方法

    添加边的方法有些不同,添加边后,要找到对应的弧头和弧尾,使其指向这条边。同时,在edgesList中找与其同弧头或同弧尾的边,如果该边的同弧头或同弧尾为空,就指向这条新插入的边。同时,因为是表示无向图,所以用户在添加i到j的边时还要同时添加j到i的边

     //插入边
        public void insertEdge(int tailIdx,int headIdx)
        {
            LinkedEdge<T> edge = new LinkedEdge<>(tailIdx,headIdx);
    
            if(!edgesList.isEmpty())
            {
                for(int i=0;i<edgesList.size();i++)
                {
                    if((edgesList.get(i).getSameHead()==null)&&
                            (edgesList.get(i).getHeadIdx()==edge.getHeadIdx()))
                            edge.setSameHead(edgesList.get(i));
                    if((edgesList.get(i).getSameTail()==null)&&
                            (edgesList.get(i).getTailIdx()==edge.getTailIdx()))
                            edge.setSameTail(edgesList.get(i));
                }
            }
            edgesList.add(edge);
            for (int i=0;i<vertexList.size();i++)
            {
                LinkedVertex<T> vertex = vertexList.get(i);
                if((vertex.getKey() == headIdx)&&
                        (vertex.getIn()==null))
                {
                    vertex.setIn(edge);
                    vertexList.set(i, vertex);
                }
                if((vertex.getKey() == tailIdx)&&
                        (vertex.getOut()==null))
                {
                    vertex.setOut(edge);
                    vertexList.set(i, vertex);
                }
            }
        }
    

    返回

    removeEdge(int startIndex, int endIndex)方法

    删除边时要同时删除两条,i到j和j到i

     //删除边
        public void removeEdge(int tailIdx,int headIdx)
        {
            for (int i = 0; i < edgesList.size(); i++)
            {
                LinkedEdge<T> edge = edgesList.get(i);
                if (((edge.getTailIdx() == tailIdx) && (edge.getHeadIdx() == headIdx))
                        || ((edge.getTailIdx() == headIdx) && (edge.getHeadIdx() == tailIdx)))
                    edgesList.remove(i);
            }
        }
    

    返回

    toString()方法

    先打印一个顶点,在该顶点后面打印以该顶点为弧尾的边

    //返回图的字符串形式
        public String toString()
        {
            String result = "顶点         以该顶点为弧尾的边
    ";
            for(int i=0;i<count;i++)
            {
                LinkedVertex<T> vertex = vertexList.get(i);
                result += vertex.toString()+"   ";
                for(int j=0;j<edgesList.size();j++)
                {
                    LinkedEdge<T> edge = edgesList.get(j);
                    if(vertex.getKey() == edge.getTailIdx())
                    {
                        result += edge.toString()+" ";
                    }
                }
                result += "
    ";
            }
            return result;
        }
    

    返回

    iteratorBFS(int startIndex)方法和iteratorDFS(int startIndex)方法

    看似难,其实很简单。和邻接矩阵实现的原理一样,只不过它获得与顶点相连的边的方式不同,也就是把if和for循环的一些条件改一改就行了,代码比较多,就不贴出来了,可以在后面的代码链接里看

    返回

    3.测试截图

    (三) 代码链接

    返回目录

    三、图的实现与应用-3

    (一) 实验目的

    (二) 实验过程

    1.分析

    其实这是一个最短路径的问题,图类可以不用写了,因为之前已经写好了,而且在邻接矩阵实现的图里我实现了一个添加带权重的边的方法,所以我只需在MatrixGraph类中实现一个获得最短路径的方法就行了。核心算法是Floyd算法,接下来的代码实现都是在MatrixGraph类的基础上做的

    2.方法实现

    其实老师在课上讲的我并没有完全理解,所以课后我又到网上查了一下Floyd算法的相关内容和一些代码的实现,通过这些参考才完成这个实验

    目录

    getWeightMatrix()方法

    要用Floyd算法,首先要得到这个图的带权矩阵,这个方法就是实现此功能。我之前在第一个实验里说过,MatrixGraph类里有一个二维数组matrix用来存边,但是如果我们对图进行了删除点的操作,那么这个数组里的一些元素是null,不能直接拿来用,所以我需要稍微改一下。

    public int[][] getWeightMatrix()
        {
            int weight[][] = new int[count][count];
            int a=0;
           for(int i=0;i<max;i++)
           {
               if (!(getVertex(i)==null))
               {
                   int b=0;
                   for (int j=0;j<max;j++)
                   {
                       if (!(getVertex(j)==null))
                       {
                           weight[a][b] = matrix[i][j].getIsExist()*matrix[i][j].getWeight();
                           b++;
                       }
                   }
                   a++;
               }
           }
           return weight;
        }
    

    首先,得到的二维数组是整型,而不是TripleEdge类型;数组的长度是count而不是max或者其它。然后开始循环,对matrix中的元素进行判断,如果它不为null,则把它的isExist*weight得到的值赋给weight[a][b],同时b++;如果matrix中的元素为空,则直接跳过,不进行任何操作,a、b也不会自加1,最终得到的weight就是图的带权二维数组

    返回

    floyd()方法

    这个是最主要的方法,可以得到最短路径和最小权值的矩阵(用数组储存)。用二位数组length存储从i点到j点的最小权重(在这个实验里是最小费用),path是一个三维数组,path[i][j][]中储存从i点到j点经过的顶点,因为可能不止一个,所以也用数组储存。

    1. 我们先初始化路径,刚开始相连的两个顶点之间的距离就是权重,可以不用改,而一个点到它自己的距离是0,所以data[i][j]为0,然后修改不直接相连的两个顶点间的距离即可。本来应该是无限大,但是data是int类型,不好储存无穷大,所以我用100代替。
    2. 然后我们初始化spot和onePath数组,我们假定刚开始任意两个点之间没有中间点,没有路径,所以都初始化为-1。这里说以下onePath数组的作用,它是用来储存某两个点之间的路径的,因为路径是用顶点序号表示的,所以为int类型,假设0到3的最短路径是0,1,3,那么onePath就储存0,1,3,然后把onePath数组赋值给path[0][3][],这样就保存了0到3之间的最短路径。然后初始化lenght数组,其实就是把data数组的数据赋值给它
    3. 通过一个三重循环,找出最小权重,也是利用中间点,如果u到v的距离加上v到w的距离小于u到w的距离,就取小的那个,同时把中间点v存进spot数组
    4. 得到最短路径
        public void floyd()
        {
            int data[][]=getWeightMatrix();
            int MAX = 100;
    
            // 储存中间点
            int[][] spot = new int[count][count];
    
            int [] onePath = new int[count];
    
            length = new int[count][count];
    
            path = new int[count][count][];
    
            // 初始化图中两点间的路径
            for (int i = 0; i < count; i++)
                for (int j = 0; j < count; j++)
                {
                    // 没有路径的两个点之间的路径为默认最大
                    if (data[i][j] == 0)
                        data[i][j] = MAX;
                    if (i == j)
                        data[i][j] = 0;
                }
    
            for (int i = 0; i < count; i++)// 初始化为任意两点之间没有路径
                for (int j = 0; j < count; j++)
                    spot[i][j] = -1;
    
            for (int i = 0; i < count; i++)// 假设任意两点之间的没有路径
                onePath[i] = -1;
    
            for (int v = 0; v < count; v++)
                for (int w = 0; w < count; w++)
                    length[v][w] = data[v][w];
    
            for (int u = 0; u < count; u++)
                for (int v = 0; v < count; v++)
                    for (int w = 0; w < count; w++)
                        // 如果存在更短路径则取更短路径
                        if (length[v][w] > length[v][u] + length[u][w])
                        {
                            length[v][w] = length[v][u] + length[u][w];
                            spot[v][w] = u;// 把经过的点加入
                        }
    
            for (int i = 0; i < count; i++)
            {// 求出所有的路径
                int[] point = new int[1];
                for (int j = 0; j < count; j++)
                {
                    point[0] = 0;
    
                    onePath[point[0]++] = i;
    
                    outputPath(spot, i, j, onePath, point);
    
                    path[i][j] = new int[point[0]];
    
                    for (int s = 0; s < point[0]; s++)
                        path[i][j][s] = onePath[s];
                }
            }
        }
    

    返回

    getMinWeight()和getMinPath()方法

    这两个方法比较简单,直接获取length数组和path数组相应位置的元素就好了

    public int getMinWeight(int startIdx,int endIdx)
        {
            return length[startIdx][endIdx];
        }
    
        public String getMinPath(int startIdx,int endIdx)
        {
            String result = "From " + startIdx + " to " + endIdx + " path is: ";
            for (int k = 0; k < path[startIdx][endIdx].length; k++)
                result += path[startIdx][endIdx][k] + " ";
    
            return result;
        }
    

    返回

    其它辅助方法

    一个private的方法,用来得到路径

    private void outputPath(int[][] spot, int i, int j, int[] onePath, int []point)
        {
            // 输出i// 到j// 的路径的实际代码,point[]记录一条路径的长度
            if (i == j)
                return;
    
            if (spot[i][j] == -1)
                onePath[point[0]++] = j;
            else
                {
                outputPath(spot, i, spot[i][j], onePath, point);
                outputPath(spot, spot[i][j], j, onePath, point);
            }
        }
    

    返回

    测试截图

    第一个图是之前做的,只打印出了最小费用的矩阵,所以云班课里之提交了这个。后来补充完整了,加上了最短路径,后面的图是测试结果

    (三) 代码链接

    返回目录

    四、遇到的问题和解决办法

    我感觉本次实验比较特殊,因为前面的数据结构实验,书上都有代码,自己只需补充几个方法就好,但这次基本全是自己写,所以遇到的问题也比较多。因为有很多问题,有大也有小,而且很多是相互关联的,所以我觉得单独写出来不是很好主要是当时遇到太多问题,只想着解决,没有记下来,其实大部分我遇到的问题和解决办法,在写实验过程的时候也或多或少嵌入进去了,所以这里就不单独写了。

    返回目录

    五、总结

    这次实验主要是自己用代码实现图。前一周课上讲的理论知识,都理解了,而且课上的测试,自己画出几种图,也都没问题,但真正到了自己实现的时候才发现没有那么简单。有很多嘴上说的容易的实现起来却要考虑很多细节。所以,实践是真的很重要,自己动手实践才能更深刻的理解理论。

    返回目录

    六、参考资料

    除了Floyd算法找了资料以外,其它两个实验本来也想去网上找找资料,但是我看的他们的代码都是比较整体,顶点类、边类、图类是一体的,只能一起照搬,而我又自己定义了顶点类和边类,很难通过修改网上的代码来适应自己的代码,所以就没有再找资料了。除了老师给的PPT以外,没有再参考其它的资料

    返回目录

  • 相关阅读:
    第一次作业-编译原理概述
    node 升级版本,指定的版本
    v-show,v-if切换组件echarts显示不全的问题
    js点击特效动画,小人动画
    路由懒加载
    echarts tree 点击动态添加子集实例
    echarts中数据过多加入滚动条,相关属性dataZoom介绍
    解决echarts x轴标签文字过多导致显示不全
    element-ui 单选框点击整个行为选中状态
    Eclipse上Maven环境配置使用
  • 原文地址:https://www.cnblogs.com/-zzr-/p/7896191.html
Copyright © 2011-2022 走看看