数据结构——求邻接矩阵表示的图的关节点

  
    
#include < iostream >
using namespace std;

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

#define OK 1
#define NULL 0
#define MAX_VERTEX_NUM 20 // 最大顶点数
// 全局变量
int count;
int visited[MAX_VERTEX_NUM]; // 记录节点访问的顺序
int low[MAX_VERTEX_NUM];

typedef
char VertexType;
typedef
int VRType;
typedef
int InforType;

typedef
struct ArcNode
{
int adjvex; // 该边所指的顶点的位置
struct ArcNode * nextarc; // 指向下一条边的指针
int weight; // 边的权
}ArcNode; // 表的结点

typedef
struct VNode
{
VertexType data;
// 顶点信息(如数据等)
ArcNode * firstarc; // 指向第一条依附该顶点的边的弧指针
}VNode, AdjList[MAX_VERTEX_NUM]; // 头结点

typedef
struct ALGraph
{
AdjList vertices;
int vexnum, arcnum; // 图的当前顶点数和弧数
}ALGraph;


// 返回顶点v在顶点向量中的位置
int LocateVex(ALGraph & G, char v)
{
int i;
for (i = 0 ; v != G.vertices[i].data && i < G.vexnum; i ++ )
;
if (i >= G.vexnum)
return - 1 ;
return i;
}

// 增加节点
void add_vex(ALGraph & G)
{
cout
<< " 输入无向图顶点数: " << endl;
cin
>> G.vexnum;
// getchar(); // 吃回车
cout << " 输入顶点信息: " << endl;
for ( int i = 0 ; i < G.vexnum; i ++ )
{
cin
>> G.vertices[i].data; // 构造顶点向量
G.vertices[i].firstarc = NULL;
// getchar();
}
}

// 增加边
void add_arc(ALGraph & G)
{
ArcNode
* s, * t;
ArcNode
* p;

cout
<< " 输入无向图边数: " << endl;
cin
>> G.arcnum;
char v1, v2;
cout
<< " 输入边信息: " << endl;
for ( int k = 0 ; k < G.arcnum; k ++ )
{
cin
>> v1 >> v2;
int i = LocateVex(G, v1);
int j = LocateVex(G, v2); // 确定v1 , v2在G中的位置

s
= (ArcNode * ) malloc ( sizeof (ArcNode));
t
= (ArcNode * ) malloc ( sizeof (ArcNode));

s
-> adjvex = j; // 该边所指向的顶点的位置为j
s -> nextarc = NULL;
if ( ! G.vertices[i].firstarc)
{
G.vertices[i].firstarc
= s;
}
else
{
for (p = G.vertices[i].firstarc; p -> nextarc; p = p -> nextarc)
;
p
-> nextarc = s;
}

t
-> adjvex = i; // 该边所指向的顶点的位置为j
t -> nextarc = NULL;
if ( ! G.vertices[j].firstarc)
{
G.vertices[j].firstarc
= t;
}
else
{
for (p = G.vertices[j].firstarc; p -> nextarc; p = p -> nextarc)
;
p
-> nextarc = t;
}
}
}
// 构造邻接链表
void CreateUDN(ALGraph & G)
{
add_vex(G);
// 增加节点
add_arc(G); // 增加边
}

void PrintAdjList(ALGraph & G)
{
int i;
ArcNode
* p;
cout
<< " 编号 顶点 邻点编号 " << endl;

for (i = 0 ; i < G.vexnum; i ++ )
{
cout
<< " " << i << " " << G.vertices[i].data << " " ;
for (p = G.vertices[i].firstarc; p; p = p -> nextarc)
cout
<< p -> adjvex << " " ;
cout
<< endl;
}
}

void DFSArticul(ALGraph & g, int v)
{
int min;
int w;
ArcNode
* q;
visited[v]
= min =++ count; // 记录访问次序
for (q = g.vertices[v].firstarc; q; q = q -> nextarc) // 对v的每个邻接点检查
{
w
= q -> adjvex; // w为v的邻接顶点
if ( 0 == visited[w]) // w未曾访问,是v的孩子节点
{
DFSArticul(g,w);
// 返回前求得low[w]
if (low[w] < min)
min
= low[w];


if (low[w] >= visited[v])
cout
<< g.vertices[v].data << " " << endl;
// 如果low[w] >= visited[v]的话,说明v的子树上没有到v的祖先的回边,
// 因为如果有回边的话,low[w]肯定就等于有回边的这个点的所有邻接点的visited[i]的最小值
// 而这个点因为是v的祖先,所有这个值必然小于visited[v]
}
else if (visited[w] < min) // w已经访问,是v的祖先
{
min
= visited[w];
}
}
// for
low[v] = min;
}
// DFSArticul
// 找关节点
void FindArticul(ALGraph & g)
{
// 定义的全局变量见前面
count = 1 ;
visited[
0 ] = 1 ; // 设定邻接表上0号顶点为生成树的根
for ( int i = 1 ; i < g.vexnum; i ++ )
visited[i]
= 0 ; // 其余节点尚未访问
ArcNode * p;
p
= g.vertices[ 0 ].firstarc;
DFSArticul(g,p
-> adjvex); // 从p的第一个邻接点出发深度优先查找关节点

if (count < g.vexnum) // 生成树的根至少有两棵子树,只判断起始的根节点
{
cout
<< g.vertices[ 0 ].data << " " << endl;
while (p -> nextarc) // 对根的其它子树上的节点做判断
{
p
= p -> nextarc;
if ( 0 == visited[p -> adjvex])
DFSArticul(g,p
-> adjvex);
}
// while
} // if
} // FindArticul

int main()
{
ALGraph G;
CreateUDN(G);
PrintAdjList(G);

// 找关节点
FindArticul(G);
return 0 ;
}

 

你可能感兴趣的:(数据结构)