1. 程式人生 > >資料結構——圖整理程式碼(鄰接表儲存圖)

資料結構——圖整理程式碼(鄰接表儲存圖)

資料結構圖相關程式碼整理記錄——鄰接表儲存圖

環境CodeBlocks17 執行通過

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
using namespace std;

#define MAX_VERTEX_NUM 20
typedef char VertexType;    // 頂點資料型別
typedef char InfoArc;   // 弧節點相關資訊
typedef enum {DG,DN,UDG,UDN} GraphKind;//圖型別{有向圖,有向網,無向圖,無向網}   (邊帶權值的圖叫網)
typedef struct ArcNode  // 弧節點
{
    int adjvex; // 該弧所指向的頂點在陣列中的位置
    int value;  // 弧的權值
    struct ArcNode *nextarcs;   // 指向下一條弧的指標
    InfoArc *info;  // 該弧相關資訊的指標
}ArcNode;
typedef struct VNode    // 頂點
{
    VertexType data;    // 頂點資訊
    ArcNode *firstarc;  // 指向第一條依附於該頂點的弧的指標
}VNode, AdjList[MAX_VERTEX_NUM];
typedef struct  // 圖結構
{
    AdjList vertices;    // 指向訂點連結串列的指標
    int vexnum, arcnum; // 圖的當前頂點和弧數
    GraphKind kind;   // 圖的種類標誌DG,DN,UDG,UDN
}ALGraph;

int visited[MAX_VERTEX_NUM];    // 訪問記錄陣列
int indegree[MAX_VERTEX_NUM];   // 入度記錄陣列

void CreatGraph_DN(ALGraph &G)
{// 建立有向圖
    ArcNode *p,*q;
    int i,j,flag1,flag2,value;  // value 接收輸入的權值
    VNode v1,v2;
    G.kind = DN;    // 規定為有向圖

    // 輸入該有向網的頂點數目和弧的數目
    scanf("%d%d",&G.vexnum,&G.arcnum);getchar();
    // 初始化頂點
    for(i=0;i<G.vexnum;i++)
    {
        scanf("%c ",&G.vertices[i].data);
        G.vertices[i].firstarc = NULL;
    }
    // 請初始化頂點之間的關係 G.arcnum 條弧
    for(i=0;i<G.arcnum;i++)
    {
        flag1=flag2=-1; // 標記
        scanf("%c %c",&v1.data,&v2.data);getchar();
        for(j=0;j<G.vexnum;j++)
        {
            if(G.vertices[j].data == v1.data)
                flag1 = j;
            if(G.vertices[j].data == v2.data)
                flag2 = j;
        }

        if(flag1==-1||flag2==-1)    // 錯誤輸入
        {printf("Input error!\n");exit(-1);}

        else    // 在相關頂點的鄰接表頭插入新弧節點
        {
            p = (ArcNode *)malloc(sizeof(ArcNode));
            p->nextarcs = NULL;
            p->adjvex = flag2;
            //  沒有權值 p->value==?
            q = G.vertices[flag1].firstarc;
            if(q == NULL)   // 弧連結串列為空
                G.vertices[flag1].firstarc = p;
            else    // 弧連結串列不為空,接到表尾
            {
                /*
                while(q->nextarcs!=NULL)
                    q = q->nextarcs;
                q->nextarcs = p;
                */
                //方法二插到表頭後面
                p->nextarcs = G.vertices[flag1].firstarc;
                G.vertices[flag1].firstarc = p;
            }
        }
    }
}

