20172302 《Java軟件結構與數據結構》第九周學習總結


2018年學習總結博客總目錄:第一週 第二週 第三週 第四周 第五週 第六週 第七週 第八週 第九周
html


教材學習內容總結

第十五章 圖

1.圖:圖(graph)是由一些點(vertex)和這些點之間的連線(edge)所組成的;其中,點一般被成爲"頂點(vertex)",而點與點之間的連線則被成爲"邊"(edge)。git

2.圖的分類:根據邊是否有方向,將圖能夠劃分爲:無向圖和有向圖。
       無向圖是一種邊爲無序結點對的圖。

       有序圖是一種邊爲有序結點對的圖。
算法

3.圖的一些基本概念數組

  • 無向圖
    (1)若是圖中的兩個頂點之間有一條連通邊,則稱這兩個頂點是鄰接的。
    (2)鄰接的頂點有時也互稱爲鄰居。
    (3)連通一個頂點及其自身的邊稱爲自循環(self-loop)。
    (4)若是無向圖擁有最大數目的連通頂點的邊,則認爲這個無向圖是徹底的。對n個頂點的無向圖,要使該該圖爲徹底的,要有n*(n-1)/2條邊。(假設沒有邊是自循環的。)
    (5)路徑是圖的一系列邊,每條邊連通兩個頂點。路徑的長度是該路徑中邊的條數(頂點數減1)。
    (6)若是無向圖的任意兩個頂點之間都存在一條路徑,則認爲這個無向圖是連通的。
    (7)環路是一種首頂點和末頂點相同且沒有重邊的路徑。
    (8)無向樹是一種連通的無環無向圖,其中一個元素被指定爲樹根。
  • 有向圖
    (1)若是有向圖中的任意兩個頂點之間都存在一條路徑,則認爲該有向圖是連通的。

    (2)若是有向圖中沒有環路,且有一條從A到B的邊,則能夠把頂點A排在B的邊以前。這種排列獲得的頂點次序稱爲拓排序。
    (3)有向樹是一種指定了一個元素做爲樹根的有向圖,該圖具備以下屬性:
    ①不存在其它頂點到樹根的鏈接
    ②每一個非樹根元素剛好有一個鏈接
    ③樹根到每一個其它頂點都有一條路徑

4.網絡(Network)
網絡,或稱加權圖(weighted graph),是一種每條邊都帶有權重或代價的圖。
網絡可使無向的,也能夠是有向的。
對於網絡,咱們採用一個三元組來表示每條邊。這個三元組包括起始頂點,終止頂點和權重。對無向網絡來講,起始頂點與終止頂點能夠互換,但對於有向網絡來講,起始頂點與終止頂點不能夠互換,由於每一個有向鏈接上的權重不必定相等。網絡

5.圖算法
(一)遍歷
分兩種:廣度優先遍歷和深度優先遍歷
(1)廣度優先遍歷


第1步:訪問A。
第2步:依次訪問C,D,F。
在訪問了A以後,接下來訪問A的鄰接點。前面已經說過,在本文實現中,頂點ABCDEFG按照順序存儲的,C在"D和F"的前面,所以,先訪問C。再訪問完C以後,再依次訪問D,F。
第3步:依次訪問B,G。
在第2步訪問完C,D,F以後,再依次訪問它們的鄰接點。首先訪問C的鄰接點B,再訪問F的鄰接點G。
第4步:訪問E。
在第3步訪問完B,G以後,再依次訪問它們的鄰接點。只有G有鄰接點E,所以訪問G的鄰接點E。
所以訪問順序是:A -> C -> D -> F -> B -> G -> E
(2)深度優先遍歷

