1. 程式人生 > >06-圖3. 六度空間 (30)

06-圖3. 六度空間 (30)

資料有1萬個,鄰接矩陣掛了,所以只能套鄰接表。第一次直接是套的模板,搜尋過程也是參考教材指導書上的實現。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stdlib.h>
using namespace std;
#define  MaxVertexNum  1024

typedef  unsigned long  VertexType;
typedef  struct  node    /* 邊表結點 */
{
    VertexType AdjV;            /* 鄰接點域 */
struct node *Next; /* 指向下一個鄰接點的指標域 */ } EdgeNode; typedef struct Vnode /* 頂點表結點 */ { int vis; double percent; EdgeNode *FirstEdge; /* 邊表頭指標 */ } VertexNode; typedef VertexNode AdjList[ MaxVertexNum ]; typedef struct { AdjList adjlist; /* 鄰接表 */ unsigned long int n, e; /* 頂點數和邊數 */
} ALGraph; /*ALGraph是以鄰接表方式儲存的圖型別 */ typedef struct queuenode { unsigned long int v; int level; }; queue<queuenode>q; void bfs(ALGraph *G,unsigned long int st) { G->adjlist[st].vis=1; int cnt=1; EdgeNode *egde; queuenode qe; while(!q.empty()) q.pop(); qe.v=st; qe.level=0
; q.push(qe); while(!q.empty()) { qe=q.front(); q.pop(); for(egde=G->adjlist[qe.v].FirstEdge; egde; egde=egde->Next) { if(!G->adjlist[egde->AdjV].vis) { G->adjlist[egde->AdjV].vis=1; cnt++; if(++qe.level<6) { //printf("%ld %ld\n",st+1,egde->AdjV+1); qe.v=egde->AdjV; q.push(qe); } qe.level--; } } } G->adjlist[st].percent=(double)cnt/(double)G->n*100.0; //printf("%ld: %.2f%%\n",st+1,G->adjlist[st].percent); } int main() { unsigned long int i,j,k; ALGraph *G=(ALGraph*)malloc(sizeof( ALGraph)); EdgeNode *edge; while(~scanf("%d%d",&(G->n),&(G->e))) { for ( i=0; i < G->n; i++ ) /* 建立有n個頂點的頂點表 */ { G->adjlist[i].vis=0; G->adjlist[i].percent=0.0; G->adjlist[i].FirstEdge = NULL; /* 頂點的邊表頭指標設為空 */ } for ( k=0; k < G->e; k++ ) /* 建立邊表 */ { scanf( "%d%d", &i, &j); /* 讀入邊<vi,vj>的頂點對應序號*/ edge = (EdgeNode*)malloc(sizeof(EdgeNode)); /* 生成新邊結點edge */ edge->AdjV = j-1; /* 鄰接點序號為j */ edge->Next = G->adjlist[i-1].FirstEdge; /* 將新邊表結點edge插入到頂點vi的邊表頭部 */ G->adjlist[i-1].FirstEdge = edge; edge = (EdgeNode*)malloc(sizeof(EdgeNode)); /* 生成新邊結點edge */ edge->AdjV = i-1; /* 鄰接點序號為j */ edge->Next = G->adjlist[j-1].FirstEdge; /* 將新邊表結點edge插入到頂點vi的邊表頭部 */ G->adjlist[j-1].FirstEdge = edge; } for(i=0L; i<G->n; i++) { bfs(G,i); printf("%ld: %.2f%%\n",i+1,G->adjlist[i].percent); for ( j=0L; j < G->n; j++ ) /* 建立有n個頂點的頂點表 */ { G->adjlist[j].vis=0; } } } return 0; }

教材上的參考程式碼

#include<stdio.h>
#include<stdlib.h>

#define SIX 6
#define  MaxVertexNum  1000     /* 最大頂點數 */

typedef unsigned long  VertexType;    /* 頂點用無符號長整數表示 */
typedef  struct  node{          /* 邊表結點 */
    VertexType AdjV;              /* 鄰接點域 */
    struct  node  *Next;          /* 指向下一個鄰接點的指標域 */
  /* 若要表示邊上的權值資訊,則應增加一個數據域Weight */
} EdgeNode;        

typedef unsigned long  VertexType;    /* 頂點用無符號長整數表示 */
typedef  struct  Vnode{       /* 頂點表結點 */
    char   Visited;              /* 頂點域,這裡用於標記該結點是否已經訪問 */
    double  Percent;              /* 用於記錄距離不超過SIX的結點百分比 */
    EdgeNode  *FirstEdge;       /* 邊表頭指標 */
} VertexNode;

typedef  VertexNode  AdjList[ MaxVertexNum ];
/* AdjList是鄰接表型別 */
typedef  struct{  
    AdjList  adjlist;          /* 鄰接表 */
    unsigned long int  n, e;  /* 頂點數和邊數 */
} ALGraph;                   /* ALGraph是以鄰接表方式儲存的圖型別 */

typedef struct Element { 
    VertexType v;        /* 結點編號 */
    int Layer;           /* BFS的層次 */
} QElementType;
typedef struct Node{
    QElementType  Data;
    struct Node  *Next;
}QNode; 
typedef  struct {              /* 鏈佇列結構  */
    QNode  *rear;              /* 指向隊尾結點 */
    QNode  *front;             /* 指向隊頭結點 */
} LinkQueue;

void Initialize(LinkQueue  *PtrQ)
{
    PtrQ->rear = PtrQ->front = NULL;
}

int IsEmptyQ(LinkQueue  *PtrQ)
{
    return PtrQ->front == NULL ;
}

void AddQ ( LinkQueue  *PtrQ, QElementType item )
{   
    QNode *cell = (QNode *)malloc(sizeof(QNode));/* 申請一個結點空間  */

    cell->Data = item; 
    cell->Next = NULL;
    if  ( IsEmptyQ(PtrQ) )  /* 若佇列空,頭尾是同一個元素 */
        PtrQ->front = PtrQ->rear = cell;
    else
    { /* 否則新元素新增到尾部 */
        PtrQ->rear->Next = cell;
        PtrQ->rear = cell;
    }
}

QElementType DeleteQ ( LinkQueue  *PtrQ )
{   QNode  *FrontCell; 
    QElementType FrontElem;

    if  ( PtrQ->front == NULL) {
        printf("佇列空");
        exit(0);
    } 
    FrontCell = PtrQ->front;
    if ( PtrQ->front == PtrQ->rear) /* 若佇列只有一個元素 */
        PtrQ->front = PtrQ->rear = NULL; /* 刪除後佇列置為空 */
    else                     
        PtrQ->front = PtrQ->front->Next;
    FrontElem = FrontCell->Data;
    free( FrontCell );  /* 釋放被刪除結點空間  */
    return  FrontElem;
}

void DestroyQueue( LinkQueue  Q )
{
    QNode *cell ;
    while((cell = Q.front)){
        Q.front = Q.front->Next;
        free(cell);
    }
}

void CreateALGraph( ALGraph *G )
{
    unsigned long int i,j,k;
    EdgeNode *edge;

    scanf( "%ld %ld", &(G->n), &(G->e) );      /* 讀入頂點數和邊數 */ 
    for ( i=0; i < G->n; i++ ) {        /* 建立有n個頂點的頂點表 */
        G->adjlist[i].Visited = 0;      /* 記錄該結點是否已經訪問 */
        G->adjlist[i].Percent = 0.0;    /* 距離不超過SIX的結點百分比 */
        G->adjlist[i].FirstEdge = NULL; /* 頂點的邊表頭指標設為空 */
    }
    for ( k=0; k < G->e; k++ ){   /* 建立邊表 */
        scanf( "%ld %ld", &i, &j); /* 讀入邊<vi,vj>的頂點對應序號*/
        edge = (EdgeNode*) malloc( sizeof( EdgeNode ) );
        /* 生成新邊表結點edge,用來表示邊(vi, vj) */
        edge->AdjV = j-1; /* 鄰接點序號為j */
        /* 將新邊表結點edge插入到頂點vi的邊表頭部 */
        edge->Next = G->adjlist[i-1].FirstEdge;
        G->adjlist[i-1].FirstEdge = edge;
        /* 因為是無向圖,還要生成一個結點,用來表示邊(vj, vi)  */
        edge = (EdgeNode*) malloc( sizeof( EdgeNode ) );
        edge->AdjV = i-1; /* 鄰接點序號為i */
        /* 將新邊表結點edge插入到頂點vj的邊表頭部 */
        edge->Next = G->adjlist[j-1].FirstEdge;
        G->adjlist[j-1].FirstEdge = edge;
    }
}

void  SixDegree_BFS( ALGraph *G , VertexType Start )
{   /* 計算離節點Start的距離不超過SIX的節點百分比 */
    QElementType  qe;   
    LinkQueue  Q; 
    VertexType  v;
    EdgeNode *edge;
    unsigned long int VisitCount = 1;  /* 記錄路徑長度<=SIX的頂點數 */

    Initialize( &Q );     /* 置空的佇列Q */
     G->adjlist[Start].Visited = 1; 
    qe.v = Start; qe.Layer = 0;   /* 起點算0層 */
    AddQ( &Q, qe );                  /* qe入佇列 */
    while ( !IsEmptyQ(&Q) ) {      /* 佇列非空迴圈 */
        qe = DeleteQ(&Q); v = qe.v; 
        for( edge=G->adjlist[v].FirstEdge; edge; edge=edge->Next )
            if ( !G->adjlist[edge->AdjV].Visited )
            /* 若edge->AdjV是v的尚未訪問的鄰接頂點 */
            {    
                G->adjlist[edge->AdjV].Visited = 1; 
                /* 將其記為六度以內的頂點 */
                VisitCount++ ;        /* 增加路徑長度<=SIX的頂點數 */
                if(++qe.Layer < SIX) /* 僅將六度以內的頂點再進隊 */
                {    qe.v = edge->AdjV;   
                    AddQ(&Q, qe);
                }
                qe.Layer--;   /* 恢復qe的層數 */
            } /* 結束if,for */
    } /* 結束while迴圈 */
    DestroyQueue( Q );
    G->adjlist[Start].Percent = 100.0 * (double)VisitCount / (double)G->n;
}

int main()
{
    VertexType i,j;
    ALGraph *G = (ALGraph *)malloc( sizeof(ALGraph) );
    CreateALGraph( G );
    for(i=0L; i<G->n; i++)
    {    
        SixDegree_BFS( G, i );/*計算離節點i的距離不超過SIX的節點百分比 */
        printf("%ld: %.2f%%\n", i+1, G->adjlist[i].Percent);
        for ( j=0; j < G->n; j++ )         /* 工作空間初始化 */
            G->adjlist[j].Visited = 0;     /* 重置標記所有結點未經訪問 */
    }    
    return 0;
}