void CreatGraph_UDG(ALGraph &G)
{// 建立鄰接表儲存的無向圖G
    ArcNode *p,*q;
    int i,j,flag1,flag2;
    VNode v1,v2;
    G.kind = UDG;    // 規定為無向圖

    // 輸入該有向網的頂點數目和弧的數目
    scanf("%d%d",&G.vexnum,&G.arcnum);getchar();
    // 初始化頂點
    for(i=0;i<G.vexnum;i++)
    {
        scanf("%s ",G.vertices[i].data);
        G.vertices[i].firstarc = NULL;
    }
    // 請初始化頂點之間的關係 G.arcnum 條弧
    for(i=0;i<G.arcnum;i++)
    {
        flag1=flag2=-1; // 標記
        scanf("%s %s",v1.data,v2.data);getchar();
        for(j=0;j<G.vexnum;j++)
        {//以下比較字串可以使用strcmp
            if(G.vertices[j].data[0] == v1.data[0])
                if(G.vertices[j].data[1] == v1.data[1])
                    if(G.vertices[j].data[2] == v1.data[2])
                        flag1 = j;
            if(G.vertices[j].data[0] == v2.data[0])
                if(G.vertices[j].data[1] == v2.data[1])
                    if(G.vertices[j].data[2] == v2.data[2])
                        flag2 = j;
        }

        if(flag1==-1||flag2==-1)    // 錯誤輸入
        {printf("Input error!\n");exit(-1);}

        else    // 在相關頂點的鄰接表頭插入新弧節點
        {
            p = (ArcNode *)malloc(sizeof(ArcNode));
            p->nextarcs = NULL;
            p->adjvex = flag2;
            //  沒有權值 p->value==?
            q = G.vertices[flag1].firstarc;
            if(q == NULL)   // 弧連結串列為空
                G.vertices[flag1].firstarc = p;
            else    // 弧連結串列不為空,插入到表中
            {
                // 方法一 插入到表尾
                /*
                while(q->nextarcs!=NULL)
                    q = q->nextarcs;
                q->nextarcs = p;
                */
                //方法二插到表頭後面
                p->nextarcs = G.vertices[flag1].firstarc;
                G.vertices[flag1].firstarc = p;
            }
            //------------------------------
            p = (ArcNode *)malloc(sizeof(ArcNode));
            p->nextarcs = NULL;
            p->adjvex = flag1;
            // DN 沒有權值 p->value==?
            q = G.vertices[flag2].firstarc;
            if(q == NULL)   // 弧連結串列為空
                G.vertices[flag2].firstarc = p;
            else    // 弧連結串列不為空,插入到表中
            {
                // 方法一 插入到表尾
                /*
                while(q->nextarcs!=NULL)
                    q = q->nextarcs;
                q->nextarcs = p;
                */
                //方法二插到表頭後面
                p->nextarcs = G.vertices[flag2].firstarc;
                G.vertices[flag2].firstarc = p;
            }
        }
    }
}


void CountVerNum_DN(ALGraph &G, int *D, int *ID, int* OD)
{//計算各結點的度
	//鄰接表儲存的有向網,當計算頂點的度時,出度為頂點連結串列中弧表結點的數目
	//入度則需遍歷整個鄰接表求得相應的頂點的入度,然後與出度相加得到個頂點的度
    int i;
    ArcNode *p;
    for(i=0;i<G.vexnum;i++) // 初始化
    {
        D[i] = ID[i] = OD[i] = 0;
    }
    for(i=0;i<G.vexnum;i++)
    {
        p = G.vertices[i].firstarc;
        if(p==NULL)
            OD[i]=0;
        else
            while(p!=NULL)
                {
                    OD[i]++;
                    ID[p->adjvex]++;
                    p = p->nextarcs;
                }
    }
    for(i=0;i<G.vexnum;i++)
		D[i]=ID[i]+OD[i];
}

void Display_AdjacencyList_DN(ALGraph &G)
{// 輸出鄰接表 example:0:A 2 1
    ArcNode *p;
    for(int i=0;i<G.vexnum;i++)
    {
        printf("%d:%c",i,G.vertices[i].data);
        p = G.vertices[i].firstarc;
        while(p)
        {
            printf(" %d",p->adjvex);
            p = p->nextarcs;
        }
        printf("\n");
    }
}

//--------------------------------------------------
int FirstAdjVex(ALGraph &G, int v)
{// 返回表示第v個節點的第一個鄰接點的陣列下標
    if(G.vertices[v].firstarc==NULL)    // 下個節點不存在
        return -1;
    else    // 下個節點存在
        return G.vertices[v].firstarc->adjvex;
}
int NextAdjVex(ALGraph &G, int v, int w)
{// 返回圖G中v的鄰接連結串列中邊data值為w的下一個節點的陣列下表
    ArcNode *p = G.vertices[v].firstarc;
    while(p->adjvex!=w) // 查詢v的弧連結串列上的w的位置
    {
        p = p->nextarcs;
    }
    if(p->nextarcs!=NULL)    // 下個節點存在
        return p->nextarcs->adjvex;
    else    // 下個節點不存在
        return -1;
}
//--------------------------------------------------

void DFS(ALGraph &G, int v)
{// 從第v個頂點開始遞迴比深度優先遍歷圖 連通圖 G
    cout<<G.vertices[v].data;
    visited[v] = 1;
    for(int w=FirstAdjVex(G,v); w>=0; w=NextAdjVex(G,v,w))
    // FirstAdjVex(G,v)表示第v個節點的第一個鄰接點,NextAdjVex(G,v,w)表示v相對與w的下一個節點
    // w>=0表示存在鄰接點
        if(!visited[w])
            DFS(G,w);
}

