一、一些概念的理解:
生成树:一个连通图的生成树是原图的极小连通图,它包含原图中的所有顶点,而且有尽可能少的边。也就意味着对于生成树来说,若砍去他的一条边,就会使生成树变成一个非连通图;若给他增加一条边,就会形成图中的一个回路。
最小生成树:
1、概念:
对于一个带权的连通图(即网络),如何找出一棵生成树,使得各边上的权值总和达到最小。
2、原则:
(1)必须只使用该网络中的边来构造
(2)必须只使用且仅适用n-1条边来连接网络中的n个顶点
(3)不能使用产生回路的边
3、算法:
(1)克鲁斯卡尔算法(Kruskal):
将各边的权值从小到大排列,依次连接符合原则且最小的边。
核心操作:father[i]
#pragma once
#include"AllHead.h"
#include<stdlib.h>
#include<search.h>
#define MAXSIZE 10
struct EdgeNode
{
int x;
int y;
int weight;
};
template<class T,class E>
class Grap
{
private:
T *VerticesList; //顶点元素
E **Edge; //动态的二维数组
int maxVertices; //预定最多的顶点个数
int numVertices; //记录元素的个数
int numEdge; //记录边的个数
public:
Grap(int sz = 0):maxVertices(sz>MAXSIZE?sz:MAXSIZE),numVertices(0),numEdge(0)
{
int i,j;
Edge = new E*[maxVertices];
for(i = 0;i<maxVertices;++i)
{
Edge[i] = new E[maxVertices];
}
VerticesList = new T[maxVertices];
for(i=0;i<maxVertices;++i)
{
VerticesList[i] = '#';
}
for(i = 0;i<maxVertices;i++)
{
for(j = 0;j<maxVertices;++j)
Edge[i][j] = 0;
}
}
Grap(T ar[],int sz):maxVertices(sz),numVertices(sz),numEdge(0)
{
int i,j;
Edge = new E*[maxVertices];
for(i = 0;i<maxVertices;++i)
{
Edge[i] = new E[maxVertices];
}
VerticesList = new T[maxVertices];
for(i=0;i<maxVertices;++i)
{
VerticesList[i] = ar[i];
}
for(i = 0;i<maxVertices;i++)
{
for(j = 0;j<maxVertices;++j)
Edge[i][j] = 0;
}
}
public:
int GetVerticespos(T x)
{
int i;
for(i = 0;i<numVertices;++i)
{
if(VerticesList[i] == x)
return i;
}
return -1;
}
int NumberOfVertices()
{return numVertices;}
int NumberOfEdge()
{return numEdge;}
public:
int RemoveEdge(T x1,T x2)
{
int v1 = GetVerticespos(x1);
int v2 = GetVerticespos(x2);
if(v1 == -1||v2 == -1)
return -1;
Edge[v1][v2] = 0;
Edge[v2][v1] = 0;
--numEdge;
return OK;
}
int RemoveVertex(T x)
{
int v = GetVerticespos(x);
if(v == -1)
{
cout<<"结点不存在..."<<endl;
return ERROR;
}
int i,j,tempedge = 0;
for(int i=0; i<numVertices; ++i)
{
if(Edge[v][i] != 0)
tempedge++;
}
VerticesList[v] = VerticesList[numVertices - 1];
for(i = 0;i<numVertices;++i)
{
Edge[v][i] = Edge[numVertices - 1][i];
}
for(j = 0;j<numVertices;++j)
{
Edge[j][v] = Edge[j][numVertices - 1];
}
--numVertices;
numEdge -= tempedge;
}
int GetNextNeighbor(T x1,T x2)
{
int i;
int v1 = GetVerticespos(x1);//头
int v2 = GetVerticespos(x2);//第一个子
if(v1 == -1||v2 == -1)
{
cout<<"有个顶点不存在...";
return ERROR;
}
if(Edge[v1][v2] == 0)
{
cout<<"第一条线并不存在....";
return ERROR;
}
for(i = v2+1;i<numVertices;++i)
{
if(Edge[v1][i] == 1)
return i;
}
cout<<"没有下一个顶点....";
return -1;
}
int GetFirstNeighbor(T x)
{
int i;
int v = GetVerticespos(x);
if(v == -1)
{
cout<<"没有这个结点..."<<endl;
}
else
{
for(i=0;i<numVertices;++i)
{
if(Edge[v][i] == 1)
return i;
}
}
return -1;
}
int InsertEdge(T x1,T x2,int weight)
{
int v1 = GetVerticespos(x1);
int v2 = GetVerticespos(x2);
if(v1 != -1&&v2 != -1)
{
Edge[v1][v2] = weight;
Edge[v2][v1] = weight;
++numEdge;
return OK;
}
else
return ERROR;
}
int InsertVertices(T x)
{
if(numVertices >= maxVertices)
{
cout<<"空间已满(Insert)........"<<endl;
return ERROR;
}
VerticesList[numVertices++] = x;
return OK;
}
void ShowGrap()
{
int i,j;
cout<<" ";
for(i=0;i<numVertices;++i)
{
cout<<VerticesList[i]<<" ";
}
cout<<endl;
for(i = 0;i<numVertices;i++)
{
cout<<VerticesList[i]<<" ";
for(j = 0;j<numVertices;++j)
cout<<Edge[i][j]<<" ";
cout<<endl;
}
}
bool Is_Same(int father[],int i,int j)
{
while(father[i] != i)
{
i = father[i];
}
while(father[j] != j)
{
j = father[j];
}
return i == j;
}
void Mark_Same(int father[],int i,int j)
{
while(father[i]!=i)
{
i = father[i];
}
while(father[j]!=j)
{
j = father[j];
}
father[j] = i;
}
void Kruskal()
{
int k = 0;
int n = numVertices;
EdgeNode *reminfo = new EdgeNode[(n*(n-1))/2];
for(int i=0;i<numVertices;++i)
{
for(int j=i;j<numVertices;++j)
{
if(Edge[i][j]!=0)
{
reminfo[k].x = i;
reminfo[k].y = j;
reminfo[k].weight = Edge[i][j];
k++;
}
}
}
/用一个结构体数组将有权的边存起来。
qsort(reminfo,k,sizeof(EdgeNode),compare);
int *father = new int[k];//这个是核心!!!
for(int i=0;i<k;i++)
{
father[i] = i;
}
int v1,v2;
for(int i=0;i<k;++i)
{
if(!Is_Same(father,reminfo[i].x,reminfo[i].y))
{
v1 = reminfo[i].x;
v2 = reminfo[i].y;
cout<<i<<':'<<VerticesList[v1]<<"-->"<<VerticesList[v2]<<':'<<reminfo[i].weight<<endl;
Mark_Same(father,v1,v2);
}
}
}
};
//注意这个函数必须写到外面。
int compare(const void* w1,const void* w2)
{
return ((*(EdgeNode*)w1).weight - (*(EdgeNode*)w2).weight);
}
主函数:
#include"grap.h"
int main()
{
Grap<char,int> gp1;
cout<<"======================================"<<endl;
gp1.InsertVertices('A');
gp1.InsertVertices('B');
gp1.InsertVertices('C');
gp1.InsertVertices('D');
gp1.InsertVertices('E');
gp1.InsertVertices('F');
gp1.InsertEdge('A','B',6);
gp1.InsertEdge('A','C',1);
gp1.InsertEdge('A','D',5);
gp1.InsertEdge('B','C',5);
gp1.InsertEdge('D','C',5);
gp1.InsertEdge('E','C',6);
gp1.InsertEdge('F','C',4);
gp1.InsertEdge('B','E',3);
gp1.InsertEdge('E','F',6);
gp1.InsertEdge('D','F',2);
gp1.ShowGrap();
cout<<"-------------------------------"<<endl;
gp1.Kruskal();
return 0;
}
(2)普利姆算法(Prim)
从指定的一个点开始,链接权值最小的边,两个顶点合并遍历所有点,找权值最小的边,再相连,在合并(这个过程中不可以连上形成回路的边)......直到所有点都连完了。
核心操作是:增加两个数组:lowcost[i]和mst[i]
#pragma once
#include"AllHead.h"
#define MAXSIZE 10
#define MAX_COST 0x7FFFFFFF
template<class T,class E>
class Grap
{
private:
T *VerticesList; //顶点元素
E **Edge; //动态的二维数组
int maxVertices; //预定最多的顶点个数
int numVertices; //记录元素的个数
int numEdge; //记录边的个数
public:
Grap(int sz = 0):maxVertices(sz>MAXSIZE?sz:MAXSIZE),numVertices(0),numEdge(0)
{
int i,j;
Edge = new E*[maxVertices];
for(i = 0;i<maxVertices;++i)
{
Edge[i] = new E[maxVertices];
}
VerticesList = new T[maxVertices];
for(i=0;i<maxVertices;++i)
{
VerticesList[i] = '#';
}
for(i = 0;i<maxVertices;i++)
{
for(j = 0;j<maxVertices;++j)
Edge[i][j] = MAX_COST;
}
for(i = 0;i<maxVertices;++i)
{
for(j = 0;j<maxVertices;++j)
{
if(i == j)
{
Edge[i][j] = 0;
}
}
}
}
Grap(T ar[],int sz):maxVertices(sz),numVertices(sz),numEdge(0)
{
int i,j;
Edge = new E*[maxVertices];
for(i = 0;i<maxVertices;++i)
{
Edge[i] = new E[maxVertices];
}
VerticesList = new T[maxVertices];
for(i=0;i<maxVertices;++i)
{
VerticesList[i] = ar[i];
}
for(i = 0;i<maxVertices;i++)
{
for(j = 0;j<maxVertices;++j)
Edge[i][j] = 0;
}
}
public:
int GetVerticespos(T x)
{
int i;
for(i = 0;i<numVertices;++i)
{
if(VerticesList[i] == x)
return i;
}
return -1;
}
int NumberOfVertices()
{return numVertices;}
int NumberOfEdge()
{return numEdge;}
public:
int RemoveEdge(T x1,T x2)
{
int v1 = GetVerticespos(x1);
int v2 = GetVerticespos(x2);
if(v1 == -1||v2 == -1)
return -1;
Edge[v1][v2] = 0;
Edge[v2][v1] = 0;
--numEdge;
return OK;
}
int RemoveVertex(T x)
{
int v = GetVerticespos(x);
if(v == -1)
{
cout<<"结点不存在..."<<endl;
return ERROR;
}
int i,j,tempedge = 0;
for(int i=0; i<numVertices; ++i)
{
if(Edge[v][i] != 0)
tempedge++;
}
VerticesList[v] = VerticesList[numVertices - 1];
for(i = 0;i<numVertices;++i)
{
Edge[v][i] = Edge[numVertices - 1][i];
}
for(j = 0;j<numVertices;++j)
{
Edge[j][v] = Edge[j][numVertices - 1];
}
--numVertices;
numEdge -= tempedge;
}
int GetNextNeighbor(T x1,T x2)
{
int i;
int v1 = GetVerticespos(x1);//头
int v2 = GetVerticespos(x2);//第一个子
if(v1 == -1||v2 == -1)
{
cout<<"有个顶点不存在...";
return ERROR;
}
if(Edge[v1][v2] == 0)
{
cout<<"第一条线并不存在....";
return ERROR;
}
for(i = v2+1;i<numVertices;++i)
{
if(Edge[v1][i] == 1)
return i;
}
cout<<"没有下一个顶点....";
return -1;
}
int GetFirstNeighbor(T x)
{
int i;
int v = GetVerticespos(x);
if(v == -1)
{
cout<<"没有这个结点..."<<endl;
}
else
{
for(i=0;i<numVertices;++i)
{
if(Edge[v][i] == 1)
return i;
}
}
return -1;
}
int GetWeight(int v1,int v2)
{
if(v1 == -1||v2 == -1)
return MAX_COST;
return Edge[v1][v2];
}
int InsertEdge(T x1,T x2,int weight)
{
int v1 = GetVerticespos(x1);
int v2 = GetVerticespos(x2);
if(v1 != -1&&v2 != -1)
{
Edge[v1][v2] = weight;
Edge[v2][v1] = weight;
++numEdge;
return OK;
}
else
return ERROR;
}
int InsertVertices(T x)
{
if(numVertices >= maxVertices)
{
cout<<"空间已满(Insert)........"<<endl;
return ERROR;
}
VerticesList[numVertices++] = x;
return OK;
}
void ShowGrap()
{
int i,j;
cout<<" ";
for(i=0;i<numVertices;++i)
{
cout<<VerticesList[i]<<" ";
}
cout<<endl;
for(i = 0;i<numVertices;i++)
{
cout<<VerticesList[i]<<" ";
for(j = 0;j<numVertices;++j)
{
if(Edge[i][j] == MAX_COST)
{
cout<<"@ ";
}
else
{
cout<<Edge[i][j]<<" ";
}
}
cout<<endl;
}
}
void Prim(T x)
{
int begin,end;
E cost;
int n = numVertices;
E *lowcost = new E[n];
int *mst = new int[n];
assert(lowcost != NULL&&mst != NULL);
int k = GetVerticespos(x);
for(int i=0;i<n;++i)
{
if(i != k)
{
lowcost[i] = GetWeight(k,i);//把起始点的权逐个放到lowcost的数组里
mst[i] = k;
}
else
{
lowcost[i] = 0;
}
}
for(int i=0;i<n-1;++i)
{
int min = MAX_COST;//记录上次一x为顶点的边的权值
int min_index = -1;//记录上次一x为顶点的边的终点索引号
for(int j=0;j<n;++j)
{
if(lowcost[j]!=0 && lowcost[j]<min)
{
min = lowcost[j];
min_index = j;
}
}
//打印信息;
begin = mst[min_index];
end = min_index;
cout<<VerticesList[begin]<<"--->"<<VerticesList[end]<<':'<<min<<endl;
//合并顶点。
lowcost[min_index] = 0;
for(int j = 0;j<n;++j)
{
cost = GetWeight(min_index,j);
if(cost < lowcost[j])
{
lowcost[j] = cost;
mst[j] = min_index;
}
}
}
delete[]lowcost;
delete[] mst;
}
};
主函数:
#include"MinSpanTree.h"
int main()
{
Grap<char,int> MinST;
MinST.InsertVertices('A');
MinST.InsertVertices('B');
MinST.InsertVertices('C');
MinST.InsertVertices('D');
MinST.InsertVertices('E');
MinST.InsertVertices('F');
MinST.InsertEdge('A','B',6);
MinST.InsertEdge('A','C',1);
MinST.InsertEdge('A','D',5);
MinST.InsertEdge('C','B',5);
MinST.InsertEdge('E','B',3);
MinST.InsertEdge('C','E',6);
MinST.InsertEdge('C','F',4);
MinST.InsertEdge('D','F',2);
MinST.InsertEdge('C','D',5);
MinST.InsertEdge('E','F',6);
MinST.ShowGrap();
MinST.Prim('A');
return 0;
}