圖的鄰接矩陣和鄰接鏈表表示


 圖的鄰接矩陣表示:

  下面的這個程序讀入一組定義一個無向圖的便,創建一個對應這個圖的鄰接矩陣。如果在圖中頂點i,j或j,i之間有一條邊,就把a[i][j]和a[j][i]置為1,如果不存在這樣的邊,則置0。

#include<iostream>
using namespace std;
int main()
{
    int N;
    int i,j;
    cin>>N;
    int **adj=new int*[N];
    for( i=0;i<N;i++)
        adj[i]=new int[N];
    for(i=0;i<N;i++)
        for(j=0;j<N;j++)
            adj[i][j]=0;
    for(i=0;i<N;i++) adj[i][i]=1;

    while(cin>>i>>j)
    {
        adj[i][j]=1;
        adj[j][i]=1;
    }
}

 

另一種圖的直觀表示方法是鏈表數組,也叫鄰接表(adjacent list),我們為每個頂點保存一個鏈表。

 這2中方法都是簡單數據結構的數組-----都對每個頂點描述了和該頂點關聯的邊。對鄰接矩陣,這個簡單數據結構實現為一個索引數組;對鄰接列表,則實現為一個鏈表。

#include<iostream>
#include<cstdlib>
using namespace std;
#define N 8
struct node
{
    int v;
    node *next;
    node(int x,node *t):v(x),next(t){ }
};
typedef node *Link;

int main()
{
    freopen("input.txt","r",stdin);
    int i,j;
    Link adj[N];
    for(i=0;i<N;i++) adj[i]=0;
    while(cin>>i>>j)
    {
        adj[j]=new node(i,adj[j]);
        adj[i]=new node(j,adj[i]);
    }

    for(i=0;i<N;i++)
    {
        cout<<i<<"\t";
        while(adj[i]->next!=NULL)
        {
            cout<<adj[i]->v<<"--->";
            adj[i]=adj[i]->next;
        }
        cout<<adj[i]->v<<endl;

    }



}

輸出的語句是我自己加的。(algorithms in c++ parts1-4本沒有)。看下面圖:

從鏈表中我們要注意,前面的0,1,2,3,4只是數組中的序號,並不是節點。對於無向圖,如果在i的鏈表中存在節點j,則在j的鏈表中必定存在節點i。數組的第i個位置,包含了一個鏈表指針,鏈表中為每個和i鏈接的頂點保存一個節點。

程序運行過程如下:

輸入 0 1

adj[1]=new node(0,NULL); //為數組的第1個位置建立0節點

adj[0]=new node(1,NULL); 為數組的第0個位置建立1節點

輸入 0 2

adj[2]=new node(0,adj[2]) //為數組的第2個位置建立0節點

adj[0]=new node(2,adj[0]); //這里很重要,adj[0]不是NULL了,代表了1節點,新建立的2節點后面的next為1節點說明我們建立鏈表的順序是從右向左的

所以我們輸出時,2應該在前,1在后。

我們輸入:

0 1
0 2
0 5
0 6
0 7

5 4
4 6

5 3
4 3

4 7

1 7
2 7

 輸出:

 

可以看到,在數組的第0個位置,2在1前面。注意;鄰接鏈表的輸出與輸入有關系。所以輸出不是唯一的。

  我們現在頂點從1開始而不是從0開始:

#include<iostream>
#include<cstdlib>
using namespace std;
#define N 8
typedef struct Node
{
    int data;
    Node *next;
    Node(int x,Node *t)
    {
        data=x;
        next=t;
    }

}*LinkNode;
typedef struct{
    LinkNode *adj;
    int vexnum,arcnum;
    int kind;//圖的種類標志
}Graph;

void DFS(Graph G,int v);

static bool visited[100];
void (*visitFunc)(int v);

void visit(int v)
{
    cout<<v<<ends;
}
void DFSTraverse(Graph G,void (*Visit)(int v))
{
    visitFunc=Visit;
    for(int v=1;v<=G.vexnum;v++) visited[v]=false;
    for(int v=1;v<=G.vexnum;v++)
    {
        if(!visited[v])
            DFS(G,v);
    }
    
}

void DFS(Graph G,int v)
{
    visited[v]=true;
    visitFunc(v);
    LinkNode m,n;
    m=G.adj[v];
    while(m!=NULL )
    {
        if(!visited[m->data])
            DFS(G,m->data);
        m=m->next;
    }
}

int main()
{
    freopen("有向圖鄰接表.txt","r",stdin);
 
    //從1開始
    Graph graph;
    int vexnum,arcnum;
    cin>>vexnum>>arcnum;
    graph.vexnum=vexnum;
    graph.arcnum=arcnum;

    LinkNode *adj=new LinkNode[graph.vexnum+1];
    for(int i=1;i<=vexnum;i++) adj[i]=0;

    int start,end;//起點,終點
    for(int i=1;i<=arcnum;i++)
    {
        cin>>start>>end;
        adj[start]=new Node(end,adj[start]);
        adj[end]=new Node(start,adj[end]);
    }
    LinkNode *adj2=new LinkNode[graph.vexnum+1];
    for(int i=1;i<=vexnum;i++)
    {
        adj2[i]=adj[i];
    }

    for(int i=1;i<=vexnum;i++)
    {
        cout<<i<<"\t";
        while(adj[i]->next!=NULL)
        {
            cout<<adj[i]->data<<"--->";
             adj[i]=adj[i]->next;
        }

       cout<<adj[i]->data<<endl;
    }
    //必須重置adj[i];因為現在adj[i]已經指向的最后一個節點,為了重置,之前必須保存adj[i]
    for(int i=1;i<=vexnum;i++)
    {
        adj[i]=adj2[i];
    }

    for(int i=1;i<=vexnum;i++)
    {
        cout<<i<<"\t";
        cout<<adj[i]->data<<endl;
    }
    
    graph.adj=adj;
    DFSTraverse(graph,visit);


}