void DFS_No_Connet(ALGraph &G)
{// 對 !-->非連通圖<--! G做深度優先遍歷
    for(int v=0; v<G.vexnum; v++)
        visited[v] = 0; // 訪問標誌陣列初始化
    for(int v=0; v<G.vexnum; v++)
        if(!visited[v])
            DFS(G,v);   // 對尚未訪問的頂點進行訪問

}

void DFS_AL(ALGraph &G, int v)
{// 圖G為鄰接表 從第v個頂點出發深度優先搜尋遍歷圖G
    int w;
    cout<<G.vertices[v].data;
    visited[v] = 1;
    ArcNode *p = G.vertices[v].firstarc;
    while(p!=NULL)    // 邊結點非空
    {
         w = p->adjvex;  // 表示w是v的鄰接點
        if(!visited[w]) // w未被訪問
            DFS_AL(G,w);    // 遞迴訪問
        p = p->nextarcs;
    } //<end while>
}

void BFS_No_Recursive1(ALGraph &G, int v)
{// 從第v個頂點開始 廣度優先 非遞迴 遍歷連通圖G
    int i;
    for(i=0; i<G.vexnum; i++)   // 初始化
        visited[i] = 0;
    cout<<G.vertices[v].data<<" ";
    visited[v] = 1;
    queue<int> Q;
    Q.push(v);
    while(!Q.empty())
    {
        int u = Q.front();Q.pop();
        for(int w=FirstAdjVex(G,u); w>=0; w=NextAdjVex(G,u,w))
        {// 依次檢查u的所有鄰接點;FirstAdjVex(G,u)表示u的第一個鄰接點
            //NextAdjVex(G,u,w) 表示u相對於w的下一個鄰接點,W>=0表示存在鄰接點
            if(!visited[w])
            {
                cout<<G.vertices[w].data<<" ";
                visited[w] = 1;
                Q.push(w);
            }
        }
    }
}

void BFS_No_Recursive2(ALGraph G)
{
    int i,u,w;
    queue<int> Q;
    for(i=0; i<G.vexnum; i++)   // 初始化
        visited[i] = 0;

    for(i=0; i<G.vexnum; i++)
    {
        if(!visited[i])
        {
            cout<<G.vertices[i].data<<" ";
            visited[i] = 1;
            Q.push(i);
            while(!Q.empty())
            {
                u = Q.front(); Q.pop();
                for(w=FirstAdjVex(G,u); w>=0; w=NextAdjVex(G,u,w))
                    if(!visited[w])
                {
                    cout<<G.vertices[w].data<<" ";
                    visited[w] = 1;
                    Q.push(w);
                }// <end for>
            }// <end while>
        }// <end if>
    }// <end for>
}

void DFS_No_Recursive(ALGraph &G)
{//鄰接表儲存圖的非遞迴深度優先遍歷
	ArcNode *p;
	stack<int> S;
	cout <<G.vertices[0].data<<" ";//預設從0結點開始遍歷
	visited[0] = 1;//此為遍歷標誌陣列,0:未訪問,1:已訪問
	S.push(0);
	while (!S.empty())
    {
		p = G.vertices[S.top()].firstarc;
		while (p != NULL)
		{
			if(visited[p->adjvex] != 1)
            {
				cout <<G.vertices[p->adjvex].data<<" ";
				visited[p->adjvex] = 1;
				S.push(p->adjvex);
				break;
			}
            else
			{
				p = p->nextarcs;
			}
		}
		if (p == NULL)
		{
			S.pop();
		}
	}
}

int main()
{
    ALGraph G;
    for(int i=0; i<=MAX_VERTEX_NUM; i++)    // 每次遍歷之前記得初始化訪問記錄陣列!!!!
        visited[i] = 0;
    int D[MAX_VERTEX_NUM],ID[MAX_VERTEX_NUM],OD[MAX_VERTEX_NUM];
    // 建立
    CreatGraph_DN(G);
    // 統計度
    CountVerNum_DN(G,D,ID,OD);
    for(int i=0;i<6;i++)
        printf("D:%d ID:%d OD:%d\n",D[i],ID[i],OD[i]);
    // 輸出鄰接表
    Display_AdjacencyList_DN(G);
    // 遍歷鄰接表



    return 0;
}

/*
第一組測試資料 data為char
測試資料:
連通圖
6 6
A B C D E F
A B
A C
B D
C D
D E
C F

非連通圖
6 5
A B C D E F
A B
A C
B D
C D
D E

第二組測試資料 data為char [3]
請修改CreatGraph函式 和 typedef struct VNode
輸入:
12 16
c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12
c1 c4
c1 c2
c1 c3
c1 c12
c4 c5
c2 c3
c3 c5
c3 c7
c5 c7
c3 c8
c9 c12
c9 c10
c10 c12
c9 c11
c11 c6
c6 c8
*/