DFS和Bellman_Ford算法的代码实现
不想麻烦声明函数,所以把实现写到头文件中了,只剩下一个cpp文件main.cpp.
本程序实现了深度优先搜索非递归算法和单源最短路径Bellman_Ford算法;
DFS用非递归效率高,因为输入规模太大,递归让我电脑吃不消,
Bellman_Ford算法可以处理负权值图,这点比Dijkstra算法好.
1
/**/
/******************************************
2
程序名称:DFS和Bellman_Ford算法的实现
3
作者:pengkuny
4
主页:http://www.cppblog.com/pengkuny
5
邮箱:[email protected]
6
参考书籍:<<Introduction to Agrithms>>
7
完成日期:2006.11.30
8
******************************************/
2
3
4
5
6
7
8
ALGraph.h
1
/**/
/* ALGraph.h 图的邻接表存储表示 */
2
#ifndef ALGRAPH_H
3
#define
ALGRAPH_H
4![]()
5
#include
<
iostream
>
6
#include
<
cstdio
>
7
#include
<
cmath
>
8
#include
<
cstring
>
9![]()
10
using
namespace
std;
11![]()
12
#define
wuqiong 65535
//
初始权值无穷大
13![]()
14![]()
typedef
enum
{WHITE,GRAY,BLACK}
;
15![]()
16
typedef
struct
VNode VNode;
17![]()
18
typedef
struct
ArcNode
19![]()
{
20![]()
int adjvex; /**//* 原顶点 */
21![]()
ArcNode* next; /**//* 指向下一条弧的指针 */
22![]()
long weight; /**//* 权值 */
23![]()
}
ArcNode;
/**/
/* 表结点 */
24![]()
25![]()
26
typedef
struct
VNode
27![]()
{
28![]()
int adjvex; /**//* 顶点序号 */
29![]()
int color; /**//* 顶点颜色 */
30![]()
long d; /**//* 顶点最初DFS发现时间 ; 兼作Dijkstra算法中当前最短路径 */
31![]()
long f; /**//* 顶点最终DFS结束时间 */
32
VNode * father;
33![]()
ArcNode * next; /**//* 第一个表结点的地址,指向第一条依附该顶点的弧的指针 */
34![]()
}
VNode,
*
AdjList ;
/**/
/* 头结点 */
35![]()
36![]()
37
typedef
struct
38![]()
{
39![]()
AdjList vertices; /**//* 表结点指针(一个头结点数组) */
40![]()
int vexnum,arcnum; /**//* 图的当前顶点数和弧数 */
41
}
ALGraph;
42
43![]()
44
#endif
//
ALGRAPH_H
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Stack.h: 栈的表示,DFS使用栈非递归
1
/**/
/* Stack.h 图的邻接表存储表示 */
2
#ifndef STACK_H
3
#define
STACK_H
4![]()
5
#include
"
ALGraph.h
"
6![]()
7
#include
<
iostream
>
8
#include
<
cstdio
>
9
#include
<
cmath
>
10
#include
<
cstring
>
11![]()
12
using
namespace
std;
13![]()
14
typedef
struct
LinkList
15![]()
{
16
VNode * data; //栈中只保存图顶点指针
17
LinkList * next; //下一个顶点
18
}
LinkList;
19![]()
20
typedef
struct
Stack
21![]()
{
22
LinkList * top;
23
}
Stack;
24![]()
25![]()
26
void
InitStack(Stack
&
S)
27![]()
{
28
S.top = NULL;
29
}
30![]()
31
bool
Empty(Stack S)
32![]()
{
33
if (S.top == NULL)
34![]()
{
35
return true;
36
}
37
return false;
38
}
39![]()
40
void
Push(Stack
&
S, VNode
*
k)
41![]()
{
42![]()
43
LinkList * p = new LinkList;
44
p->data = k;
45
p->next = S.top;
46
S.top = p;
47
}
48![]()
49
VNode
*
GetTop(Stack
&
S)
50![]()
{
51
return S.top->data;
52
}
53![]()
54
VNode
*
Pop(Stack
&
S)
55![]()
{
56
LinkList* p = S.top;//保存栈顶指针
57
VNode* q;
58
if(Empty(S))
59![]()
{
60
cout<<"Stack underflow."; //下溢
61
exit(1);
62
}
63![]()
64
S.top = p->next; //将栈顶结点从链上摘下
65![]()
66
q = p->data;//回收栈空间,不可以写成q=p;delete p;return q->data;
67
delete p; //因为delete p之后,p所指的空间已不可用
68![]()
69
return q;
70
}
71![]()
72![]()
73
#endif
//
STACK_H
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
CTimer.h:CTimer类,计时功能,单位毫秒
1
#ifndef CTIMER_H
2
#define
CTIMER_H
3![]()
4
#include
"
Windows.h
"
5![]()
6
class
CTimer
7![]()
{
8
public:
9
CTimer()
10![]()
{
11
QueryPerformanceFrequency(&m_Frequency);//取CPU频率
12
}
13
void Start()
14![]()
{
15
QueryPerformanceCounter(&m_StartCount);//开始计数
16
}
17
double End()
18![]()
{
19
LARGE_INTEGER CurrentCount;
20
QueryPerformanceCounter(&CurrentCount);//终止计数
21
return
22
double(CurrentCount.QuadPart-m_StartCount.QuadPart)*1000/(double)m_Frequency.QuadPart;
23
24
}
25
private:
26
LARGE_INTEGER m_Frequency;
27
LARGE_INTEGER m_StartCount;
28
}
;
29![]()
30
#endif
//
CTIMER_H
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
CreateALGraph.h: 创建邻接图G
1
#include
"
ALGraph.h
"
2![]()
3
void
CreateALGraph(ALGraph
&
G,
long
vexnum,
long
arcnum)
4![]()
{
5
int i,j,m,n;
6
bool flag = false;//检查边是否已存在
7
int * weight = new int[arcnum];
8
for(i = 0; i < G.arcnum; i++)
9![]()
{
10
weight[i] = 0; //初始权值为零
11
}
12![]()
13
AdjList vertices = new VNode[vexnum] ; //动态分配头结点数组
14
ArcNode* p = NULL;
15
ArcNode* q = NULL;
16
srand(NULL);
17
18
G.vexnum = vexnum;
19
G.arcnum = arcnum;
20
for(i=0; i<G.vexnum; i++)
21![]()
{
22
vertices[i].adjvex = i; // 顶点序号
23
vertices[i].color = WHITE; // 顶点颜色
24
vertices[i].d = 0; // 顶点最初DFS发现时间 ; 兼作Bellman_Ford算法中当前最短路径
25
vertices[i].f = 0; // 顶点最终DFS结束时间
26
vertices[i].father = NULL; //访问路径上的父结点
27
vertices[i].next = NULL; //表结点指针,叫做firstarc似乎更合适,也更好控制,懒得改了
28
}
29
G.vertices = vertices;
30
31
32
for(i = 0; i < G.arcnum; i++)//随机产生arcnum条边
33![]()
{
34
weight[i] = rand()%1000 ;//- 200; //适当加一些负权值边
35
if (weight[i] == 0)
36![]()
{
37
weight[i]++;//不能让权值为零,否则等于没有添加边
38
}
39
}
40
41
for(i = 0; i < G.arcnum; i++)//打乱数组
42![]()
{
43
j = rand()%G.arcnum ;//随机选取数组下标,注意整除的是数组大小
44
if (j>=0 && j<G.arcnum)
45![]()
{
46
int exchange=weight[i];
47
weight[i]=weight[j];
48
weight[j]=exchange;
49
}
50
}
51
52
53
i = 0;
54
j = 0;
55
while (2*i+1 < G.vexnum)//先将V-1条边分配,为保证图是连通的,按完全二叉树结构产生边
56
//当然这样产生的边不够随机性
57![]()
{
58
p = new ArcNode;
59
p->adjvex = 2*i+1;
60
p->weight = weight[j++];
61
p->next = NULL;
62
G.vertices[i].next = p;//k尚无邻接点,p作为第一个邻接点
63
64
if (2*i+2 < G.vexnum)
65![]()
{
66
q = p;
67
p->next = new ArcNode;//动态分配表结点
68
p = p->next;
69
p->adjvex = 2*i+2;
70
p->weight = weight[j++];
71
p->next = NULL;
72
G.vertices[i].next->next = p;
73
}
74
else
75
break;//V-1条边分配完毕
76
77
i++;
78
}
79
80
81
for(i = G.vexnum-1; i < G.arcnum; )//将剩下的边分配出去
82![]()
{
83
flag = false;
84
85
m = rand()%G.vexnum; //随机弧尾序号
86
n = rand()%G.vexnum; //随机弧头序号
87
while (m == n) //不考虑指向自身的结点
88![]()
{
89
n = rand()%G.vexnum;
90
}
91
92
if (G.vertices[m].next != NULL)
93![]()
{
94
p = G.vertices[m].next;
95
}
96
else //k尚无邻接点
97![]()
{
98
p = NULL;
99
q = NULL;
100
}
101
102
while (p != NULL)
103![]()
{
104
if (p->adjvex == n)
105![]()
{
106
flag = true;//边已经存在
107
break;
108
}
109
else//继续往下找
110![]()
{
111
q = p;
112
p = p->next;
113
}
114
}
115
116
if (!flag)//Vm→Vn的边本不存在
117![]()
{
118
p = new ArcNode;
119
120
p->adjvex = n;
121
p->weight = weight[i];
122
p->next = NULL;
123
if (q!=NULL)
124![]()
{
125
q->next = p;
126
}
127
else
128
G.vertices[m].next = p;
129
130
i++;//仅当成功分配一条边才i++; 本循环存在死循环的可能,即永远碰巧都分配不出去
131
//考虑复杂度和出错的概率,姑且不管它.
132
}
133
}
134![]()
135
delete [] weight;
136
}
137![]()
138![]()
139![]()
140
void
ShowGraph(ALGraph G)
//
打印创建后的图
141![]()
{
142
for(int i=0; i<G.vexnum; i++)
143![]()
{
144
ArcNode * p = G.vertices[i].next;
145
cout<<"source V"<<G.vertices[i].adjvex<<":";
146
while(p!=NULL)
147![]()
{
148
cout<<" V"<<p->adjvex;
149
cout<<"(w: "<<p->weight<<")";
150
p=p->next;
151
}
152
cout<<endl;
153![]()
154
}
155
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
ClearUp.h: 销毁图G,回收工作
1
#include
"
ALGraph.h
"
2![]()
3
void
ClearUp(ALGraph
&
G)
//
销毁图G
4![]()
{
5
ArcNode* p = NULL;
6
ArcNode* q = NULL;
7
int i;
8
for(i=0; i<G.vexnum; i++) //回收表结点
9![]()
{
10
p = G.vertices[i].next;
11
while (p != NULL)
12![]()
{
13
q = p->next;
14
delete p;
15
p = q;
16
}
17
}
18![]()
19
delete [] G.vertices; //回收头结点
20
G.vertices = NULL;
21
G.arcnum = 0;
22
G.vexnum = 0;
23
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DFS.h: 深度优先遍历
1
#include
"
ALGraph.h
"
2
#include
"
Stack.h
"
3![]()
4
void
DFSVisit(ALGraph
&
G, VNode
&
s,
int
&
time);
5![]()
6
void
DFS(ALGraph
&
G)
7![]()
{
8
int time = 0;
9
for(int i=0; i<G.vexnum; i++) //初始化
10![]()
{
11
G.vertices[i].color = WHITE;
12
G.vertices[i].father = NULL;
13
}
14
15
for(i=0; i<G.vexnum; i++) //深度优先遍历
16![]()
{
17
if (G.vertices[i].color == WHITE)
18
DFSVisit(G, G.vertices[i], time);
19
}
20
}
21![]()
22![]()
void
DFSVisit(ALGraph
&
G, VNode
&
s,
int
&
time)
/**/
/*从s出发深度优先搜索图G*/
23![]()
{
24
Stack S;
25
ArcNode * p;
26
VNode* k;//出栈顶点序号
27
VNode* t;
28
29![]()
InitStack(S); /**//*初始化空栈*/
30
31
s.color = GRAY;
32
time = time +1;
33
s.d = time;
34
Push(S, &s);
35
while(!Empty(S))
36![]()
{
37
t = GetTop(S); //弹出栈顶,返回栈顶元素地址
38![]()
39
for(p=t->next; p && G.vertices[p->adjvex].color!=WHITE; p=p->next);
40
//找到第一个白色邻接点
41
if(p == NULL)//t的所有邻接点都已访问
42![]()
{
43
k = Pop(S);
44
k->color = BLACK;
45
time = time+1;
46
k->f = time;//结束时间
47
}
48
else//继续深度访问
49![]()
{
50
Push(S,&G.vertices[p->adjvex]);
51
G.vertices[p->adjvex].father = t;
52
G.vertices[p->adjvex].color = GRAY;
53
time = time+1;
54
G.vertices[p->adjvex].d = time;//入栈之时即发现之时d
55
}
56
}
57
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
Bellman_Ford算法
1
#include
"
ALGraph.h
"
2![]()
3
void
Initialize_Single_Source(ALGraph
&
G,VNode
&
s)
//
初始化
4![]()
{
5
for(int i=0; i<G.vexnum; i++)
6![]()
{
7
G.vertices[i].father = NULL;
8
G.vertices[i].d = wuqiong;
9
}
10
s.d = 0;
11
}
12![]()
13
void
Relax(VNode
&
v, VNode
&
w, ArcNode
*
p)
//
Relax操作,更新最短路径
14![]()
{
15
if (w.d > v.d+ p->weight)
16![]()
{
17
w.d = v.d+ p->weight;
18
w.father = &v;
19
}
20
}
21![]()
22
bool
Bellman_Ford(ALGraph
&
G, VNode
&
s)
23![]()
{
24
ArcNode * p;
25
int i;
26
27
Initialize_Single_Source(G, s);
28![]()
29
for (int j=0; j<G.vexnum-1; j++)//V-1趟Relax
30![]()
{
31
for(i=0; i<G.vexnum; i++)//沿着头结点
32![]()
{
33
for (p=G.vertices[i].next; p!=NULL; p=p->next)//沿着表结点
34![]()
{
35
Relax(G.vertices[i], G.vertices[p->adjvex], p);
36
}
37
}
38
}
39![]()
40
//判断是否有负回路
41
for(i=0; i<G.vexnum; i++)//沿着头结点
42![]()
{
43
for (p=G.vertices[i].next; p!=NULL; p=p->next)//沿着表结点
44![]()
{
45
if (G.vertices[p->adjvex].d > G.vertices[i].d+ p->weight)
46![]()
{
47
cout<<"图中有负权值回路."<<endl;
48
return false;
49
}
50
}
51
}
52![]()
53
return true;
54
}
55![]()
56
void
PrintPath(ALGraph G, VNode s, VNode v)
//
递归打印最短路径
57![]()
{
58
if (v.father != NULL)
59![]()
{
60
PrintPath(G, s, *v.father);
61
cout<<"v"<<v.adjvex<<"→";
62
}
63
else
64
cout<<"v"<<s.adjvex<<"→";
65
}
66![]()
67
void
ShortestPath(ALGraph G, VNode s)
68![]()
{
69
int i=0;
70
cout<<"顶点为v0,v1,v2,……,v"<<G.vexnum-1<<endl;
71
cout<<"从源点v"<<s.adjvex<<"到其它所有顶点的最短距离:"<<endl;
72
for(i=0; i<G.vexnum; i++)//沿着头结点
73![]()
{
74
cout<<"到顶点v"<<i<<": ";
75
PrintPath(G, s, G.vertices[i]);
76
cout<<endl;
77
}
78
}
79![]()
80
void
DFSPath(ALGraph G, VNode s)
//
打印DFS各顶点的发现时间和结束时间d/f;
81![]()
{
82
int i=0;
83
for(i=0; i<G.vexnum; i++)//沿着头结点
84![]()
{
85
//PrintPath(G, s, *k);
86
cout<<"v"<<G.vertices[i].adjvex<<":"<<G.vertices[i].d<<" / "
87
<<G.vertices[i].f<<" 颜色:"<<G.vertices[i].color;
88
cout<<endl;
89
}
90
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
main函数:对不同输入规模计时分析算法性能
1
#include
"
ALGraph.h
"
2
#include
"
DFS.h
"
3
#include
"
CreateALGraph.h
"
4
#include
"
Bellman_Ford.h
"
5
#include
"
ClearUp.h
"
6
#include
"
CTimer.h
"
7![]()
8
#include
<
iostream
>
9
#include
<
cstdio
>
10
#include
<
cmath
>
11
#include
<
cstring
>
12![]()
13![]()
14
int
main()
15![]()
16![]()
{
17
//输入规模
18![]()
const int NUM1[6] =
{1000,2500,5000,7500,10000,15000};
19![]()
const int RATE1[4] =
{pow(2,2),pow(2,4),pow(2,6),pow(2,8)};
20![]()
const int NUM2[6] =
{200,400,800,1200,1600,2000};
21![]()
const int RATE2[5] =
{pow(2,2),pow(2,3),pow(2,4),pow(2,5),pow(2,6)};
22
23
ALGraph G; //图G
24
CTimer timer; //计数器
25
int i,j;
26
double runningtime; //运行时间(毫秒/ms)
27
long vexnum; //图顶点数
28
long arcnum; //图边数
29
30
for(i=0; i<6; i++)//DFS运行时间分析
31![]()
{
32
cout<<"/********************************/"<<endl;
33
for(j=0;j<4; j++)
34![]()
{
35
vexnum = NUM1[i];
36
arcnum = NUM1[i]*RATE1[j];
37
CreateALGraph(G, vexnum, arcnum);//创建图
38
timer.Start(); //计时开始
39
DFS(G);
40
runningtime = timer.End();//计时结束
41
cout<<" "<<runningtime<<"ms"<<endl;
42
// DFSPath(G, *G.vertices);
43
ClearUp(G);
44
}
45
}
46
47
for(i=0; i<6; i++)//Bellman_Ford最短路径算法运行时间分析
48![]()
{
49
cout<<"/********************************/"<<endl;
50![]()
for(j=0;j<5; j++)
{
51
vexnum = NUM2[i];
52
arcnum = NUM2[i]*RATE2[j];
53
CreateALGraph(G, vexnum, arcnum);
54
// ShowGraph(G); //打印原始图
55
timer.Start(); //计时开始
56
Bellman_Ford(G, *G.vertices);
57
runningtime = timer.End();//计时结束
58
cout<<" "<<runningtime<<"ms"<<endl;
59
// ShortestPath(G, *G.vertices);//打印源点v0到各顶点的最短路径
60
ClearUp(G);
61
}
62
}
63
64
65
return 0;
66
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66