前言
数据结构,一门数据处理的艺术,精巧的结构在一个又一个算法下发挥着他们无与伦比的高效和精密之美,在为信息技术打下坚实地基的同时,也令无数开发者和探索者为之着迷。
也因如此,它作为博主大二上学期最重要的必修课出现了。由于大家对于上学期C++系列博文的支持,我打算将这门课的笔记也写作系列博文,既用于整理、消化,也用于同各位交流、展示数据结构的美。
此系列文章,将会分成两条主线,一条“数据结构基础”,一条“数据结构拓展”。“数据结构基础”主要以记录课上内容为主,“拓展”则是以课上内容为基础的更加高深的数据结构或相关应用知识。
欢迎关注博主,一起交流、学习、进步,往期的文章将会放在文末。
最小生成树,总是和最短路径一起出现在入门图论的大道上。是一个有趣且重要的问题,有些地方又叫它做最小支撑树。
讨论最小生成树的前提是在无向有权连通图上。在非连通的无向图上,只能找到最小生成森林。在无权图上,可以寻找生成树,但是生成树无大小之分。
我们定义,在无向连通图上的最小生成树为边权和最小的生成树。
下面,来介绍两种经典的生成最小生成树的算法:
kruskal算法
kruskal算法利用贪心的思想。将所有的边按照边权升序排序,依次尝试加入图。加入时如果该边的两顶点已经连通,则不将其加入,否则可以加入。
显然,每次加入可使图中的森林数量减一,最终加入n-1条边。
用来维护顶点连通的方式是使用并查集结构,往期内容有整理过并查集相关知识(点这里)。
排序算法则见仁见智,可以使用各种方式进行排序,在使用较优复杂度的排序算法( O ( m l o g 2 m ) O(mlog_2m) O(mlog2m))及较优复杂度的并查集实现( O ( m l o g 2 m ) O(mlog_2m) O(mlog2m))情况下,该算法复杂度为 O ( m l o g 2 m ) O(mlog_2m) O(mlog2m)
下面的示例就是使用kruskal算法完成最小生成树并计算最小权值和的过程:
原图如下:
生成过程如下:
算法实现如下:
#include<iostream>
#include<algorithm>
using namespace std;
struct Edge{
int v1;
int v2;
int val;
};
Edge edges[M];//边集
int fa[N];//并查集使用父亲数组
int n,m;
int find(int k){
//查询集合代表元
if(fa[k] == k){
return k;
}
fa[k] = find(fa[k]);
return fa[k];
}
bool cmp(const Edge & x,const Edge & y){
//边结点比较函数,用于排序
return x.val < y.val;
}
int kruskal(){
sort(edges,edges + m,cmp);//边集排序,这里使用stl中的快排
int ans = 0;
Edge edge;
for(int i = 0;i < m;i