DFS和Bellman_Ford算法的代码实现

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******************************************/


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


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

CTimer.h:CTimer类,计时功能,单位毫秒
 1 #ifndef CTIMER_H
 2 #define  CTIMER_H
 3
 4 #include  " Windows.h "
 5
 6 class    CTimer   
 7 {   
 8public:   
 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    }
   
25private:   
26    LARGE_INTEGER   m_Frequency;   
27    LARGE_INTEGER   m_StartCount;   
28}
;
29
30 #endif // CTIMER_H   

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}


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}


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->= 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}

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}



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}

你可能感兴趣的:(DFS和Bellman_Ford算法的代码实现)