06-圖3. 六度空間 (30)
阿新 • • 發佈:2019-02-12
資料有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;
}