天天看點

pb代碼graph繪圖表_從零開始學習資料結構>圖之鄰接表

圖的存儲結構:鄰接矩陣 + 鄰接表 2 種形式,不同場景下選用其對應的存儲結構,這次來聊聊鄰接表。 1、稀疏矩陣 有一個稀疏因子,這是節省空間的一種存儲方式。 2、鄰接表 以鄰接矩陣存儲圖結構的話,當實際邊數遠遠小于圖的最大邊數時,将會存儲很多0,勢必造成存儲空間的巨大浪費;這時,就必須将鄰接矩陣該用為鄰接表;将鄰接矩陣各行組織為一個單連結清單,類哈希的存儲結構。 存儲結構(控制頭):

1int maxVertices;  //最大頂點數
 2int curVertices;  //目前頂點數
 3int curEdges;  //目前邊數
 4
 5template<typename Type>
 6class Edge{  //邊的存儲結構
 7public:
 8    Edge(int num) : dest(num), link(NULL){}
 9public:
10    int dest;  //是另一個頂點的下标
11    Edge *link;
12};
13template<typename Type>
14class Vertex{  //頂點的存儲結構
15public:
16    Type data;  //存放的頂點
17    Edge *adj;18};1920Vertex *vertexTable;  //指向頂點的指針,是申請數組用的
           

存儲模型:

pb代碼graph繪圖表_從零開始學習資料結構&amp;gt;圖之鄰接表

3、核心方法 均由C++實作,無向圖的鄰接表; (1)、删除邊(是連結清單的删除操作,相對簡單):