第1步:訪問A。
第2步:訪問(A的鄰接點)C。
在第1步訪問A以後,接下來應該訪問的是A的鄰接點,即"C,D,F"中的一個。但在本文的實現中,頂點ABCDEFG是按照順序存儲,C在"D和F"的前面,所以,先訪問C。
第3步:訪問(C的鄰接點)B。
在第2步訪問C以後,接下來應該訪問C的鄰接點,即"B和D"中一個(A已經被訪問過,就不算在內)。而因爲B在D以前,先訪問B。
第4步:訪問(C的鄰接點)D。
在第3步訪問了C的鄰接點B以後,B沒有未被訪問的鄰接點;所以,返回到訪問C的另外一個鄰接點D。
第5步:訪問(A的鄰接點)F。
前面已經訪問了A,而且訪問完了"A的鄰接點B的全部鄰接點(包括遞歸的鄰接點在內)";所以,此時返回到訪問A的另外一個鄰接點F。
第6步:訪問(F的鄰接點)G。
第7步:訪問(G的鄰接點)E。
所以訪問順序是:A -> C -> B -> D -> F -> G -> E
(二)測試連通性
在一個含n個頂點的圖中,當且僅當對每一個頂點v,從v開始的廣度優先遍歷的resultList大小都是n,則該圖是連通的。
代碼以下:數據結構

public boolean isConnected()
    {
        boolean result = true;
        for(int i=0;i<numVertices;i++){
            int temp=0;
            temp=getSizeOfIterator(this.iteratorBFS(vertices[i]));
            if(temp!=numVertices)
            {
                result = false;
                break;
            }
        }
        return result;
    }
    private int getSizeOfIterator(Iterator iterator) {
        int size = 0;
        while(iterator.hasNext()){
            size++;
            iterator.next();
        }
        return size;
    }

(三)最小生成樹
生成樹是一棵含有圖中全部頂點和部分邊(但可能不是全部邊)的樹。
最小生成樹:其邊的權重總和小於或等於同一個圖中其餘任何一棵生成樹的權重總和。
       算法:任取一個起始結點,將它添加到最小生成樹中。而後,按照權重次序添加到minheap中,接着從minheap中取出最小邊,並將這個邊和那個新頂點添加到最小生成樹中,下一步,咱們往minheap中添加全部含該新頂點且另外一頂點尚不在最小生成樹中的邊。繼續這一過程,直到最小生成樹含有原始圖中的全部頂點(或minheap爲空)時結束。
(四)斷定最短路徑
兩種:兩個頂點之間的最小邊數;兩個頂點之間的最小權重路
(1)最小邊數:利用廣度優先遍歷,遍歷期間對每一個頂點存儲另外兩個記錄:從起始頂點到本頂點的路徑長度,以及在路徑中做爲本結點前驅的那個結點。修改循環:抵達目標頂點時循環便可終止。
(2)最小權重路徑:Dijkstra算法oop

基本思想
經過Dijkstra計算圖G中的最短路徑時,須要指定起點s(即從頂點s開始計算)。
此外,引進兩個集合S和U。S的做用是記錄已求出最短路徑的頂點(以及相應的最短路徑長度),而U則是記錄還未求出最短路徑的頂點(以及該頂點到起點s的距離)。
初始時,S中只有起點s;U中是除s以外的頂點,而且U中頂點的路徑是"起點s到該頂點的路徑"。而後,從U中找出路徑最短的頂點,並將其加入到S中;接着,更新U中的頂點和頂點對應的路徑。 而後,再從U中找出路徑最短的頂點,並將其加入到S中;接着,更新U中的頂點和頂點對應的路徑。 ... 重複該操做,直到遍歷完全部頂點。
操做步驟學習

(1) 初始時,S只包含起點s;U包含除s外的其餘頂點,且U中頂點的距離爲"起點s到該頂點的距離"[例如,U中頂點v的距離爲(s,v)的長度,而後s和v不相鄰,則v的距離爲∞]。測試

(2) 從U中選出"距離最短的頂點k",並將頂點k加入到S中;同時,從U中移除頂點k。this

(3) 更新U中各個頂點到起點s的距離。之因此更新U中頂點的距離,是因爲上一步中肯定了k是求出最短路徑的頂點,從而能夠利用k來更新其它頂點的距離;例如,(s,v)的距離可能大於(s,k)+(k,v)的距離。

(4) 重複步驟(2)和(3),直到遍歷完全部頂點。

