1. 程式人生 > 其它 >資料結構_圖論

資料結構_圖論

技術標籤:資料結構

一、圖的基本知識

  • :是由資料元素的集合及資料元素之間的關係集合組成的一種資料結構,G=(V,E),其中V是頂點集,E是邊集
  • 無向圖:如果頂點之間沒有方向,稱為無向圖,無向圖的邊表示一般用圓括號(v,w)
  • 有向圖:如果頂點之間有方向,就稱為有向圖,有向圖的邊表示一般用尖括號<v,w>,又稱為弧
  • 完全圖:在有n個頂點的無向圖中,有n(n-1)/2條邊,稱此圖為完全無向圖;在有n個頂點的有向圖中,有n(n-1)條邊,則稱此圖 為完全有向圖(每一個頂點與另外n-1個頂點都有編項鍊)
  • :邊上具有與它相關的係數,即稱為權,帶權圖也被稱為網路
  • 鄰接點:如果(v,w)是無向圖G的一條邊,則稱V與W互為鄰接頂點;如果<v,w>是有向圖G中的一條弧,則稱頂點v鄰接到頂點到w(v是w的前驅),頂點w鄰接自v(w是v的後繼)
  • 子圖:設圖G=(V,E)和圖G'=(V',E')。若V'屬於V,E'屬於E,則稱圖G'是圖G的子圖
  • 頂點的度:無向圖中,頂點V的度表示依附於V的邊數,記作TD(v);有向圖中,以頂點v為始點的有向邊的條數稱為v的出度,記 作OD(v),以頂點v為終點的有向邊的條數稱為v的入度,記作ID(v),有向圖中頂點v的度等於該頂點的入度與出度之和:TD(v)=ID(v)+OD(v)
  • 路徑:在圖G=(V,E)中,從頂點vi出發,沿一些邊或弧經過一些頂點Vp1,Vp2.....,到達頂點vj,則稱頂點序列(vi,vp1,vp2.....vj)為從打頂點vi到頂點vj的路徑
  • 路徑長度:對於不帶權的圖,路徑長度是指此路徑上邊的數目;帶權圖,路徑長度是指路徑上各邊的權之和
  • 簡單路徑和迴路:對於一套路徑,若路徑上各頂點均不相同,則稱該路徑為簡單路徑;若頂點上第一個頂點和最後一個頂點相同,則稱該路徑為迴路或環
  • 連通圖和連通分量:在無向圖中,若從頂點vi到vj有路徑,則稱頂點vi與vj使連通的,如果無向圖中任意兩個頂點都是連用的,則稱此無向圖為連通圖。非連通圖的極大連通子圖(包含所有連通的頂點和這些頂點依附的所有的邊)叫做連通分量
  • 強連通圖和強連通分量:在有向圖中,若對於頂點vi和vj,存在一條從vi到vj和從vj到vi的路徑,則稱頂點vi和頂點vj時強連通。如果有向圖中任意兩個頂點都是強連通的,則稱此有向圖為強連通圖。非強連通圖的極大強連通子圖叫做強連通分量
  • 生成樹:一個連通圖的生成樹是它的極小連通子圖(包含圖中全部n個頂點及使這些頂點連通的n-1條

二、圖的儲存結構

(1)鄰接矩陣

對於帶權圖可表示

鄰接矩陣儲存表示

​
​
#define MaxInt 32768                //表示極大值, 即
#define MVNum                       //最大頂點
typedef char VerTexType;            //設頂點的資料型別為字元型
typedef int ArcType;                //設邊的權值為整形
typedef struct
{
    VerTexType vexs[MVNum];         //頂點表
    ArcType arcs[MVNum][MVNum]      //鄰接矩陣
    int vexnum, arcnum              //頂點數、邊數
}AMGraph;

​

​
/*
確定頂點vex在圖G中的位置
*/
 
int LocateVex(AMGraph G, VerTexType vex)
{
    for(int i = 0; i < G.vexnum; i ++)
        if(vex == G.vexs[i])return i;
}
/*
以無向帶權圖為例
*/
void CreateUDN(AMGraph &G)
{
    cout<<"請輸入頂點和邊的數目:"<<endl;
    cin>>G.vexnum>>G.arcnum;
    //對無向圖初始化
    for(int i = 0; i < G.vexnum; i ++)
    {
        for(int j = 0; j < G.vexnum; j ++)
        {
            G.arcs[i][j] = MaxInt;
        }
    }
    cout<<"請輸入頂點:"<<endl;
    for(int i = 0; i < G.vexnum; i ++)cin>>G.vexs[i];
    cout<<"請輸入邊:"<<endl;
    for(int i = 0; i < G.arcnum; i ++)
    {
        VerTexType u, v;
        ArcType w;
        cin>>u>>v>>w;
        int uid = LocateVex(G, u), vid = LocateVex(G, v);
        G.arcs[uid][vid] = G.arcs[vid][uid] = w;
    }
}

鄰接矩陣優缺點:

優點:

直接判斷兩點是否右邊相連

方面計算個點的度(入度與出度)

缺點:

不便增加和刪除頂點

不便統計邊的數目

空間複雜度高O(n^2),浪費空間

綜上:鄰接矩陣適用於稠密圖

(2)鄰接表

typedef char VerTexType;    //頂點的資料型別
typedef int ArcType;        //邊的權值的資料型別
typedef struct ArcNode      //定義邊節點
{
    int adjvex;                 //指向下一個頂點的位置
    int val;                    //邊的的權值
    struct ArcNode *nextarc;    //指向下一個邊的指標
//    OtherInfo inof;
}ArcNode;
typedef struct VNode            //定義每一個頂點
{
    VerTexType data;            //頂點表示的值
    ArcNode *firstarc;          //指向第一條依附於該頂點的邊的指標
}VNode, AdjList[MVNum];         //鄰接表
 
typedef struct                  //定義圖
{
    AdjList vertices;           //圖的頂點
    int vexnum, arcnum;         //圖的頂點數、邊數
}ALGraph;
/*
以無向帶權圖圖為例
*/
 
void CreateUDN(ALGraph &G)
{
    ArcNode *pu, *pv;
    cout<<"請輸入頂點和邊的數目:"<<endl;
    cin>>G.vexnum>>G.arcnum;
    cout<<"請輸入頂點:"<<endl;
    for(int i = 0; i < G.vexnum; i ++)
    {
        cin>>G.vertices[i].data;
        G.vertices[i].firstarc = NULL;  //將改頂點的表頭指標域置為NULL
    }
    cout<<"請輸入邊:"<<endl;
    for(int i = 0; i < G.arcnum; i ++)
    {
        VerTexType u, v;
        int w;
        cin>>u>>v>>w;
        int uid = LocateVex(G, u), vid = LocateVex(G, v);
        pu = new ArcNode; pv = new ArcNode;
        pu->adjvex = vid; pu->val = w;
        pu->nextarc = G.vertices[uid].firstarc; G.vertices[uid].firstarc = pu;
 
//        //無向圖
        pv->adjvex = uid; pv->val = w;
        pv->nextarc = G.vertices[vid].firstarc; G.vertices[vid].firstarc = pv;
    }
}

鄰接表的優缺點:

優點:

便於增加和刪除頂點

便於統計邊的數目

空間效率高

缺點:

不便於判斷頂點與頂點之間是否存在邊

不便於計算圖各頂點的度

綜上:鄰接表使用稀疏圖