diff --git a/C++/标准库/2.3.cpp b/C++/标准库/2.3.cpp index 0a42278a..230037ce 100644 --- a/C++/标准库/2.3.cpp +++ b/C++/标准库/2.3.cpp @@ -20,13 +20,32 @@ int main(){ // } // vector vec; - vector vec; - priority_queue pir(vec,[](const int a,const int b){ - if(a>b){ - return true; - } - else{ - return false; - }}) +// 构造边的对象 +struct Edge +{ + int start; + int end; + int weight; + Edge(int s,int e,int w){ + start=s; + end=e; + weight=w; + } + // 重写<运算符 + bool operator<(const Edge& a)const{ + return a.weight < weight; + } +}; + priority_queue pri; + Edge e1(1,2,3); + Edge e2(3,2,1); + Edge e3(2,1,4); + pri.push(e1); + pri.push(e2); + pri.push(e3); + while(!pri.empty()){ + cout< 包含集合和映射。即unordered_set和unordreed_map两种数据结构的实现方式。 ## 1 哈希表简介 diff --git a/数据结构/5.2 哈希集合.md b/数据结构/5.2 哈希集合.md new file mode 100644 index 00000000..e69de29b diff --git a/数据结构/5.3 哈希映射.md b/数据结构/5.3 哈希映射.md new file mode 100644 index 00000000..e69de29b diff --git a/数据结构/5.4 并查集.md b/数据结构/5.4 并查集.md new file mode 100644 index 00000000..3aa4a482 --- /dev/null +++ b/数据结构/5.4 并查集.md @@ -0,0 +1,23 @@ +# 并查集 + +## 1 概念 +### 定义 +并查集被很多OIer认为是最简洁而优雅的数据结构之一,主要用于解决一些元素分组的问题。它管理一系列不相交的集合,并支持两种操作: + +* 合并(Union):把两个不相交的集合合并为一个集合。 +* 查询(Find):查询两个元素是否在同一个集合中。 + + +## 2 题目——亲戚问题 + +> ### 题目背景 +> * 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。 +> ### 题目描述 +> * 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。 +> ### 输入格式 +> * 第一行:三个整数n,m,p,(n<=5000,m<=5000,p<=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。 +> * 以下m行:每行两个数Mi,Mj,1<=Mi,Mj<=N,表示Mi和Mj具有亲戚关系。 +> * 接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。 +> ### 输出格式 +> * P行,每行一个’Yes’或’No’。表示第i个询问的答案为“具有”或“不具有”亲戚关系。 + diff --git a/算法/B类:数据结构算法/1.1 图算法-Dijkstra算法 copy.md b/算法/B类:数据结构算法/1.1 图算法-Dijkstra算法 copy.md index cfb9e3a6..a9936b6f 100644 --- a/算法/B类:数据结构算法/1.1 图算法-Dijkstra算法 copy.md +++ b/算法/B类:数据结构算法/1.1 图算法-Dijkstra算法 copy.md @@ -10,7 +10,8 @@ >参考文献 -> [https://www.cnblogs.com/msymm/p/9769915.html](https://www.cnblogs.com/msymm/p/9769915.html) +> * [https://www.cnblogs.com/msymm/p/9769915.html](https://www.cnblogs.com/msymm/p/9769915.html) +> * [https://blog.csdn.net/jeffleo/article/details/53349825](https://blog.csdn.net/jeffleo/article/details/53349825) ## 1 问题分析 diff --git a/算法/B类:数据结构算法/1.4 图算法-Kruskal算法.md b/算法/B类:数据结构算法/1.4 图算法-Kruskal算法.md index 0996690d..3fc22007 100644 --- a/算法/B类:数据结构算法/1.4 图算法-Kruskal算法.md +++ b/算法/B类:数据结构算法/1.4 图算法-Kruskal算法.md @@ -26,22 +26,19 @@ ## 3 算法流程 1. 首先第一步,我们有一张图Graph,有若干点和边 -

+![](image/2021-04-05-16-21-06.png) 2. 将所有的边的长度排序,用排序的结果作为我们选择边的依据。这里再次体现了贪心算法的思想。资源排序,对局部最优的资源进行选择,排序完成后,我们率先选择了边AD。 - - -

+![](image/2021-04-05-16-21-18.png) 3. 在剩下的变中寻找。我们找到了CE。这里边的权重也是5 - -

+![](image/2021-04-05-16-21-32.png) 4. 依次类推我们找到了6,7,7,即DF,AB,BE。 -

+![](image/2021-04-05-16-21-42.png) 5. 下面继续选择, BC或者EF尽管现在长度为8的边是最小的未选择的边。但是现在他们已经连通了(对于BC可以通过CE,EB来连接,类似的EF可以通过EB,BA,AD,DF来接连)。所以不需要选择他们。类似的BD也已经连通了(这里上图的连通线用红色表示了)。最后就剩下EG和FG了。当然我们选择了EG。 -

+![](image/2021-04-05-16-21-58.png) ## 4 算法效率 diff --git a/算法/B类:数据结构算法/1.5 图算法-Prim算法.md b/算法/B类:数据结构算法/1.5 图算法-Prim算法.md index dd55d790..2b65a43e 100644 --- a/算法/B类:数据结构算法/1.5 图算法-Prim算法.md +++ b/算法/B类:数据结构算法/1.5 图算法-Prim算法.md @@ -31,81 +31,22 @@ ## 3 算法过程 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
图例说明不可选可选已选(Vnew
  -

-
此为原始的加权连通图。每条边一侧的数字代表其权值。---
-

-
顶点D被任意选为起始点。顶点ABEF通过单条边与D相连。A是距离D最近的顶点,因此将A及对应边AD以高亮表示。C, GA, B, E, FD
  -

-
下一个顶点为距离DA最近的顶点。BD为9,距A为7,E为15,F为6。因此,FDA最近,因此将顶点F与相应边DF以高亮表示。C, GB, E, FA, D
算法继续重复上面的步骤。距离A为7的顶点B被高亮表示。CB, E, GA, D, F
  -

-
在当前情况下,可以在CEG间进行选择。CB为8,EB为7,GF为11。E最近,因此将顶点E与相应边BE高亮表示。C, E, GA, D, F, B
  -

-
这里,可供选择的顶点只有CGCE为5,GE为9,故选取C,并与边EC一同高亮表示。C, GA, D, F, B, E
-

-
顶点G是唯一剩下的顶点,它距F为11,距E为9,E最近,故高亮表示G及相应边EGGA, D, F, B, E, C
-

-
现在,所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为39。A, D, F, B, E, C, G
+1. 此为原始的加权连通图。每条边一侧的数字代表其权值。结果集合{},可选集合{}。 +![](image/2021-04-05-16-27-10.png) +2. 顶点D被任意选为起始点。顶点A、B、E和F通过单条边与D相连。A是距离D最近的顶点,因此将A及对应边AD以高亮表示。结果集合为{D}.可选集合为{A,B,E,F} +![](image/2021-04-05-16-27-47.png) +3. 下一个顶点为距离D或A最近的顶点。B距D为9,距A为7,E为15,F为6。因此,F距D或A最近,因此将顶点F与相应边DF以高亮表示。结果集合{A,D},可选集合{B,E,F} +![](image/2021-04-05-16-30-15.png) +4. 算法继续重复上面的步骤。距离A为7的顶点B被高亮表示。结果集合为{A,D,F},可选集合为{B,E,G} +![](image/2021-04-05-16-31-52.png) +5. 在当前情况下,可以在C、E与G间进行选择。C距B为8,E距B为7,G距F为11。E最近,因此将顶点E与相应边BE高亮表示。结果集合为{A,D,F,B},可选集合为{C,E,G} +![](image/2021-04-05-16-33-26.png) +6. 这里,可供选择的顶点只有C和G。C距E为5,G距E为9,故选取C,并与边EC一同高亮表示。结果集合为{A,D,F,B,E},可选集合为{C,G} +![](image/2021-04-05-16-34-22.png) +7. 顶点G是唯一剩下的顶点,它距F为11,距E为9,E最近,故高亮表示G及相应边EG。结果集合为{A,D,F,B,E,C},可选集合为{G} +![](image/2021-04-05-16-35-06.png) +8. 现在,所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为39。结果集合为{A,D,F,B,E,C,G},可选集合为{} +![](image/2021-04-05-16-35-28.png) ## 4 算法效率 顶点数V,边数E。时间复杂度: @@ -117,5 +58,170 @@ ## 5 算法实现 ```C++ +#include +#include +#include +using namespace std; +// 构造边的对象 +struct Edge +{ + int start; + int end; + int weight; + Edge(int s,int e,int w){ + start=s; + end=e; + weight=w; + } + // 重写<运算符 + bool operator<(const Edge& a)const{ + return a.weight < weight; + } +}; +// struct cmp{ +// bool operator()(Edge a,Edge b){ +// return b.weight > a.weight; +// } +// }; + +class Graph{ +private: + int vertex_num; //图的顶点个数 + int edge; + // 如果顶点的表示是离散的应该加一层映射 + vector> arc; //邻接矩阵 +public: + // 测试用的默认构造函数 + Graph(); + //构造函数,从命令行输入 + Graph(int vertex_num_,int edge_); + //打印所有的边 + void print_edge(); + // 打印整个邻接矩阵 + void print_arc(); + //求最短路径 + void Dijkstra(int begin);//单源最短路 + void Floyd();//多源最短路 + void Prim();//最小生成树 + void Kruskal();//最小生成树 +}; + +Graph::Graph(){ + this->vertex_num = 7; + this->edge=12; + this->arc = vector>(vertex_num,vector(vertex_num,INT_MAX)); + // cout<vertex_num=vertex_num_; + this->edge=edge_; + this->arc=vector>(vertex_num,vector(vertex_num,INT_MAX)); + int beg=0,end=0,weight=0; + for(int i=0;i>beg>>end>>weight; + arc[beg][end]=weight; + // 如果是无向图则需要添加反向的路径 + arc[end][beg]=weight; + } +} + +void Graph::print_edge(){ + for(int i=0;i result(vertex_num,-1); + // 用来记录到某个节点的距离的向量 + vector distance(vertex_num,INT_MAX); + // 用来记录到某个节点的前一个节点向量 + vector pre_point(vertex_num,-1); + + // 首先选择第一个节点 + int min_index=2; + int min_distance=INT_MAX; + result[min_index]=min_index;//表示从当前节点开始.前一个节点时自己。 + + for(int k=0;k a.weight; +// } +// }; class Graph{ private: @@ -111,7 +116,7 @@ void Graph::print_arc(){ } } void Graph::Dijkstra(int begin){ - // 初始化结果集,到自己是0 + // 初始化结果集,到自己是0。 vector result(vertex_num,INT_MAX); result[begin]=0; // 初始化距离集合,每次从中挑选 @@ -180,45 +185,58 @@ void Graph::Floyd(){ cout< result; - // 初始化优先队列,用来挑选满足要求的最小的边 - priority_queue> pri_edge; + // 最小生成树开始的顶点。表示顶点是否被选中过.-1表示没有被选中。其他值表示它的上一个节点。 + vector result(vertex_num,-1); + // 用来记录到某个节点的距离的向量 + vector distance(vertex_num,INT_MAX); + // 用来记录到某个节点的前一个节点向量。dijsktra也可以添加一个前置节点向量,用来保存路径。 + vector pre_point(vertex_num,-1); - for(int k=0;k