zoukankan      html  css  js  c++  java
  • 无向网的最小生成树——Prim算法(转)

    适用于边较为稠密型的连通网

    假设N=(V,{VR})是一个连通网,TE是V上的最小生成树的边的集合,Prim算法从U={u0}(u0∈V) ,TE={}开始,重复执行下面的操作:

    在所以的u∈U,v∈V-U的边(u,v)∈VR中找一条权值最小的边(u0,v0),并入集合TE,同时v0并入U,直至U=V为止。此时TE中必有n-1条边,则T=(V,{TE})为N的最小生成树。为了实现这个算法,需引入一个辅助的数组closedge,记录从U到V-U具有最小权值的边,每个顶点Vi对应数组中的closedege[i-1],包括两个域,一个是adjvex,存储该边依附的在U中顶点,另一个是Lowcost,存储权值。下面是代码:

    tree.h文件

      1 #include<iostream>
    2 #include<string>
    3 #include<queue>
    4 using namespace std;
    5
    6 const int MAX_VEX_NUM=20;
    7 bool visited[20];
    8
    9 class MGraph;
    10
    11 class CS_Tree;
    12 //树结点
    13 class CSnode
    14 {
    15 string data;
    16 CSnode *firstchild;
    17 CSnode *nextsibling;
    18 friend class CS_Tree;
    19 friend class MGraph;
    20 };
    21
    22 //树类定义
    23 class CS_Tree
    24 {
    25 public:
    26 void PreRoot_Traverse(CSnode *T) //先根遍历
    27 {
    28 if(T)
    29 {
    30 cout<<T->data<<" ";
    31 PreRoot_Traverse(T->firstchild);
    32 PreRoot_Traverse(T->nextsibling);
    33 }
    34 }
    35
    36 void PostRoot_Traverse(CSnode *T) //后根遍历
    37 {
    38 if(T)
    39 {
    40 PostRoot_Traverse(T->firstchild);
    41 cout<<T->data<<" ";
    42 PostRoot_Traverse(T->nextsibling);
    43 }
    44 }
    45
    46 void LevelOrder_Traverse(CSnode *T) //层次遍历
    47 {
    48 queue<CSnode *> q;
    49 CSnode *t;
    50 q.push(T);
    51 do
    52 {
    53 t=q.front();
    54 do
    55 {
    56 cout<<t->data<<" ";
    57 if(t->firstchild)
    58 q.push(t->firstchild);
    59 t=t->nextsibling;
    60 }while(t);
    61 q.pop();
    62 }while(!q.empty());
    63 }
    64 };
    65
    66
    67 class ArcNode
    68 {
    69 public:
    70 int adj;
    71 bool search;//作为建立最小生成树的时结点是否被访问过的标志
    72 friend class MGraph;
    73 };
    74
    75 class temp //为建树所用
    76 {
    77 public:
    78 int i;
    79 int j;
    80 int weight;
    81 friend class MGraph;
    82 };
    83
    84 class closedge //为建树所用
    85 {
    86 public:
    87 string adjvex;
    88 int weight;
    89 friend class MGraph;
    90 };
    91
    92 class MGraph
    93 {
    94 private:
    95 string vexs[MAX_VEX_NUM];//顶点数组
    96 ArcNode arcs[MAX_VEX_NUM][MAX_VEX_NUM];//邻接矩阵
    97 int vexnum;//顶点数
    98 int arcnum;//边数
    99 public:
    100 void Create_MG()
    101 {
    102 int i,j,k;
    103 cout<<"输入图的顶点数和边数:";
    104 cin>>vexnum>>arcnum;
    105 cout<<"输入各个顶点的民称:";
    106 for(i=0;i<vexnum;i++)
    107 cin>>vexs[i];
    108
    109 for(i=0;i<vexnum;i++)
    110 for(int j=0;j<vexnum;j++)
    111 {
    112 arcs[i][j].adj=-1;
    113 arcs[i][j].search=false;
    114 }
    115 //上面是初始化邻接矩阵
    116
    117 for(k=0;k<arcnum;k++)
    118 {
    119 cout<<"输入每条边对应的两个顶点以及该边的权值:";
    120 string v1,v2;
    121 int w;
    122 cin>>v1>>v2>>w;
    123 i=Locate_Vex(v1);
    124 j=Locate_Vex(v2);
    125
    126 while(i<0|| i>vexnum-1 || j<0 || j>vexnum-1)
    127 {
    128 cout<<"结点位置输入错误,重新输入: ";
    129 cin>>v1>>v2>>w;
    130 i=Locate_Vex(v1);
    131 j=Locate_Vex(v2);
    132 }
    133
    134 arcs[i][j].adj=w;
    135 arcs[j][i]=arcs[i][j]; //置对称边
    136 }
    137 cout<<"图构造完成"<<endl;
    138 }
    139
    140 int Locate_Vex(string x) //用于确定顶点在顶点数组中的位置
    141 {
    142 for(int k=0;vexs[k]!=x;k++);
    143 return k;
    144 }
    145
    146 void DFS(int v)
    147 {
    148 visited[v]=true;
    149 cout<<vexs[v]<<" ";
    150
    151 for(int j=0;j<vexnum;j++)
    152 if(arcs[v][j].adj!=-1 && !visited[j])
    153 DFS(j);
    154 }
    155
    156 //深度优先遍历图
    157 void DFS_Traverse()
    158 {
    159 //visited数组用来作为是否已访问的标志
    160 for(int i=0;i<vexnum;i++)
    161 visited[i]=false;
    162
    163 for(int v=0;v<vexnum;v++)
    164 if(!visited[v])
    165 DFS(v);
    166 }
    167
    168 //广度优先遍历
    169 void BFS_Traverse()
    170 {
    171 queue<int> q;
    172 int u,w,v;
    173 for(v=0;v<vexnum;v++)
    174 visited[v]=false;
    175
    176 for(v=0;v<vexnum;v++)
    177 {
    178 if(!visited[v])
    179 {
    180 visited[v]=true;
    181 cout<<vexs[v]<<" ";
    182 q.push(v);
    183
    184 while(!q.empty())
    185 {
    186 u=q.front();
    187 q.pop();
    188
    189 for(w=0;w<vexnum;w++)
    190 {
    191 if(arcs[u][w].adj!=-1 && !visited[w])
    192 {
    193 visited[w]=true;
    194 cout<<vexs[w]<<" ";
    195 q.push(w);
    196 }
    197 }
    198 }
    199 }
    200 }
    201 }
    202
    203 CSnode *Prim_Min_Pre(int v,closedge c[])
    204 {
    205 string *u=new string[20];//U中保存已经作为树结点的顶点
    206 int num=0;
    207 int low;
    208 for(int l=0;l<vexnum;l++) //作为顶点是否已经在U中的标志
    209 visited[l]=false;
    210 u[num]=vexs[v];
    211 visited[v]=true;
    212 num++;
    213
    214 for(int vex=1;vex<vexnum;vex++)
    215 {
    216 temp min;
    217 low=99999;
    218 /*--------------------------------
    219 /下面的for循环是找出和U中所有顶点
    220 /相邻的非U中的顶点中边权值最小的一条
    221 /--------------------------------*/
    222 for(int j=0;j<num;j++)
    223 {
    224 int i=Locate_Vex(u[j]);
    225 for(int k=0;k<vexnum;k++)
    226 {
    227 if(arcs[i][k].adj!=-1 && arcs[i][k].adj<low && !arcs[i][k].search &&!visited[k])
    228 {
    229
    230 low=arcs[i][k].adj;
    231 min.i=i;
    232 min.j=k;
    233 min.weight=low;
    234 }
    235 }
    236 }
    237 c[min.j].adjvex=vexs[min.i];
    238 c[min.j].weight=min.weight;
    239 u[num]=vexs[min.j];
    240 num++;
    241 visited[min.j]=true;
    242 arcs[min.i][min.j].search=arcs[min.j][min.i].search=true; //将已经作为树的边的边标志为已访问
    243 if(num==vexnum)
    244 break ;
    245 }
    246 CSnode *T=NULL;
    247 Prim_TREE(v,T,c);//将c数组中的元素转换为树
    248 return T;
    249
    250 }
    251
    252 void Prim_TREE(int v,CSnode *&T,closedge c[])
    253 {
    254 CSnode *r=NULL,*p=NULL,*q=NULL;
    255 bool first;
    256 queue<CSnode *> qu;
    257 bool connected[20];//作为该顶点是否已经连接在树中的标志
    258 for(int i=0;i<vexnum;i++)
    259 connected[i]=false;
    260
    261 qu.push(T);
    262
    263 //下面是建树过程,总体思路和图的广度优先生成树的是一样的
    264 while(!qu.empty())
    265 {
    266 r=qu.front();
    267 qu.pop();
    268
    269 if(!r && !T)//第一次进来时,T为空
    270 {
    271 T=new CSnode;
    272 T->data=vexs[v];
    273 T->firstchild=T->nextsibling=NULL;
    274 r=T;
    275 }
    276
    277 first=true;
    278 for(int i=1;i<vexnum;i++)
    279 {
    280 if(!connected[i] && c[i].adjvex==r->data)
    281 {
    282 connected[i]=true;
    283 p=new CSnode;
    284 p->data=vexs[i];
    285 p->firstchild=p->nextsibling=NULL;
    286 qu.push(p);
    287 if(first)
    288 {
    289 r->firstchild=p;
    290 first=false;
    291 }
    292 else
    293 q->nextsibling=p;
    294 q=p;
    295 }
    296 }
    297 }
    298 }
    299 };

      测试函数main.cpp

     1 #include"tree.h"
    2
    3 int main()
    4 {
    5 MGraph G;
    6 G.Create_MG();
    7
    8 cout<<"图的深度优先遍历为:";
    9 G.DFS_Traverse();
    10 cout<<endl;
    11
    12 cout<<"图的广度优先遍历为:";
    13 G.BFS_Traverse();
    14 cout<<endl;
    15
    16 cout<<"要从哪个顶点开始建立最小生成树:";
    17 int v;
    18 cin>>v;
    19
    20 closedge c[20];
    21 CSnode *T=NULL;
    22 T=G.Prim_Min_Pre(v,c);
    23 CS_Tree root;
    24 cout<<"建树完成"<<endl;
    25
    26 cout<<"最小生成树的先根遍历为:";
    27 root.PreRoot_Traverse(T);
    28 cout<<endl;
    29
    30 cout<<"最小生成树的后根遍历为:";
    31 root.PostRoot_Traverse(T);
    32 cout<<endl;
    33
    34 cout<<"最小生成树的层次遍历为:";
    35 root.LevelOrder_Traverse(T);
    36 cout<<endl;
    37
    38 return 0;
    39 }

      下面是测试结果

     1 输入图的顶点数和边数:9 15
    2 输入各个顶点的民称:v1 v2 v3 v4 v5 v6 v7 v8 v9
    3 输入每条边对应的两个顶点以及该边的权值:v1 v6 7
    4 输入每条边对应的两个顶点以及该边的权值:v1 v7 3
    5 输入每条边对应的两个顶点以及该边的权值:v1 v2 2
    6 输入每条边对应的两个顶点以及该边的权值:v2 v7 6
    7 输入每条边对应的两个顶点以及该边的权值:v2 v3 4
    8 输入每条边对应的两个顶点以及该边的权值:v6 v5 6
    9 输入每条边对应的两个顶点以及该边的权值:v6 v9 5
    10 输入每条边对应的两个顶点以及该边的权值:v7 v9 1
    11 输入每条边对应的两个顶点以及该边的权值:v7 v8 3
    12 输入每条边对应的两个顶点以及该边的权值:v3 v8 2
    13 输入每条边对应的两个顶点以及该边的权值:v3 v4 2
    14 输入每条边对应的两个顶点以及该边的权值:v9 v5 2
    15 输入每条边对应的两个顶点以及该边的权值:v9 v8 4
    16 输入每条边对应的两个顶点以及该边的权值:v8 v4 8
    17 输入每条边对应的两个顶点以及该边的权值:v5 v4 1
    18 图构造完成
    19 图的深度优先遍历为:v1 v2 v3 v4 v5 v6 v9 v7 v8
    20 图的广度优先遍历为:v1 v2 v6 v7 v3 v5 v9 v8 v4
    21 要从哪个顶点开始建立最小生成树:0
    22 建树完成
    23 最小生成树的先根遍历为:v1 v2 v7 v9 v5 v4 v3 v8 v6
    24 最小生成树的后根遍历为:v2 v8 v3 v4 v5 v6 v9 v7 v1
    25 最小生成树的层次遍历为:v1 v2 v7 v9 v5 v6 v4 v3 v8
    26 Press any key to continue

      按照输入所生成的无向网和生成树如下








  • 相关阅读:
    Javascript倒计时
    Windows Live Writer的使用
    liunx下查看服务器硬件信息
    Ant+JSDocTookit生成Javascript文档
    文本文件及二进制文件的大小, Unicode字符编码
    读书笔记之:Linux与Unix shell编程指南v1
    读书笔记之:Linux程序设计(第2版)
    JM8.6中的encode_one_macroblock注释
    在fedora中挂载windows分区
    fedora14的yum源总结
  • 原文地址:https://www.cnblogs.com/math2010/p/2142083.html
Copyright © 2011-2022 走看看