初始狀態:S是已計算出最短路徑的頂點集合,U是未計算除最短路徑的頂點的集合!
第1步:將頂點D加入到S中。
此時,S={D(0)}, U={A(∞),B(∞),C(3),E(4),F(∞),G(∞)}。 注:C(3)表示C到起點D的距離是3。
第2步:將頂點C加入到S中。
上一步操做以後,U中頂點C到起點D的距離最短;所以,將C加入到S中,同時更新U中頂點的距離。以頂點F爲例,以前F到D的距離爲∞;可是將C加入到S以後,F到D的距離爲9=(F,C)+(C,D)。
此時,S={D(0),C(3)}, U={A(∞),B(13),E(4),F(9),G(∞)}。
第3步:將頂點E加入到S中。
上一步操做以後,U中頂點E到起點D的距離最短;所以,將E加入到S中,同時更新U中頂點的距離。仍是以頂點F爲例,以前F到D的距離爲9;可是將E加入到S以後,F到D的距離爲6=(F,E)+(E,D)。
此時,S={D(0),C(3),E(4)}, U={A(∞),B(13),F(6),G(12)}。
第4步:將頂點F加入到S中。
此時,S={D(0),C(3),E(4),F(6)}, U={A(22),B(13),G(12)}。
第5步:將頂點G加入到S中。
此時,S={D(0),C(3),E(4),F(6),G(12)}, U={A(22),B(13)}。
第6步:將頂點B加入到S中。
此時,S={D(0),C(3),E(4),F(6),G(12),B(13)}, U={A(22)}。
第7步:將頂點A加入到S中。
此時,S={D(0),C(3),E(4),F(6),G(12),B(13),A(22)}。
此時,起點D到各個頂點的最短距離就計算出來了:A(22) B(13) C(3) D(0) E(4) F(6) G(12)。

參考連接:Dijkstra算法之Java詳解

還有一個動圖,也比較形象

6.圖的實現策略
鄰接列表和鄰接矩陣:第一種是一個列表中元素爲列表,這樣構成的其實也是一個矩陣;第二種是直接用一個二元數組,直接就是一個矩陣。以實現無向圖爲例
(一)鄰接列表
鄰接表,存儲方法跟樹的孩子鏈表示法相相似,是一種順序分配和鏈式分配相結合的存儲結構。如這個表頭結點所對應的頂點存在相鄰頂點,則把相鄰頂點依次存放於表頭結點所指向的單向鏈表中。
(二)鄰接矩陣
邏輯結構分爲兩部分:V和E集合。所以,用一個一維數組存放圖中全部頂點數據;用一個二維數組存放頂點間關係(邊或弧)的數據,這個二維數組稱爲鄰接矩陣。鄰接矩陣又分爲有向圖鄰接矩陣和無向圖鄰接矩陣。

教材學習中的問題和解決過程

  • 問題1:關於拓撲序,書上的敘述很難理解,同時也不清楚它的用處。

  • 問題1解決方案:首先來看拓撲排序定義:

           對一個有向無環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中全部頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊(u,v)∈E(G),則u在線性序列中出如今v以前。一般,這樣的線性序列稱爲知足拓撲次序(Topological Order)的序列,簡稱拓撲序列。簡單的說,由某個集合上的一個偏序獲得該集合上的一個全序,這個操做稱之爲拓撲排序。

注意

①若將圖中頂點按拓撲次序排成一行,則圖中全部的有向邊均是從左指向右的。
②若圖中存在有向環,則不可能使頂點知足拓撲次序。
③一個DAG的拓撲序列一般表示某種方案切實可行。
【例】一本書的做者將書本中的各章節學習做爲頂點,各章節的先學後修關係做爲邊,構成一個有向圖。按有向圖的拓撲次序安排章節,才能保證讀者在學習某章節時,其預備知識已在前面的章節裏介紹過。
④一個DAG可能有多個拓撲序列。
⑤當有向圖中存在有向環時,拓撲序列不存在。


                圖1                   圖2
例如,下面的三個序列都是圖1 的拓撲序列,固然還能夠寫出許多。而圖2中則不會存在拓撲序列。

(1) C1,C8,C9,C2,C3,C5,C4,C7,C6

(2) C2,C1,C3,C5,C4,C6,C8,C9,C7

(3) C1,C2,C3,C8,C9,C5,C4,C6,C7

課程代號      課程名稱        先修課程

       C1          高等數學          無

       C2          程序設計基礎      無

       C3          離散數學          C1,C2

       C4          數據結構          C3,C5

       C5          算法語言          C2

       C6          編譯技術          C4,C5

       C7          操做系統          C4,C9

       C8          普通物理          C1

       C9          計算機原理        C8

