anuário
FIG implementado por adjacência matriz
FIG implementado usando lista de adjacência
o algoritmo de Dijkstra (single-source caminho mais curto)
algoritmo Floyd (caminho mais curto entre quaisquer dois pontos)
Prim cálculo complexidade 0 (n ^ 2)
complexidade O tempo algoritmo do Kruskal (eloge)
FIG implementado por adjacência matriz
FIG implementado adjacência matriz estrutura é definida como
typedef struct graph *Graph; //Graph是一个类型,为graph型指针
struct graph
{
WItem NoEdge;//无边标记
int n; //顶点数
int e; //边数
WItem **a; //邻接矩阵,a是一个二级指针
}AWDgraph;
GraphInit função (n, noEdge) para criar um vértices isolados do n
Graph GraphInit(int n,WItem noEdge) //返回指向一个图的指针
{
Graph G=malloc(sizeof*G); //G是变量名,sizeof要加*
G->n=n;
G->e=0;
G->a=Make2DArray(G->n+1,G->n+1,noEdge); //创建一个权值全为noEdge的矩阵
//不赋权图将上一句的NoEdge改为0
return G;
}
GraphVerticles Function (G) e GraphEdges (G), respectivamente retornar o número de vértices e arestas de um grafo G
int GraphVerticles(graph G)
{
return G->n;
}
int GraphEdges(graph G)
{
return G->e;
}
GraphExits função (i, j, L) é determinada no gráfico borda corrente de G (i, j) a presença ou ausência
int GraphExits(int i,int j,graph G)
{
if(i<1||j<1||i>G->n||j>G->n||G->a[i][j]==G->NoEdge) return 0;
//输入不在合法范围内或该边值为NoEdge
//不赋权图把if条件中的NoEdge改为0
return 1;
}
Função GraphAdd (i, j, W, L) juntar a borda em G (i, j)
void GraphAdd(int i,int j,WItem w,Graph G)
{
if(i<1||j<1||i>G->n||j>G->n||i==j||G->a[i][j]!=G->NoEdge)
//若输入不在合法范围或在对角线上或该边已经存在,则报错
//不赋权图把if条件中的NoEdge改为0
Error("Bad input");
G->a[i][j]=w;
//G->a[j][i]=w; 无向图加一句这个
//不赋权图只需要将上述语句的w改成1
G->e++; //更新边数
}
Função GraphDelete (i, j, L) exclui a borda (i, j) em L
void GraphDelete(int i,int j,graph G)
{
if(i<1||j<1||i>G->n||j>G->n||G->a[i][j]==G->NoEdge)
//输入不在合法范围内或待删边本不存在
//不赋权图把if条件中的NoEdge改为0
Error("Bad input");
G->a[i][j]=NoEdge;
//G->a[j][i]=NoEdge; 无向图加一句这个
//不赋权图只需要将上述语句的w改成0
G->e--; //更新边数
}
Indegree função (I, G) retorna o grau de vértices do gráfico G
int InDegree(int i,graph G)
{
int sum=0;
/*可单独作为求入度的方法*/
for(int j=0;j<G->n;j++)
{
if(G->a[i][j]!=NoEdge) //无向图改NoEdge为0
sum++;
}
/*如果是无向图加上以下代码*/
/*也可单独作为求出度的方法*/
for(int j=0;j<G->n;j++)
{
if(G->a[j][i]!=NoEdge) //无向图改NoEdge为0
sum++;
}
/**/
return sum;
}
FIG implementado usando lista de adjacência
definição de estrutura lista de adjacência nó
typedef struct lnode *glink; //glink是一个类型,为lnode型指针
struct lnode
{
int v; //边的另一个顶点
glink next; //邻接表指针
//若是赋权图,加上w属性
//WItem w;
};
Criar uma nova lista de nós adjacência
glink NewLNode(int v,glink next) //返回指向lnode的指针
{
glink x=malloc(sizeof*x); //x是变量名,sizeof取变量名长度要加*
x->v=v;
x->next=next;
//若是赋权图
//x->w=w;
return x;
}
FIG implementada usando a estrutura definida tabela adjacente
typedef struct graph *Graph;
struct graph
{
int n; //顶点数
int e; //边数
glink *adj; //glink型的一维数组,数组中的成员都是指针
}Lgraph;
GraphInit função (n) para criar uma tabela representada por adjacência com n vértices FIG isolado
Graph GraphInit(int n)
{
Graph G=malloc(sizeof*G) //G是变量名,sizeof前加*
G->n=n;
G->e=0;
G->adj=malloc(n+1)*sizeof(glink)) //adj是一个指针数组,成员都是glink指针,v此时是0
for(int i=0;i<=n)
G->adj[i]=0;
return G;
}
GraphVerticles Function (G) e funções GraphEdge (G) retornar o número de vértices e arestas com a formulação de matriz de adjacência FIG ligeiramente.
Função GraphExist (i, j, L) determinar se existe actualmente uma vantagem no gráfico G (i, j)
int GraphExist(int i,int j,graph G)
{
if(i<1||j<1||i>G->n||j>G->n) return 0;
glink p=G->adj[i];
while(p&&p->v!=j) p=p->next; //不走到最后且不为目标,则继续向前
if(p) return 1;
else return 0;
}
Função GraphAdd (i, j, L) foi adicionado para atingir a figura de um bordo (i, j) é operado pela primeira inserção de um vértice j do vértice i adjacente exemplar
void GraphAdd(int i,int j,Graph G) //赋权图加上WItem w
{
if(i<1||j<1||i>G->n||j>G->n||i==j||GraphExits(i,j,G))
Error("Bad input");
G->adj[i]=NewLNode(j,G->adj[i]); //直接取代G->a[i]
//无向图加上下一句
//G->adj[j]=NewLNode(i,G->adj[j]);
//赋权图加上w
//G->adj[i]=NewLNode(j,w,G->adj[i]);
G->e++;
}
GraphDelete função (i, j, L) para eliminar o gráfico borda G (i, j)
void GraphDelete(int i,int j,Graph G)
{
glink p,q;
if(i<1||j<1||i>G->n||j>G->n||!GraphExists(i,j,G))
{
Error("Bad input");
}
p=G->adj[i];
if(p->v==j) //如果第一个节点就是待删除节点,直接令其成为邻接表数组中的成员
{
G->adj[i]=p->next;
free(p);
}
else
{
while(p&&p->v!=j) p=p->next; //若未走到最后且未找到目标则继续向前
if(p) //若找到目标
{
q=p->next;
p->next=q->next;
free(q);
}
}
//有向图加上下面的代码
/*
p=G->adj[j];
if(p->v==i) //如果第一个节点就是待删除节点,直接令其成为邻接表数组中的成员
{
G->adj[j]=p->next;
free(p);
}
else
{
while(p&&p->v!=i) p=p->next; //若未走到最后且未找到目标则继续向前
if(p) //若找到目标
{
q=p->next;
p->next=q->next;
free(q);
}
}
*/
G->e--;
}
Outdegree função (i, L) calculado pela relação de adjacência do vértice i longa, há um retorno para o vértice do gráfico G
int OutDegree(int i,Graph G)
{
glink p;
int sum=0;
if(i<1||i>G->n) Error("Bad input");
p=G->adj[i];
while(p)
{
sum++;
p=p->next;
}
return sum;
}
Função indegree (I, G) volta a ter o grau de vértice i do gráfico G
int InDegree(int i,Graph G)
{
int sum=0;
for(int j=0;j<G->n;j++)
{
if(GraphExists(i,j,G))
sum++;
}
return sum;
}
BFS
//用邻接矩阵实现的无向图G中的广度优先搜索算法bfs描述
bfs(G,i)
{
/*从顶点v开始,广度优先搜索图G的算法*/
标记顶点i;
用顶点i初始化顶点队列Q;
while(!QueueEmpty(Q))
{
i=DeleteQueue(Q);
设j是i的邻接顶点;
while(j)
{
if(j未标记)
{
标记顶点j;
EnterQueue(j,Q);
}
j=i的下一个邻接顶点
}
}
}
===================================================================
//具体实现时,用一个数组pre来记录搜索到的顶点的状态。初始时对所有顶点v有pre[v]=0。
//用一全局变量cnt记录算法对图中顶点的访问次序。算法结束后,数组pre[i]中的值是算法访问顶点i的序号。
void bfs(Graph G,int i)
{
Queue Q=QueueInit();
EnterQueue(i,Q); //顶点先入队
while(!QueueEmpty(Q))
{
if(pre[i=DeleteQueue(Q)]==0) //未访问过
{
pre[i]=cnt++; //访问该结点并标记
for(int j=1;j<=G->n;j++)
{
if(G->adj[i][j]&&pre[j]==0) //若边存在且未访问过,入队
EnterQueue(j,Q);
}
}
}
}
//图中可能不止一个连通分量,遍历全图算法如下
void GraphSearch(Graph G)
{
cnt=1;
for(int i=1;i<=G->n;i++) pre[i]=0;
for(int i=1;i<=G->n;i++)
{
if(pre[i]==0)bfs(G,i); //对每个连通分量调用一次bfs
}
}
//天勤上面用邻接表表示图的bfs写法
int visit[MAXSIZE]=0; //访问状态数组
void bfs(Graph *G,int v)
{
ArcNode *p;
visit[v]=1;
//Visit(v);
Queue<int> q;
q.push(v);
while(!IsEmpty(q))
{
int t=q.top();
q.pop();
p=G->adj[t].firstarc; //p指向当前结点第一条边
while(p)
{
if(visit[p->adjvex]==0)
{
visit[p->adjvex]=1;
//Visit(p->adjvex);
q.push(p->adjvex); //若当前邻接顶点未被访问过,则置为已访问,并压入队列
}
p=p->nextarc; //否则,p指向当前结点的下一条邻边
}
}
}
void BFS(Graph *G)
{
for(int i=0;i<G->n;i++)
if(visit[i]==0)
bfs(G,i);
}
busca em profundidade
//用邻接矩阵实现的无向图G中的深度优先搜索算法dfs如下
void dfs(Graph G,int i)
{
pre[i]=cnt++; //初始化时所有结点pre[i]=0,当pre[i]不为0使表示该结点已访问过,pre[i]的值为算法访问结点i的序号
for(int j=1;j<=G->n;j++) //顺序遍历与结点i相邻的结点,
{
if(G->[i][j]) //若边<i,j>存在
{
if(pre[j]==0)dfs(G,j); //若结点j还未被访问过,对j递归调用dfs,若访问过,j++探测下一个相邻结点
}
}
}
//用邻接表实现的有向图G中的深度优先搜索算法dfs如下
void dfs(Graph G,int i)
{
glink p;
pre[i]=cnt++;
for(p=G->adj[i];p;p=p->next)
{
if(pre[i]==0)dfs(G,p->v); //若p指向的结点已访问过,结束当前层次的递归,返回上一层递归,执行p=p->next探测下一个相邻结点
}
}
void GraphSearch(Graph G)
{
cnt=1;
for(int i=1;i<=G->n;i++) pre[i]=0;
for(int i=1;i<=G->n;i++) if(pre[i]==0) dfs(G,i);
}
//天勤上面用邻接表表示图的dfs写法
int visit[MAXSIZE]=0; //全局变量用来保存访问状态
int dfs(Graph *G,int v)
{
ArcNode *p;
visit[v]=1; //置当前结点为已访问
Visit(v);
p=G->adj[v].firstarc; //p指向顶点v的第一条边
while(p)
{
if(visit[p->adjvex])==0 //若当前结点未被访问过,则往深处继续访问
{
dfs(G,p->adjvex)
}
p=p->nextarc; //否则检测下一个与v邻接的结点
} //执行到这一步时,所有与v邻接的结点已经检查完毕,该层dfs也执行到了最后一句,自动返回上一层递归
}
void DFS(Graph *G)
{
for(int i=0;i<G->n;i++)
if(visit[i]==0)
dfs(G,i);
}
//天勤上判断图G是否是树的算法,基于dfs
int vc=0,ec=0; //定义全局变量vc和ec,就不用在函数里面传了
int visit[MAXSIZE]=0;
void dfs(Graph *G,int v)
{
ArcNode *p;
visit[v]=1; //置当前结点为已访问
vc++; //结点数自增1
p=G->adj[v].firstarc;
while(p)
{
if(visit[p->adjvex]==0) //若当前顶点的邻接点未被访问过,则访问它,并对ec自增1
{
ec++;
dfs(G,p->adjvex);
}
p=p->next;
}
}
int IsTree(Graph *G)
{
dfs(G,1);
if(vc==G->n&&(ec/2)==G->e) //若vc等于图中顶点数,ec等于图中边数的2倍
return 1;
return 0;
}
//由于每次访问顶点ec都会累加上之前所有与访问过的结点关联的边数,因此遍历完之后,相当于ec中的数值是图的度数,(一条边2个度),因此ec/2就是访问过的边数。
Shortest Path
o algoritmo de Dijkstra (single-source caminho mais curto)
Algoritmo ideia:
Configurar um conjunto de vértices S, e continuar a expandir esta coleção como ganancioso. Um vértice pertencente ao conjunto S se e apenas se a fonte tem o menor comprimento da trajectória a partir do vértice. Inicial, S contém apenas fonte. Seja u G é um vértice do caminho através do vértice S da fonte ser um caminho especial a partir da fonte para apenas U e u intermédia, e tratou-se com dist especial matriz para gravar o comprimento do caminho mais curto que corresponde a cada um dos vértices de corrente. Dijkstra algoritmo para cada vértice u é removido do VS tem o menor comprimento da trajectória especial, u é adicionada ao conjunto S, enquanto a matriz dist fazer as modificações necessárias. Uma vez V S contém todos os vértices, dist na ficha do menor comprimento de trajecto entre a outra a partir do vértice fonte para todos.
descrição do algoritmo:
Passo 1: A inicialização dist [v] = a [s] [v]
Para todos os vértices v adjacente à frente s pré [v] = s;
Por outro vértice u conjunto pré [u] = 0;
Tabela G contém todos os pré estabelecida [v] ≠ vértice v 0 é o tempo inicial @ isto é, G s é a fonte directamente vértices adjacentes
Passo 2: Se lista vazia L, em seguida, as extremidades do algoritmo, de outra forma, ir para o passo 3
Passo 3: Remover o valor mínimo de dist ou seja, a fonte vértice v // s mais recente da lista vértice L
Passo 4: Para todos os vértices adjacentes ao vértice v u opostas dist [u] = min {dist [u], dist [v] + A [V] [u]}
Se a mudança dist [u], isto é, após a adição de caminho especial vértice v é mais curto, o conjunto de pré [u] = v; e, se não na lista L L, L L é adicionado; ir para o passo 2
//在用邻接矩阵实现的赋权有向图中,单源最短路径问题的Dijkstra算法实现如下
void Dijkstra(int s,WItem dist[],int prev[],Graph G)
{
int i,j;
List L=ListInit(); //初始化L表
if(s<1||s>G->n) Error("Out of bounds") //处理非法输入
/*初始化dist,prev和L*/
for(int i=1;i<=G->n;i++)
{
dist[i]=a[s][i]; //顶点i到源点s的初始距离为a[s][i]的值
if(dist[i]==G->NoEdge) prev[i]=0; //若顶点i与源点s之间不存在边,则置i的前驱结点为0
else{prev[i]=s;ListInsert(0,i,L);} //否则,置i的前驱结点为s,并将顶点i加入L表,参数啥意思?
}
dist[s]=0; //源点s的前驱为0
/*修改dist和prev*/
while(!ListEmpty(L))
{
/*找L中具有最小dist值得顶点v*/
/*将顶点v从表L中删除,并修改dist的值*/
i=ListDelMin(L,dist); //顶点i是L表中所有已知特殊路径长度的结点中路径最短的
for(int j=1;j<=G->n;j++) //遍历所有与顶点i相邻的顶点
{
if(G->a[i][j]!=G->NoEdge&&(!prev[j]||dist[j]>dist[i]+G->a[i][j])) //若边(i,j)存在,且加入结点i之后,结点j到源点s的距离缩短
{
/*dist减少*/
dist[j]=dist[i]+G->a[i][j]; //更新结点j到源点s的特殊路径距离
/*顶点j插入表L*/
if(!prev[j]ListInsert(0,j,L)) //结点j的特殊路径长度已知,加入表L
prev[j]=i; //更新结点j的前驱
}
}
}
}
//天勤上的写法,我觉得更好理解一些
void Dijkstra(Graph G,int v,int dist[],int path[]) //dist是v到某点vu的距离,path是vu到v最短路径上前驱结点的下标,dist是一维数组,因为将它看作二维数组时,有一维是不变的,下标都是v
{
int sex[MAXSIZE]; //set记录顶点是否被加入路径,取值为1则为加入,0为未加入
/*以下是对各数组进行初始化*/
for(int i=0;i<G.n;i++)
{
dist[i]=G.edges[v][i];
path[i]=v;
set[i]=0;
}
set[v]=1;
/*初始化完毕*/
/*以下是找到剩余结点中与已生成的路径距离最短的结点*/
int min=INF;
for(int i=0;i<G.n;i++)
{
if(set[i]==0&&dist[i]<min)
{
u=i;
min=G.dist[i];
}
}
set[u]=1;
/*找到该结点后,加入路径中*/
/*加入顶点u到路径中之后,更新dist和path*/
for(int i=0;i<G.n;i++)
{
if(set[i]==0&&dist[u]+G.edges[u][i]<dist[i])
{
dist[i]=dist[u]+G.edges[u][i];
path[i]=u; //u为i在路径上的前驱
}
}
}
algoritmo Floyd (caminho mais curto entre quaisquer dois pontos)
Algoritmo ideia:
Dispostas numa matriz de c, c inicialmente [i] [j] = uma [i] [j]. Em seguida, o c-matriz fazer n iterações, depois da primeira iteração k, C [i] [J] é um valor do vértice i ao vértice j, e não passa através do comprimento da trajectória intermédia é maior do que o número k de vértices. Ao fazer o k-ésimo iteração em C, C [i] [j] = min {C [i] [k] + c [k] [j], C [i] [j]}, para calcular c [i ] [j] pode ser comparado com a corrente de C [i] [j] e C [i] [k] + c [k] [j] tamanho. c correntes [i] [j] valor indica do vértice i a j, o número de vértices intermédios não é maior do que k-1 mais curto comprimento de percurso; e c [i] [k] + c [k] [j] indica o i vértice a k, e, em seguida, a partir de k para j, e não passa através do comprimento da trajectória intermédia é maior do que o número de vértices k.
caminho matriz bidimensional é utilizada para gravar o caminho mais curto. Quando K é a manipulação c [i] [j] para se obter um número inteiro de um valor mínimo, que é definido como P [i] [j] = k. Quando o caminho de [i] [j] = 0, que representa o caminho mais curto do nó i a j é a borda a partir de i a j. Depois de calcular o C [i] valor [j], facilmente gravado por as informações de caminho para encontrar o caminho mais curto correspondente.
void Floyd(WItem **c,int **path,Graph G)
{
/*初始化c[i][j]*/
for(int i=1;i<=G->n;i++)
for(int j=1;j<=G->n;j++)
{
if(i==j)
c[i][j]=0;
else
{
c[i][j]=G->a[i][j];
path[i][j]=0; //path=0表示当前顶点i到顶点j的最短路径就是它们之前的边
}
}
for(int k=1;k<=G->n;k++)
for(int i=1;i<=G->n;i++)
for(int j=1;j<G->n;j++)
{
if(c[i][k]!=NoEdge&&c[k][j]!=NoEdge&&(c[i][j]==NoEdge||c[i][j]>c[i][k]+c[k][j]))
//确保加入的顶点k与顶点i,顶点k与顶点j之前是可达的,当顶点i到顶点j无边或小于顶点i到k加上顶点k到j的距离时,更新顶点i到j的路径长度
{
c[i][j]=c[i][k]+c[k][j];
p[i][j]=k; //加入的点k是使c[i][j]取最小值的数
}
}
}
árvore mínimo spanning
Prim cálculo complexidade 0 (n ^ 2)
Algoritmo ideia:
Primeiro conjunto S = {1}, e em seguida, enquanto S é um subconjunto de V (isto é, ainda não contêm todos os nós), para ser ávido seleccionado como se segue: Escolha do ponto conjunto S i, VS no ponto J, e uma [I] [j] a menor borda e vértice adicionado ao conjunto S j. Este tipo de processo para a alimentação de S = V acima. (Não é necessário para julgar se um ciclo, porque os dois lados dos vértices de diferentes conjuntos)
Como descobrir a condição de i e j, precisamos definir duas matrizes armário e lowcost. Para vértices j de um VS, mais próximo [j] é adjacente a um vértice S j em que j e k outros vértices adjacentes em S são comparados com um [j] [mais próximo [j]] <= um [j] [k]. lowcost [j] é o valor de um [j] [mais próximo [j]]
Prim durante a execução do algoritmo, para encontrar o mínimo VS manipulação lowcost vértice j, e seleccionar a partir do lado da matriz mais próximo (j, mais próximo [j]), e, finalmente, adicionar a S, j, e mais próximo do necessário e lowcost modificações.
void Prim(WItem *lowcost,int *closest,Graph G)
{
/*初始化*/
int *s; //集合S,值为1表示在集合中,为0表示不在集合中
s=malloc((G->n+1)*sizeof(int));
for(int i=1;i<=G->n;i++)
{
lowcost[i]=a[1][i]; //先设置顶点1在S中
closest[i]=1;
s[i]=0; //除1以外所有点都不在集合S中
}
s[1]=1; //把顶点1加入集合S
for(int i=1;i<=G->n;i++) //执行n次
{
min=G->NoEdge; //要找出最小值,先把min设为最大
j=1; //j用来记录到集合S距离最短的顶点序号,一开始先设为1作为初始值
for(int k=2;k<=G->n;k++) //k=2是因为一开始只有1在S中,V-S要从2开始
{
if(lowcost[k]<min)&&(!s[k]) //k到集合S最短距离小于min且k不在集合S中,即k在V-S中
{
min=lowcost[k]; //更新最小值,j为当前V-S中里S最近的顶点,现在令j为k
j=k;
}
}
//此时j是到集合S距离最短的顶点序号
s[j]=1; //把j加入集合S
for(int k=2;k<=G->n;k++) //j加入集合S后,要修改原来的closest和lowcost
{
if((G->a[k][j]<lowcost[k])&&(!s[k])) //若K不在集合S且顶点j和k之间距离小于j加入集合S前顶点k到集合S的最短距离
{
//更新closest,lowcost
closest[k]=j;
lowcost[k]=G->a[k][j]
; }
}
}
}
//V-S中的顶点为焦点向S中的顶点逐个连线找最短,j是通过k来更新的
//利用closest还能找到最短路径
//while(k>0)
//p=closest[k];
//k=p;
complexidade O tempo algoritmo do Kruskal (eloge)
Em primeiro lugar, os vértices de n L n como uma comunicação ramo isolado. Todas as partes por peso de pequena a grande, dos primeiros bordos, cada vista lateral em ordem ascendente do lado direito, ao exibir a borda do k-ésimo (V, W), V e W se os terminais estão apex corrente dois componentes ligados diferentes T1 e T2, a borda uso (v, w) está ligado ao T1 e T2 ligados componente, e, em seguida, continuar a ver o lado do k + 1, ou directamente aceder a k + 1 lado, o processo continua até que apenas um tempo até que o componente ligado.
A configuração descrita acima de Kruskal mínima abrangendo algoritmo árvore requer G Ver FIG ordem crescente dos pesos de todas as bordas. Isto requer que todos os bordos laterais G classificados por peso. Estrutura definição são armazenados em cada extremidade:
typedef struct edge
{
int u;
int v;
WItem w;
}Edge;
/*函数EDGE(u,v,w)创造一条权威w的边(u,v)*/
Edge EDGE(int u,int v,WItem w)
{
Edge e;
e->u=u;
e->v=v;
e->w=w;
return e;
}
/*函数Edges(a,G)抽取图G的所有边到赋权边数组a中,并返回图G的边数*/
int Edges(Edges a[],Graph G)
{
int k=0;
for(int i=1;i<=G->n;i++)
for(int j=1;j<=G->n;j++)
if(G->a[i][j]!=G->NoEdge)
a[k++]=EDGE(i,j,G->a[i][j]);
return k;
}
void Kruskal(Edge mst[],Graph G)
{
Edge a[maxE];
UFset U; //并查集u
int e=Edges(a,G); //抽取G的所有边,e为边数
quicksort(a,0,e-1); //对边数组a排序,参数意义为对数组a从元素0到元素e-1进行排序
U=UFinit(G->n); //初始化并查集U
for(int i=0,int k=0;i<e&&k<G->n-1;i++) //k记录循环次数,执行n-1次结束
{
int s=UFind(a[i].u,U); //a[i].u是当前最短边的一个端点,找出它所属的连通分支
int t=UFind(a[i].v,U); //a[i].v是当前最短边的另一个端点,找出它所属的连通分支
if(s!=t) //若s和t不是同一个连通分支
{
mst[k++]=a[i]; //更新最小生成树
UFunion(s,t,U); //合并连通分支s和t
}
}
}