20162311 實驗四-圖的實現與應用 實驗報告

20162311 實驗四-圖的實現與應用 實驗報告

目錄java

1、圖的實現與應用-1

(一) 實驗目的

(二) 實驗過程

1.建立VertexNode類和TripleEdge

這兩個類分別表示圖的頂點和邊。VertexNode類包含一個int類型變量key,表示頂點序號,T類型變量element,表示該頂點儲存的元素。TripleEdge類包含一個int類型變量isExist,表示這條邊是否存在,爲0時不存在,爲1時不存在;一個int類型變量weight,表示邊的權重,初始默認爲1。爲何不加上邊的開始頂點和結束頂點的序號呢?這個問題在後面解釋測試

2.建立MatrixGraph

方法實現this

構造方法

首先咱們用Arraylist來保存頂點,用一個二維數組matrix來保存邊,這裏解釋下以前的爲何不加上邊的開始頂點和結束頂點的序號,由於matrix[i][j]就表示序號爲i的點到序號爲j的點之間的邊,由於是無向圖,因此在添加matrix[i][j]的同時也要添加matrix[j][i],這個在以後的實現insertEdge()方法時會再講。而後構造函數先實例化ArrayList和二維數組,數組大小先暫定50spa

//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 += "\n";
        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 += "\n";
        }
        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、圖的實現與應用-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 = "頂點         以該頂點爲弧尾的邊\n";
        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 += "\n";
        }
        return result;
    }

返回

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

看似難,其實很簡單。和鄰接矩陣實現的原理同樣,只不過它得到與頂點相連的邊的方式不一樣,也就是把if和for循環的一些條件改一改就好了,代碼比較多,就不貼出來了,能夠在後面的代碼連接裏看

返回

3.測試截圖

(三) 代碼連接

返回目錄

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);
        }
    }

返回

測試截圖

第一個圖是以前作的,只打印出了最小費用的矩陣,因此雲班課裏之提交了這個。後來補充完整了,加上了最短路徑,後面的圖是測試結果

(三) 代碼連接

返回目錄

4、遇到的問題和解決辦法

我感受本次實驗比較特殊,由於前面的數據結構實驗,書上都有代碼,本身只需補充幾個方法就好,但此次基本全是本身寫,因此遇到的問題也比較多。由於有不少問題,有大也有小,並且不少是相互關聯的,因此我以爲單獨寫出來不是很好主要是當時遇到太多問題,只想着解決,沒有記下來,其實大部分我遇到的問題和解決辦法,在寫實驗過程的時候也或多或少嵌入進去了,因此這裏就不單獨寫了。

返回目錄

5、總結

此次實驗主要是本身用代碼實現圖。前一週課上講的理論知識,都理解了,並且課上的測試,本身畫出幾種圖,也都沒問題,但真正到了本身實現的時候才發現沒有那麼簡單。有不少嘴上說的容易的實現起來卻要考慮不少細節。因此,實踐是真的很重要,本身動手實踐才能更深入的理解理論。

返回目錄

6、參考資料

除了Floyd算法找了資料之外,其它兩個實驗原本也想去網上找找資料,可是我看的他們的代碼都是比較總體,頂點類、邊類、圖類是一體的,只能一塊兒照搬,而我又本身定義了頂點類和邊類,很難經過修改網上的代碼來適應本身的代碼,因此就沒有再找資料了。除了老師給的PPT之外,沒有再參考其它的資料

返回目錄

相關文章
相關標籤/搜索