例如,假定一個計算機專業的學生必須完成圖3-4所列出的所有課程。在這裏,課程表明活動,學習一門課程就表示進行一項活動,學習每門課程的先決條件是學完它的所有先修課程。如學習《數據結構》課程就必須安排在學完它的兩門先修課程《離散數學》和《算法語言》以後。學習《高等數學》課程則能夠隨時安排,由於它是基礎課程,沒有先修課。若用AOV網來表示這種課程安排的前後關係,則如圖3-5所示。圖中的每一個頂點表明一門課程,每條有向邊表明起點對應的課程是終點對應課程的先修課。圖中的每一個頂點表明一從圖中能夠清楚地看出各課程之間的先修和後續的關係。如課程C5的先修課爲C2,後續課程爲C4和C6。

拓撲序列的實際意義是:若是按照拓撲序列中的頂點次序,在開始每一項活動時,可以保證它的全部前驅活動都已完成,從而使整個工程順序進行,不會出現衝突的狀況。

拓撲排序算法
拓撲排序算法主要是循環執行如下兩步,直到不存在入度爲0的頂點爲止。
(1) 選擇一個入度爲0的頂點並輸出之;
(2) 從網中刪除此頂點及全部出邊。
循環結束後,若輸出的頂點數小於網中的頂點數,則輸出「有迴路」信息,不然輸出的頂點序列就是一種拓撲序列。

代碼調試中的問題和解決過程

  • 問題1:在作做業PP15.1時,即用鄰接表構建圖時,addVertex方法遇到空指針錯誤。

  • 問題1解決方案:一開始構建鄰接表是使用的是兩個列表,頂點元素存於一個列表中,而邊又存於另一個列表中,這樣作後來才知道實際上是作麻煩了,一開始就對鄰接表理解錯了。

    鄰接表,存儲方法跟樹的孩子鏈表示法相相似,是一種順序分配和鏈式分配相結合的存儲結構。如這個表頭結點所對應的頂點存在相鄰頂點,則把相鄰頂點依次存放於表頭結點所指向的單向鏈表中。

上面的錯誤是經過構建一個新的列表,列表當中存儲當前的元素,這樣作完就不會出現空指針錯誤。

vertices.add(vertex);
        List list = new ArrayList();
        list.add(vertex);
        adjMatrix.add(list);
        numVertices++;
        modCount++;

一直到了週五,老師講完鄰接表後,才知道本身這樣作實際上是作麻煩了,徹底沒有必要再去使用存儲頂點的列表了。

代碼託管

       上週代碼行數爲15816行,如今爲18065行,本週2249行。

上週考試錯題總結

未進行考試

結對及互評

  • 本週結對學習狀況
    • 20172308
    • 博客中值得學習的或問題:博客中教材問題寫得比較充實。
    • 結對學習內容:第十五章——圖

其餘(感悟、思考等)

感悟

  • 本週學習過程當中比較難的是Dijkstara算法,這裏僅靠書上的幾行描述是不大好理解的,從網上查閱了一些資料,同時又詢問了王老師,纔在資料的基礎上用兩個集合實現了最小權重路徑的查找,而沒有使用最小堆,用最小堆去實現查找最小權重路線我尚未理解,實現起來可能也比較複雜。
  • 這周還看了一些暑假作了App的同窗的博客,感受你們作的都挺好的。本身暑假時候偷懶,沒有動手去實踐一次,有點後悔了。望下週開始的APP小組開發本身多投入一些,盡力作的好一些,可以追上來。

學習進度條

代碼行數(新增/累積) 博客量(新增/累積) 學習時間(新增/累積) 重要成長
目標 5000行 30篇 400小時
第一週 0/0 1/1 15/15
第二週 572/572 1/2 16/31
第三週 612/1184 1/3 13/44
第四周 1468/2652 2/5 13/57
第五週 1077/3729 1/6 14/71 初步理解各個排序算法
第六週 1087/4816 1/7 17/88 認識樹結構
第七週 1252/6068 1/8 19/107 平衡二叉樹、AVL樹、紅黑樹
第八週 2065/8133 2/10 17/124 堆、最小堆
第九周 2249/10382 1/11 18/142 圖及其實現

參考資料

相關文章
相關標籤/搜索