1bool removeEdge(const Type &v1, const Type &v2){  //删除邊
 2    int i = getVertexIndex(v1);
 3    int j = getVertexIndex(v2);
 4
 5
 6    if(i==-1 || j==-1){  //保證頂點的儲存在
 7        return false;
 8    }
 9    //v1-->v2
10    Edge *p = vertexTable[i].adj;11    if(p == NULL){  //判斷有沒有邊12        return false;13    }1415    if(p->link == NULL && p->dest == j){ //删除的是第一個邊,其後沒有邊了;16        vertexTable[i].adj = NULL;17        delete p;    18    }else if(p->dest == j){  //删除的是第一個邊,并且其後還有邊19        vertexTable[i].adj = p->link;20        delete p;21    }else{22        while(p->link != NULL){23            if(p->link->dest == j){24                Edge *q = p->link;25                p->link = q->link;26                delete q;27            }28            p = p->link;29        }30    }31    //v2-->v132    Edge *s = vertexTable[j].adj;33    if(s == NULL){  //判斷有沒有邊34        return false;35    }3637    if(s->link == NULL && s->dest == i){ //删除的是第一個邊,其後沒有邊了;38        vertexTable[j].adj = NULL;39        delete s;40        curEdges--;41        return false;42    }else if(s->dest == i){  //删除的是第一個邊,并且其後還有邊43        vertexTable[j].adj = s->link;44        delete s;45        curEdges--;46        return true;47    }else{48        while(s->link != NULL){49            if(s->link->dest == i){50                Edge *q = s->link;51                s->link = q->link;52                delete q;53                curEdges--;54                return true;55            }56            s = s->link;57        }58    }5960    return true;61}
           

(2)、删除頂點 這個算法相對複雜,但是思路比較清晰: i>、首先找到要删除的頂點,将其後上的邊所對應的邊和這個邊都得删除; ii>、将最後一個頂點的data和adj都覆寫到這個地方; iii>、找到其後邊上的dest,更改為當下位置的下标。 大緻模型如下:

pb代碼graph繪圖表_從零開始學習資料結構&amp;gt;圖之鄰接表
1bool removeVertex(const Type &v){  //删除頂點
 2    int i = getVertexIndex(v);
 3    if(i == -1){
 4        return false;
 5    }
 6
 7    Edge *p = vertexTable[i].adj;  //先删除邊上的dest和此邊 8    while(p != NULL){ 9        vertexTable[i].adj = p->link;10        int k = p->dest;11        Edge *q = vertexTable[k].adj;12        if(q->dest == i){13            vertexTable[k].adj = q->link;14            delete q;15        }else{16            while(q->link != NULL && q->link->dest != i){17                q = q->link;18            }19            Edge *t = q->link;20            q->link = t->link;21            delete t;22        }23        delete p;24        p = vertexTable[i].adj;25        curEdges--;26    }2728    curVertices--;  //下面實行覆寫,指針和最後的那個頂點的adj相等;29    vertexTable[i].data = vertexTable[curVertices].data;30    vertexTable[i].adj = vertexTable[curVertices].adj;31    vertexTable[curVertices].adj = NULL;3233    int k = curVertices;34    p = vertexTable[i].adj;35    while(p != NULL){  //修改其它頂點的dest.36        Edge *s = vertexTable[p->dest].adj;37        while(s != NULL){38            if(s->dest == k){39                s->dest = i;40                break;41            }42            s = s->link;43        }44        p = p->link;45    }46    return true;47}
           

4、鄰接表完整代碼、測試代碼、測試結果 (1)、完整代碼(用的是繼承,友善寫其它的存儲結構代碼)

1#ifndef _GRAPH_H_
  2#define _GRAPH_H_
  3
  4#include
  5using namespace std;
  6
  7#define VERTEX_DEFAULT_SIZE        10
  8
  9template<typename Type>    
 10class Graph{
 11public:
 12    bool isEmpty()const{
 13        return curVertices == 0;
 14    }
 15    bool isFull()const{
 16        if(curVertices >= maxVertices || curEdges >= curVertices*(curVertices-1)/2)
 17            return true;  //圖滿有2種情況:(1)、目前頂點數超過了最大頂點數,存放頂點的空間已滿
 18        return false;     //(2)、目前頂點數并沒有滿,但是目前頂點所能達到的邊數已滿
 19    }
 20    int getCurVertex()const{
 21        return curVertices;
 22    }
 23    int getCurEdge()const{
 24        return curEdges;
 25    }
 26public:
 27    virtual bool insertVertex(const Type &v) = 0;  //插入頂點
 28    virtual bool insertEdge(const Type &v1, const Type &v2) = 0; //插入邊
 29    virtual bool removeVertex(const Type &v) = 0;  //删除頂點
 30    virtual bool removeEdge(const Type &v1, const Type &v2) = 0; //删除邊
 31    virtual int getFirstNeighbor(const Type &v) = 0; //得到第一個相鄰頂點
 32    virtual int getNextNeighbor(const Type &v, const Type &w) = 0; //得到下一個相鄰頂點
 33public:
 34    virtual int getVertexIndex(const Type &v)const = 0; //得到頂點下标
 35    virtual void showGraph()const = 0;  //顯示圖
 36protected:
 37    int maxVertices;  //最大頂點數
 38    int curVertices;  //目前頂點數
 39    int curEdges;  //目前邊數
 40};
 41
 42template<typename Type>
 43class Edge{  //邊的存儲結構
 44public:
 45    Edge(int num) : dest(num), link(NULL){}
 46public:
 47    int dest;
 48    Edge *link;
 49};
 50template<typename Type>
 51class Vertex{  //頂點的存儲結構
 52public:
 53    Type data;
 54    Edge *adj; 55}; 56template<typename Type> 57class GraphLnk : public Graph{ 58#define maxVertices  Graph::maxVertices  //因為是模闆,是以用父類的資料或方法都得加上作用域限定符 59#define curVertices  Graph::curVertices 60#define curEdges     Graph::curEdges 61public: 62    GraphLnk(int sz = VERTEX_DEFAULT_SIZE){ 63        maxVertices = sz > VERTEX_DEFAULT_SIZE ? sz : VERTEX_DEFAULT_SIZE; 64        vertexTable = new Vertex[maxVertices]; 65        for(int i = 0; i  66            vertexTable[i].data = 0; 67            vertexTable[i].adj = NULL; 68        } 69 70        curVertices = curEdges = 0; 71    } 72public: 73    bool insertVertex(const Type &v){ 74        if(curVertices >= maxVertices){ 75            return false; 76        } 77        vertexTable[curVertices++].data = v; 78        return true; 79    } 80    bool insertEdge(const Type &v1, const Type &v2){ 81        int v = getVertexIndex(v1); 82        int w = getVertexIndex(v2); 83 84        if(v==-1 || w==-1){ 85            return false; 86        } 87 88        Edge *p = vertexTable[v].adj; 89        while(p != NULL){  //這裡主要判斷邊是否已經存在 90            if(p->dest == w){   //無向圖,判斷一邊即可; 91                return false; 92            } 93            p = p->link; 94        } 95        //v1-->v2  //采用頭插 96        Edge *s = new Edge(w); 97        s->link = vertexTable[v].adj; 98        vertexTable[v].adj = s; 99100        //v2-->v1  //采用頭插101        Edge *q = new Edge(v);102        q->link = vertexTable[w].adj;103        vertexTable[w].adj = q;104105        curEdges++;106        return true;107    }108    bool removeVertex(const Type &v){109        int i = getVertexIndex(v);110        if(i == -1){111            return false;112        }113114        Edge *p = vertexTable[i].adj;115        while(p != NULL){116            vertexTable[i].adj = p->link;117            int k = p->dest;118            Edge *q = vertexTable[k].adj;119            if(q->dest == i){120                vertexTable[k].adj = q->link;121                delete q;122            }else{123                while(q->link != NULL && q->link->dest != i){124                    q = q->link;125                }126                Edge *t = q->link;127                q->link = t->link;128                delete t;129            }130            delete p;131            p = vertexTable[i].adj;132            curEdges--;133        }134135        curVertices--;  //下面實行覆寫136        vertexTable[i].data = vertexTable[curVertices].data;137        vertexTable[i].adj = vertexTable[curVertices].adj;138        vertexTable[curVertices].adj = NULL;139140        int k = curVertices;141        p = vertexTable[i].adj;142        while(p != NULL){143            Edge *s = vertexTable[p->dest].adj;144            while(s != NULL){145                if(s->dest == k){146                    s->dest = i;147                    break;148                }149                s = s->link;150            }151            p = p->link;152        }153        return true;154    }155    bool removeEdge(const Type &v1, const Type &v2){156        int i = getVertexIndex(v1);157        int j = getVertexIndex(v2);158159160        if(i==-1 || j==-1){  //保證頂點的儲存在161            return false;162        }163        //v1-->v2164        Edge *p = vertexTable[i].adj;165        if(p == NULL){  //判斷有沒有邊166            return false;167        }168169        if(p->link == NULL && p->dest == j){ //删除的是第一個邊,其後沒有邊了;170            vertexTable[i].adj = NULL;171            delete p;    172        }else if(p->dest == j){  //删除的是第一個邊,并且其後還有邊173            vertexTable[i].adj = p->link;174            delete p;175        }else{176            while(p->link != NULL){177                if(p->link->dest == j){178                    Edge *q = p->link;179                    p->link = q->link;180                    delete q;181                }182                p = p->link;183            }184        }185        //v2-->v1186        Edge *s = vertexTable[j].adj;187        if(s == NULL){  //判斷有沒有邊188            return false;189        }190191        if(s->link == NULL && s->dest == i){ //删除的是第一個邊,其後沒有邊了;192            vertexTable[j].adj = NULL;193            delete s;194            curEdges--;195            return false;196        }else if(s->dest == i){  //删除的是第一個邊,并且其後還有邊197            vertexTable[j].adj = s->link;198            delete s;199            curEdges--;200            return true;201        }else{202            while(s->link != NULL){203                if(s->link->dest == i){204                    Edge *q = s->link;205                    s->link = q->link;206                    delete q;207                    curEdges--;208                    return true;209                }210                s = s->link;211            }212        }213214        return true;215    }216    int getFirstNeighbor(const Type &v){217        int i = getVertexIndex(v);218        if(i != -1){219            Edge *p = vertexTable[i].adj;220            if(p != NULL){221                return p->dest;222            }223        }224225        return -1;226    }227    int getNextNeighbor(const Type &v, const Type &w){228        int i = getVertexIndex(v);229        int j = getVertexIndex(w);230231        if(i==-1 || j==-1){232            return -1;233        }234        Edge *p = vertexTable[i].adj;235        while(p != NULL){236            if(p->dest == j && p->link != NULL){237                return p->link->dest;238            }239            p = p->link;240        }241242        return -1;243    }244public:245    int getVertexIndex(const Type &v)const{246        for(int i = 0; i 247            if(vertexTable[i].data == v){248                return i;249            }250        }251252        return -1;253    }254    void showGraph()const{255        for(int i = 0; i 256            cout<":-->";257            Edge *p = vertexTable[i].adj;258            while(p != NULL){259                cout<dest<<"-->";260                p = p->link;261            }262            cout<<"Nul. "<<endl;263        }    264    }265private:266    Vertex *vertexTable;  //指向頂點的指針,是申請數組用的267};268269#endif
           

(2)、測試代碼

1#include"Graph.h"
 2
 3int main(void){
 4    GraphLnk<char> gl;
 5    gl.insertVertex('A');
 6    gl.insertVertex('B');
 7    gl.insertVertex('C');
 8    gl.insertVertex('D');
 9    gl.insertEdge('A','B');
10    gl.insertEdge('A','D');
11    gl.insertEdge('B','C');
12    gl.insertEdge('C','D');
13    gl.showGraph();
14
15    cout<'A')<<endl;16    cout<'A','B')<<endl;17    gl.removeEdge('B','C');18    cout<<"---------------------"<<endl;19    gl.removeVertex('B');20    gl.showGraph();2122    return 0;23}
           

(3)、測試結果 測試的圖:

pb代碼graph繪圖表_從零開始學習資料結構&amp;gt;圖之鄰接表
pb代碼graph繪圖表_從零開始學習資料結構&amp;gt;圖之鄰接表

推薦閱讀: 從零開始學習資料結構-->入門篇 從零開始學習資料結構-->連結清單 從零開始學習資料結構-->線性表 從零開始學習資料結構-->棧 從零開始學習資料結構-->隊列 從零開始學習資料結構-->矩陣+串 從零開始學習資料結構-->哈希表 從零開始學習資料結構-->散列桶 從零開始學習資料結構-->二叉樹

從零開始學習資料結構-->二叉樹方法實作

從零開始學習資料結構-->線索二叉樹

從零開始學習資料結構-->樹、森林與二叉樹的轉換

從零開始學習資料結構-->大堆+小堆

從零開始學習資料結構-->AVL樹之旋轉算法

從零開始學習資料結構-->AVL樹之插入算法

從零開始學習資料結構-->AVL樹之删除算法 從零開始學習資料結構-->紅黑樹 從零開始學習資料結構-->圖之鄰接矩陣 認真的人 自帶光芒

pb代碼graph繪圖表_從零開始學習資料結構&amp;gt;圖之鄰接表

繼續閱讀