樹的直徑是指樹的最長簡單路。求法: 兩遍BFS :先任選一個起點BFS找到最長路的終點,再從終點進行BFS,則第二次BFS找到的最長路即爲樹的直徑;
原理: 設起點爲u,第一次BFS找到的終點v一定是樹的直徑的一個端點
證明: 1) 如果u 是直徑上的點,則v顯然是直徑的終點(因爲如果v不是的話,則必定存在另一個點w使得u到w的距離更長,則於BFS找到了v矛盾)
2) 如果u不是直徑上的點,則u到v必然於樹的直徑相交(反證),那麼交點到v 必然就是直徑的後半段了
所以v一定是直徑的一個端點,所以從v進行BFS得到的一定是直徑長度
代碼如下:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
#define N 7
#define INFINITE 0x7fffffff
#define WHITE 1
#define GRAY 2
#define BLACK 3
//頂點結點結構
struct Vertex
{
Vertex * next;/*指向下一個頂點*/
int id;/*節點的標誌*/
int color;//顏色
Vertex *p;//指向遍歷結果的父結點
int d;//與源點之間的距離
Vertex():next(NULL),id(0),color(WHITE),p(NULL),d(INFINITE){}
};
//圖結構
struct Graph
{
Vertex *Adj[N+1];//N個頂點
Graph()
{
for(int i = 1; i <= N; i++)
Adj[i] = new Vertex;
}
~Graph()
{
for(int i = 1; i <= N; i++)
delete Adj[i];
}
};
std::queue<int>Q;/*隊列,保存搜索過程的中間數據*/
int c_node;/*當前遍歷的節點*/
void Print(Graph *g);
bool Init(Graph *g);
bool InsertEdge(Graph *g , int start,int end);
void PaintColor(Graph *g,int vertex,int color);
//插入邊
bool InsertEdge(Graph *g , int start,int end)
{
Vertex* v = new Vertex();
v->id = end;
if(g->Adj[start]->next == NULL)
{/*如果不存在臨界表的頭結點列表中,則插入*/
Vertex* s = new Vertex();
s->id = start;
g->Adj[start] = s;
}
Vertex* tmp = g->Adj[start];
while(tmp->next)
{
tmp = tmp->next;
}
tmp->next =v;
return true;
}
/*初始化鄰接表表示樹,無向圖。
1
/ \
2 3
/\ /\
4 5 6 7
*/
bool Init(Graph *g)
{
InsertEdge(g,1,2);
InsertEdge(g,2,1);
InsertEdge(g,1,3);
InsertEdge(g,3,1);
InsertEdge(g,2,4);
InsertEdge(g,4,2);
InsertEdge(g,2,5);
InsertEdge(g,5,2);
InsertEdge(g,3,6);
InsertEdge(g,6,3);
InsertEdge(g,3,7);
InsertEdge(g,7,3);
return true;
}
/*
寬度優先搜索,vertex爲初試的節點
這種方法適合於無向圖,如果是有向圖會產生死循環
*/
bool BreadFirstSearch(Graph *g,int vertex)
{
//對所有結點進行初始化
for(int i = 1; i <= N; i++)
{
//g->Adj[i]->color = WHITE;
g->Adj[i]->d = INFINITE;
g->Adj[i]->p = NULL;
PaintColor(g,i,WHITE);
}
PaintColor(g,vertex,GRAY);
g->Adj[vertex]->d = 0;
g->Adj[vertex]->p = NULL;
while(!Q.empty())
{
Q.pop();
}
Q.push(vertex);
while(!Q.empty())
{ /*應該存儲節點的ID,不應該是數據結構,可以節省存儲空間*/
int node = Q.front();
c_node = node;
Vertex *v = g->Adj[node]; //Q.front();
Q.pop();
std::cout<<v->id<<"\t";
while(v)
{
if(v->color == WHITE)
{
PaintColor(g,v->id,GRAY);
g->Adj[v->id]->d = g->Adj[node]->d +1;
Q.push(v->id);
}
v = v->next;
}
PaintColor(g,node,BLACK);
}
return true;
}
/*
對臨界表的節點染色
*/
void PaintColor(Graph *g,int vertex,int color)
{
g->Adj[vertex]->color = color;
for(int i=1;i<=N;i++)
{
Vertex *v = g->Adj[i];
v = v->next;
while(v)
{
if(v->id == vertex)
{
v->color = color;
}
v = v->next;
}
}
}
/*
顯示結果
1 2 3 4 5 6 7
7 3 1 6 2 4 5
4
*/
int main(int argc,char *argv[])
{
//構造一個空的圖
Graph *g = new Graph;
Init(g);
BreadFirstSearch(g,1);
std::cout<<std::endl;
BreadFirstSearch(g,c_node);
std::cout<<std::endl;
/*最後的節點的深度即樹的最大直徑*/
std::cout<<g->Adj[c_node]->d<<std::endl;
getchar();
return 0;
}