按嚴蔚敏書上P168的圖,輸入:

 

8
9

1 2 

1 3

 

 

2 4 

2 5

 

3 6 
3 7

4 8

5 8

6 7

輸出:

 

我們按照嚴蔚敏書上關於鄰接表的嚴格定義,寫出如下代碼:

#include<iostream>
using namespace std;
typedef int InfoType;
 typedef  struct ArcNode{
     int adjvex;//該狐所指向的頂點位置
     ArcNode *nextarc;//指向下一條弧的指針
     InfoType *info;
 }ArcNode;
 typedef char   VextexType[10] ;
 typedef struct VNode{
     VextexType data; //頂點信息
     ArcNode *firstarc; //指向第一條依附該頂點的弧的指針
 }VNode,Adj[100];
 typedef  struct {
     Adj vertices;
     int vexnum,arcnum;
     int kind;
 }Graph;
 int locateVex(Graph &G,VextexType u)
 {
     for(int i=0;i<G.vexnum;i++)
      if(strcmp(u,G.vertices[i].data)==0)//如果VexTexType 為char []類型
        //if(u==G.vertices[i].data)//如果VextexType為數值型,用這句
             return i;
     return -1;
 }
 void createGraph(Graph &G)
 {
     cout<<"請輸入圖的類型:有向圖0,有向網1,無向圖2,無向網3:"<<endl;
     cin>>G.kind;
     cout<<"輸入頂點數和邊數"<<endl;
     cin>>G.vexnum>>G.arcnum;

     cout<<"請輸入"<<G.vexnum<<"個頂點的值\n";
     for(int i=0;i<G.vexnum;i++)//構造頂點向量
     {
         cin>>G.vertices[i].data;
         G.vertices[i].firstarc=NULL;
     }

     if(G.kind==1||G.kind==3)//
         cout<<"請輸入每條弧(邊)的權值、弧尾和弧頭(以空格作為間隔):\n";
     else //
         cout<<"請輸入每條弧(邊)的弧尾和弧頭(以空格作為間隔):\n";
     VextexType va,vb;
     int w;
     for(int k=0;k<G.arcnum;k++)
     {
         if(G.kind==1||G.kind==3)
             cin>>w>>va>>vb;
         else
             cin>>va>>vb;

         int i=locateVex(G,va);//弧尾
         int j=locateVex(G,vb);//弧頭
         ArcNode *p=new ArcNode();
         p->adjvex=j;
          if(G.kind==1||G.kind==3)
          {
              p->info=new int(w);
          }
          else
              p->info=NULL;

          p->nextarc=G.vertices[i].firstarc;//插在表頭
          G.vertices[i].firstarc=p;

          if(G.kind>=2) //無向的 ,產生第二個表節點
          {
              p=new ArcNode();
              p->adjvex=i;
              if(G.kind==3) //無向網
              {
                  p->info=new int(w);
              }
              else
                  p->info=NULL;

              p->nextarc=G.vertices[j].firstarc;
              G.vertices[j].firstarc=p;

          }
     }//end for
      
 }
          


 int main()
 {
     freopen("鄰接表2.txt","r",stdin);
     Graph G;
     createGraph(G);
     for(int i=0;i<G.vexnum;i++)
     {
         cout<<G.vertices[i].data<<"\t";
          ArcNode *p=G.vertices[i].firstarc;
         while(p!=NULL)
         {
             cout<<G.vertices[p->adjvex].data<<"--->";
             p=p->nextarc;
         }
         cout<<endl;

     }
 }

Adj vertices[i]存儲的第i個頂點的信息,是一個結構體,里面的data該頂點的數據,firstarc表示指向的第一條狐。

該程序同前面的程序實際上都是一樣,都是在之前插入

2 //無向圖

8
9

v1 v2 v3 v4 v5 v6 v7 v8

v1 v2
v1 v3

v2 v4
v2 v5

v3 v6
v3 v7

v4 v8

v5 v8

v6 v7

可以看到更 前面的一樣。

只不過這種程序靈活性更大。

DFS遍歷代碼:

 bool visited[100];
void (*visitFunc)(VextexType v);

void visit(VextexType v)
{
    cout<<v<<ends;
}
void DFS(Graph G,int v);//函數聲明
void DFSTraverse(Graph G,void (*Visit)(VextexType v))
{
    visitFunc=Visit;
    for(int v=0;v<G.vexnum;v++) visited[v]=false;
    for(int v=0;v<G.vexnum;v++)
    {
        if(!visited[v])
            DFS(G,v);
    }
    
}

void DFS(Graph G,int v)
{
    visited[v]=true;
    visitFunc(G.vertices[v].data);
    ArcNode *p=G.vertices[v].firstarc;
    while(p!=0)
    {
        int w=p->adjvex;
        if(!visited[w])
            DFS(G,w);
        p=p->nextarc;
    }
}

遍歷上面的圖輸出:

v1 v3 v7 v6 v2 v5 v8 v4。

有幾點值得注意,

 visitFunc(G.vertices[v].data);不是visitFunc(v).
因為我們不是遍歷頂點的序號,而是得到頂點的信息

 

測試有向網:

1                                                                                   

4 5
a b c d

3 a b
2 a c
2 b c

4 b d
5 d c

                                                                                            

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM