1. 程式人生 > 實用技巧 >圖的一些簡單演算法實現

圖的一些簡單演算法實現

1、型別宣告

鄰接矩陣

#define MAXV<最大頂點個數>
#define INF 32767   //定義∞
typedef struct
{
    int no;   //頂點編號
    InfoType info;   //頂點其他資訊
}VertexType;   //頂點型別
typedef struct
{
    int edges[MAXV][MAXV];   //鄰接矩陣陣列
    int n,e;   //頂點數,邊數
    VertexType vexs[MAXV];   //存放頂點資訊
}MatGraph;   //鄰接矩陣型別

鄰接表

typedef struct ANode
{
    int adjvex;   //該邊的鄰接點編號
    struct ANode *nextarc;   //指向下一條邊的指標
    int weight;   //權值
}ArcNode;
typedef struct Vnode
{
    InfoType info;   //頂點其他資訊
    ArcNode *firstarc;   //指向第一個邊結點
}VNode;   //鄰接表的頭結點型別
typedef struct
{
    VNode adjlist[MAXV];   //鄰接表的頭結點陣列
    int n,e;   //頂點數和邊數
}AdjGraph;   //鄰接表型別

2、不帶權有向圖鄰接矩陣

void InDs1(MatGraph g) //求每個頂點的入度
{
    int i,j,n;
    printf("各頂點入度:\n");
    for(j=0;j<g.n;j++)
    {
        n=0;
        for(i=0;i<g.n;i++)
        {
            if(g.edges[i][j]!=0)
            {
                n++; //累計入度數
            }
        }
        printf("頂點%d:%d\n",j,n);
    }
}

void OutDs1(MatGraph g) //求每個頂點的出度
{
    int i,j,n;
    printf("各頂點出度:\n");
    for(i=0;i<g.n;i++)
    {
        n=0;
        for(j=0;j<g.n;j++)
        {
            if(g.edges[i][j]!=0)
            {
                n++; //累計出度數
            }
        }
    	printf("頂點%d:%d\n",i,n);
    }
}

void ZeroOutDs1(MatGraph g) //求出度為0的頂點
{
    int i,j,n;
    printf("出度為0的頂點:\n");
    for(i=0;i<g.n;i++)
    {
        n=0;
        for(j=0;j<g.n;j++)
        {
            if(g.edges[i][j]!=0)
            {
                n++;
            }
            if(n==0)
            {
                printf("2d\n",i);
            }
        }
    }
    printf("\n");
}

3、不帶權有向圖鄰接表

void InDs2(AdjGraph *G) //求每個頂點的入度
{
    ArcNode *p;
    int A[MAXV],i; //A存放各頂點的入度
    for(i=0;i<G->n;i++) //A中元素初始值0
    {
        A[i]=0;
        
    }
    for(i=0;i<G->n;i++) //掃描所有頭結點
    {
        p=G->adjlist[i].firstarc;
        while(p!=NULL) //掃描邊結點
        {
            A[p->adjvex]++; //表示i到p->adjvex頂點有一條邊
            p=p->nextarc;
        }
    }
    printf("各頂點的入度:\n");
    for(i=0;i<G->n;i++)
    {
        printf("頂點%d:%d\n",i,A[i]);
    }
}

void OutDs2(AdjGraph *G) //求每個頂點的出度
{
    int i,n;
    ArcNode *p;
    printf("各頂點出度為:\n");
    for(i=0;i<G->n;i++) //掃描所有頭結點
    {
        n=0;
        p=G->adjlist[i].firstarc;
        while(p!=NULL) //掃描邊結點
        {
            n++;
            p=p->nextarc;
        }
        printf("頂點%d:%d\n",i,n);
    }
}

void ZeroOutDs2(AdjGraph *G) //出度為0的頂點數
{
    int i,n;
    ArcNode *p;
    printf("出度為0的頂點數:\n");
    for(i=0;i<G->n;i++) //掃描所有頭結點
    {
        n=0;
        p=G->adjlist[i].firtarc;
        while(p!=NULL) //掃描邊結點
        {
            n++;
            p=p->nextarc;
        }
        if(n==0) //輸出出邊為0的頂點編號
        {
            printf("%2d",i);
        }
    }
    printf("\n");
}

4、判斷是否存在經過頂點v的迴路

int visited[MAXV]; //全域性變數陣列
void Cycle(AdjGraph *G,int u,int v,int d,bool &has)
{
    //呼叫初始值has置為false,d為-1
    ArcNode *p;
    int w;
    visited[u]=1; //置已訪問的標記
    d++;
    p=G->adjlist[u].firstarc; //p指向頂點u的第一個鄰接點
    while(p!=NULL)
    {
        w=p->adjvex;
        if(visited[w]==0) //若頂點w未訪問,則遞迴訪問
        {
            Cycle(G,w,v,d,has); //從頂點w出發搜尋
        }
        else if(w==v&&d>1) //u到v存在一條邊且迴路長度大於1
        {
            has=true;
            return;
        }
        p=p->nexterc; //找下個鄰接點
    }
}
bool hasCycle(AdjGraph *G,int v) //判斷連通圖中是否有經過頂點v的迴路
{
    bool has=false;
    Cycle(G,v,v,-1,has); //從頂點v出發
    return has;
}

5、判斷無向圖是否為一棵樹

void DFS(AdjGraph *G,int v,int &vn,int &en)
{
    //深度優先遍歷圖G,並求出遍歷過的頂點數vn和邊數en
    ArcNode *p;
    visited[v]=1;
    vn++; //遍歷過的頂點數增1
    p=G->adjlist[v].firstarc;
    while(p!=NULL)
    {
        en++; //遍歷過的邊數增1
        if(visited[p->adjvex]==0)
        {
            DFS(G,p->adjvex,vn,en);
        }
        p=p->nextarc;
    }
}
bool isTree(AdjGraph *G) //判斷無向圖G是否為樹
{
    int vn=0,en=0,i;
    for(i=0;i<G->n;i++)
    {
        visited[i]=0;
    }
    DFS(G,1,vn,en);
    //遍歷頂點為 G->n 個,遍歷邊數為 2(G->n-1),則為樹
    if(vn==G->n&&en==2*(G->n-1))
    {
        return true;
    }
    else
    {
         return false;   
    }
}

6、源點到其餘各點的最短路徑

void shortPath(AdjGraph *G,int i)
{
    int qu[MAXV],level[MAXV];
    int fornt=0,raer=0,k,lev; //lev儲存i到訪問頂點的層數
    ArcNode *p;
    visited[i]=1; //i已經訪問,進隊
    rear++;
    qu[rear]=i;
    level[rear]=0;
    while(front!=rear) //隊非空
    {
        front=(front+1)%MAXV;
        //出隊
        k=qu[front];
        lev=level[front];
        if(k!=i)
        {
            printf(" 頂點%d到頂點%d的最短距離是:%d\n",i,k,lev);
        }
        p=G->adjlist[k].firstarc; //取k的邊表頭指標
        while(p!=NULL) //依次搜尋鄰接點
        {
            if(visited[p->adjvex==0]) //未被訪問過
            {
                visited[p->adjvex]=1;
                rear=(rear+1)%MAXV;
                qu[rear]=p->adjvex; //訪問過的鄰接點進隊
                level[rear]=lev+1;
            }
            p=p->nextarc; //頂點i的下一個鄰接點
        }
    }
}

7、所有路徑及其長度

int visited[MAXV];
void findPath(AdjGraph *G,int u,int v,int path[],int d,int length)
{
    //d表示 path 中頂點個數,初始為 0;length 表示路徑長度,初始為 0
	int w,i;
    ArcNode *p;
    //頂點u加到路徑中,d增1
    path[d]=u;
    d++;
    visited[u]=1; //置已訪問標記
    if(u==v&&d>0) //找到一條路徑就輸出
    {
        printf(" 路徑長度:%d,路徑:",length);
        for(i=0;i<d;i++)
        {
            printf("%2d",path[i]);
        }
		printf("\n");
    }
    p=G->adjlist[u].firstarc; //p指向頂點u的第一個鄰接點
    while(p!=NULL)
    {
        w=p->adjvex; //w為頂點u的鄰接點
        if(visited[w]==0) //w未訪問,遞迴訪問
        {
            findPath(G,w,v,path,d,p->weigth+length);
        }
        p=p->nextarc; //p指向頂點u的下一個鄰接點
    }
    visited[u]=0; //重置
}