数据结构(并查集,图)

并查集

练习版

class UnionFindSet
{
public:void swap(int* a, int* b){int tmp = *a;*a = *b;*b = tmp;}UnionFindSet(size_t size):_ufs(size,-1){}int UnionFind(int x){}void Union(int x1, int x2){}//长分支改为相同节点int FindRoot(int x){}bool InSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}int SetCount(){}
private:std::vector<int> _ufs;
};
class UnionFindSet
{
public:void swap(int* a, int* b){int tmp = *a;*a = *b;*b = tmp;}UnionFindSet(size_t size):_ufs(size,-1){}int UnionFind(int x){int parent = x;while (_ufs[parent] >= 0){parent = _ufs[parent];}return parent;}void Union(int x1, int x2){int root1 = UnionFind(x1);int root2 = UnionFind(x2);/*if (root1 > root2){swap(&root1, &root2);}if (root1 != root2){_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}*/if (abs(_ufs[root1]) < abs(_ufs[root2]))swap(&root1, &root2);_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}//长分支改为相同节点int FindRoot(int x){int root = x;while (_ufs[root] >= 0){root = _ufs[root];}while (_ufs[x] >= 0){int parent = _ufs[x];_ufs[x] = root;x = parent;}return root;}bool InSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}int SetCount(){int count = 0;for (int i = 0; i < _ufs.size(); i++){if (_ufs[i] < 0)count++;}return count;}
private:std::vector<int> _ufs;
};

邻接矩阵

template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{typedef Graph<V, W, MAX_W, Direction> Self;
public:Graph() = default;// 图的创建// 1、IO输入  -- 不方便测试,oj中更适合// 2、图结构关系写到文件,读取文件// 3、手动添加边Graph(const V* a, size_t n)//邻接矩阵{_vertexs.reserve(n);for (size_t i = 0; i < n; ++i){_vertexs.push_back(a[i]);_indexMap[a[i]] = i;}_matrix.resize(n);for (size_t i = 0; i < _matrix.size(); ++i){_matrix[i].resize(n, MAX_W);}}size_t GetVertexIndex(const V& v){auto it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else{//assert(false);throw invalid_argument("顶点不存在");return -1;}}void _AddEdge(size_t srci, size_t dsti, const W& w){_matrix[srci][dsti] = w;// 无向图if (Direction == false){_matrix[dsti][srci] = w;}}void AddEdge(const V& src, const V& dst, const W& w){size_t srci = GetVertexIndex(src);size_t dsti = GetVertexIndex(dst);_AddEdge(srci, dsti, w);}void Print(){// 顶点for (size_t i = 0; i < _vertexs.size(); ++i){cout << "[" << i << "]" << "->" << _vertexs[i] << endl;}cout << endl;// 矩阵// 横下标cout << "  ";for (size_t i = 0; i < _vertexs.size(); ++i){//cout << i << " ";printf("%4d", i);}cout << endl;for (size_t i = 0; i < _matrix.size(); ++i){cout << i << " "; // 竖下标for (size_t j = 0; j < _matrix[i].size(); ++j){//cout << _matrix[i][j] << " ";if (_matrix[i][j] == MAX_W){//cout << "* ";printf("%4c", '*');}else{//cout << _matrix[i][j] << " ";printf("%4d", _matrix[i][j]);}}cout << endl;}cout << endl;}
};

邻接矩阵 

template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{typedef Graph<V, W, MAX_W, Direction> Self;
public:Graph() = default;// 图的创建// 1、IO输入  -- 不方便测试,oj中更适合// 2、图结构关系写到文件,读取文件// 3、手动添加边Graph(const V* a, size_t n)//邻接矩阵{_vertexs.reserve(n);for (size_t i = 0; i < n; ++i){_vertexs.push_back(a[i]);_indexMap[a[i]] = i;}_matrix.resize(n);for (size_t i = 0; i < _matrix.size(); ++i){_matrix[i].resize(n, MAX_W);}}size_t GetVertexIndex(const V& v){auto it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else{//assert(false);throw invalid_argument("顶点不存在");return -1;}}void _AddEdge(size_t srci, size_t dsti, const W& w){_matrix[srci][dsti] = w;// 无向图if (Direction == false){_matrix[dsti][srci] = w;}}void AddEdge(const V& src, const V& dst, const W& w){size_t srci = GetVertexIndex(src);size_t dsti = GetVertexIndex(dst);_AddEdge(srci, dsti, w);}void Print(){// 顶点for (size_t i = 0; i < _vertexs.size(); ++i){cout << "[" << i << "]" << "->" << _vertexs[i] << endl;}cout << endl;// 矩阵// 横下标cout << "  ";for (size_t i = 0; i < _vertexs.size(); ++i){//cout << i << " ";printf("%4d", i);}cout << endl;for (size_t i = 0; i < _matrix.size(); ++i){cout << i << " "; // 竖下标for (size_t j = 0; j < _matrix[i].size(); ++j){//cout << _matrix[i][j] << " ";if (_matrix[i][j] == MAX_W){//cout << "* ";printf("%4c", '*');}else{//cout << _matrix[i][j] << " ";printf("%4d", _matrix[i][j]);}}cout << endl;}cout << endl;}
private:vector<V> _vertexs;			// 顶点集合map<V, int> _indexMap;		// 顶点映射下标vector<vector<W>> _matrix;  // 邻接矩阵
};

广度优先遍历

void BFS(const V& src)//广度优先遍历
{size_t srci = GetVertexIndex(src);// 队列和标记数组queue<int> q;vector<bool> visited(_vertexs.size(), false);q.push(srci);visited[srci] = true;int levelSize = 1;size_t n = _vertexs.size();while (!q.empty()){// 一层一层出for (int i = 0; i < levelSize; ++i){int front = q.front();//下标q.pop();cout << front << ":" << _vertexs[front] << " ";//下标对应的值// 把front顶点的邻接顶点入队列for (size_t i = 0; i < n; ++i){if (_matrix[front][i] != MAX_W){if (visited[i] == false){q.push(i);visited[i] = true;}}}}cout << endl;levelSize = q.size();}cout << endl;
}

深度优先遍历

void _DFS(size_t srci, vector<bool>& visited)
{cout << srci << ":" << _vertexs[srci] << endl;//访问起点visited[srci] = true;// 找一个srci相邻的没有访问过的点,去往深度遍历for (size_t i = 0; i < _vertexs.size(); ++i){if (_matrix[srci][i] != MAX_W && visited[i] == false){_DFS(i, visited);}}}void DFS(const V& src)
{size_t srci = GetVertexIndex(src);vector<bool> visited(_vertexs.size(), false);_DFS(srci, visited);
}

最小生成树

Kruskal算法
W Kruskal(Self& minTree)
{size_t n = _vertexs.size();//最小生成树初始化,否则越界minTree._vertexs = _vertexs;minTree._indexMap = _indexMap;minTree._matrix.resize(n);for (size_t i = 0; i < n; ++i){minTree._matrix[i].resize(n, MAX_W);}priority_queue<Edge, vector<Edge>, greater<Edge>> minque;for (size_t i = 0; i < n; ++i){for (size_t j = 0; j < n; ++j){if (i < j && _matrix[i][j] != MAX_W){minque.push(Edge(i, j, _matrix[i][j]));}}}// 选出n-1条边int size = 0;W totalW = W();UnionFindSet ufs(n);while (!minque.empty()){Edge min = minque.top();minque.pop();if (!ufs.InSet(min._srci, min._dsti))//如果一条边的两个端点属于同一个集合,则形成环{cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;minTree._AddEdge(min._srci, min._dsti, min._w);ufs.Union(min._srci, min._dsti);++size;totalW += min._w;}else{cout << "构成环:";cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;}}if (size == n - 1){return totalW;}else{return W();}
}

void TestGraphMinTree()
{const char* str = "abcdefghi";Graph<char, int> g(str, strlen(str));g.AddEdge('a', 'b', 4);g.AddEdge('a', 'h', 8);//g.AddEdge('a', 'h', 9);g.AddEdge('b', 'c', 8);g.AddEdge('b', 'h', 11);g.AddEdge('c', 'i', 2);g.AddEdge('c', 'f', 4);g.AddEdge('c', 'd', 7);g.AddEdge('d', 'f', 14);g.AddEdge('d', 'e', 9);g.AddEdge('e', 'f', 10);g.AddEdge('f', 'g', 2);g.AddEdge('g', 'h', 1);g.AddEdge('g', 'i', 6);g.AddEdge('h', 'i', 7);Graph<char, int> kminTree;cout << "Kruskal:" << g.Kruskal(kminTree) << endl;kminTree.Print();
}

Prim算法

局部贪心

W Prim(Self& minTree, const W& src)
{size_t srci = GetVertexIndex(src);size_t n = _vertexs.size();minTree._vertexs = _vertexs;minTree._indexMap = _indexMap;minTree._matrix.resize(n);for (size_t i = 0; i < n; ++i){minTree._matrix[i].resize(n, MAX_W);}/*set<int> X;set<int> Y;X.insert(srci);for (size_t i = 0; i < n; ++i){if (i != srci){Y.insert(i);}}*/vector<bool> X(n, false);vector<bool> Y(n, true);X[srci] = true;Y[srci] = false;// 从X->Y集合中连接的边里面选出最小的边priority_queue<Edge, vector<Edge>, greater<Edge>> minq;// 先把srci连接的边添加到队列中//for (size_t i = 0; i < n; ++i){if (_matrix[srci][i] != MAX_W){minq.push(Edge(srci, i, _matrix[srci][i]));}}cout << "Prim开始选边" << endl;size_t size = 0;W totalW = W();while (!minq.empty()){Edge min = minq.top();minq.pop();// 最小边的目标点也在X集合,则构成环if (X[min._dsti]){//cout << "构成环:";//cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;}else{minTree._AddEdge(min._srci, min._dsti, min._w);cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;X[min._dsti] = true;Y[min._dsti] = false;++size;totalW += min._w;if (size == n - 1)break;for (size_t i = 0; i < n; ++i){if (_matrix[min._dsti][i] != MAX_W && Y[i])//避免重复{minq.push(Edge(min._dsti, i, _matrix[min._dsti][i]));}}}}if (size == n - 1){return totalW;}else{return W();}
}
void TestGraphMinTree(){const char str[] = "abcdefghi";Graph<char, int> g(str, strlen(str));g.AddEdge('a', 'b', 4);g.AddEdge('a', 'h', 8);//g.AddEdge('a', 'h', 9);g.AddEdge('b', 'c', 8);g.AddEdge('b', 'h', 11);g.AddEdge('c', 'i', 2);g.AddEdge('c', 'f', 4);g.AddEdge('c', 'd', 7);g.AddEdge('d', 'f', 14);g.AddEdge('d', 'e', 9);g.AddEdge('e', 'f', 10);g.AddEdge('f', 'g', 2);g.AddEdge('g', 'h', 1);g.AddEdge('g', 'i', 6);g.AddEdge('h', 'i', 7);Graph<char, int> kminTree;cout << "Kruskal:" << g.Kruskal(kminTree) << endl;kminTree.Print();cout << endl << endl;Graph<char, int> pminTree;cout << "Prim:" << g.Prim(pminTree, 'a') << endl;pminTree.Print();cout << endl;for (size_t i = 0; i < strlen(str); ++i){cout << "Prim:" << g.Prim(pminTree, str[i]) << endl;}}

 

邻接表

template<class W>
struct Edge
{//int _srci;int _dsti;  // 目标点的下标W _w;		// 权值Edge<W>* _next;Edge(int dsti, const W& w):_dsti(dsti), _w(w), _next(nullptr){}
};template<class V, class W, bool Direction = false>
class Graph
{typedef Edge<W> Edge;
public:Graph(const V* a, size_t n){_vertexs.reserve(n);for (size_t i = 0; i < n; ++i){_vertexs.push_back(a[i]);_indexMap[a[i]] = i;}_tables.resize(n, nullptr);}size_t GetVertexIndex(const V& v){auto it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else{//assert(false);throw invalid_argument("顶点不存在");return -1;}}void AddEdge(const V& src, const V& dst, const W& w){size_t srci = GetVertexIndex(src);size_t dsti = GetVertexIndex(dst);// 1->2Edge* eg = new Edge(dsti, w);eg->_next = _tables[srci];//新创建的边的 _next 指针指向当前 _tables[srci] 所指向的链表头节点_tables[srci] = eg;//更新 _tables[srci] 使其指向新创建的边 eg,即将新边插入到链表头部// 2->1if (Direction == false){Edge* eg = new Edge(srci, w);eg->_next = _tables[dsti];_tables[dsti] = eg;}}void Print(){// 顶点for (size_t i = 0; i < _vertexs.size(); ++i){cout << "[" << i << "]" << "->" << _vertexs[i] << endl;}cout << endl;for (size_t i = 0; i < _tables.size(); ++i){cout << _vertexs[i] << "[" << i << "]->";Edge* cur = _tables[i];while (cur){cout << "[" << _vertexs[cur->_dsti] << ":" << cur->_dsti << ":" << cur->_w << "]->";cur = cur->_next;}cout << "nullptr" << endl;}}private:vector<V> _vertexs;			// 顶点集合map<V, int> _indexMap;		// 顶点映射下标vector<Edge*> _tables;		// 邻接表//表示存储每个顶点对应的边链表的表头指针数组
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/74923.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构:探秘AVL树

本节重点 理解AVL树的概念掌握AVL树正确的插入方法利用_parent指针正确更新平衡因子掌握并理解四种旋转方式&#xff1a;左单旋&#xff0c;右单旋&#xff0c;左右双旋&#xff0c;右左双旋 一、AVL树的概念 AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis&…

电源系统的热设计与热管理--以反激式充电器为例

前言 反激电源常用于各种电子设备中&#xff0c;比如充电器、适配器等&#xff0c;它们通过变压器进行能量转换。高温环境可能对电子元件造成影响&#xff0c;特别是像MOSFET、二极管、变压器这样的关键部件&#xff0c;导致效率变低&#xff0c;甚至可能导致功能失效。还有安…

linux课程学习二——缓存

一.文件io与标准io的一个区别 遇到死循环可以ctrl c结束进程 使用printf输出&#xff0c;输出没有问题 用wirte输出&#xff0c;参数1&#xff0c;可以理解为上面介绍的linux标准文件描述符的1&#xff08;STDOUT&#xff09;标准输出&#xff0c;我们加上一个死循环while&…

Kafka中的消息如何分配给不同的消费者?

大家好&#xff0c;我是锋哥。今天分享关于【Kafka中的消息如何分配给不同的消费者&#xff1f;】面试题。希望对大家有帮助&#xff1b; Kafka中的消息如何分配给不同的消费者&#xff1f; 在 Kafka 中&#xff0c;消息是通过 主题&#xff08;Topic&#xff09; 进行组织的&…

Android的安全问题 - 在 Android 源码的 system/sepolicy 目录中,区分 public、private 和 vendor的目的

参考&#xff1a;Google文档 在 Android 8.0 及更高版本中自定义 SEPolicy 在 Android 源码的 system/sepolicy 目录中&#xff0c;区分 public、private 和 vendor 是为了模块化 SELinux 策略&#xff0c;并明确不同部分的访问权限和接口边界。这种设计主要基于以下原因&…

Java NIO之FileChannel 详解

关键点说明 文件打开选项&#xff1a; StandardOpenOption.CREATE - 文件不存在时创建 StandardOpenOption.READ/WRITE - 读写权限 StandardOpenOption.APPEND - 追加模式 StandardOpenOption.TRUNCATE_EXISTING - 清空已存在文件 缓冲区操作&#xff1a; ByteBuffer.wrap…

stock-pandas,一个易用的talib的替代开源库。

原创内容第841篇&#xff0c;专注智能量化投资、个人成长与财富自由。 介绍一个ta-lib的平替——我们来实现一下&#xff0c;最高价突破布林带上轨&#xff0c;和最低价突破布林带下轨的可视化效果&#xff1a; cross_up_upper stock[high].copy()# cross_up_upper 最高价突破…

JVM 面经

1、什么是 JVM? JVM 就是 Java 虚拟机&#xff0c;它是 Java 实现跨平台的基石。程序运行之前&#xff0c;需要先通过编译器将 Java 源代码文件编译成 Java 字节码文件&#xff1b;程序运行时&#xff0c;JVM 会对字节码文件进行逐行解释&#xff0c;翻译成机器码指令&#x…

【JavaScript】合体期功法——DOM(一)

目录 DOMWeb API 基本概念作用和分类 什么是 DOMDOM 树DOM 对象 获取 DOM 元素根据 CSS 选择器来获取 DOM 元素选择匹配的第一个元素选择匹配的多个元素 其他获取 DOM 元素方法 修改元素的内容对象.innerText 属性对象.innerHTML 属性案例&#xff1a;年会抽奖 修改元素属性修改…

GAMMA数据处理(十)

今天向别人请教了一个问题&#xff0c;刚无意中搜索到了一模一样的问题 不知道这个怎么解决... ok 解决了 有一个GAMMA的命令可转换 但是很奇怪 完全对不上 转换出来的行列号 不知道为啥 再试试 是因为经纬度坐标的小数点位数 de as

Java入门知识总结——章节(二)

ps&#xff1a;本章主要讲数组、二维数组、变量 一、数组 数组是一个数据容器&#xff0c;可用来存储一批同类型的数据 &#x1f511;&#xff1a;注意 类也可以是一个类的数组 public class Main {public static class Student {String name;int age; // 移除 unsignedint…

动态IP:网络世界的“变色龙”如何改变你的在线体验?

你知道吗&#xff1f;有时候我觉得动态IP就像是网络世界里的“变色龙”。它不像静态IP那样一成不变&#xff0c;而是随时在变化&#xff0c;像是一个永远在换衣服的演员。你永远不知道它下一秒会变成什么样子&#xff0c;但正是这种不确定性&#xff0c;让它变得特别有趣。想象…

从24GHz到71GHz:Sivers半导体的广泛频率范围5G毫米波产品解析

在5G技术的浪潮中&#xff0c;Sivers半导体推出了创新的毫米波无线产品&#xff0c;为通信行业带来高效、可靠的解决方案。这些产品支持从24GHz到71GHz的频率&#xff0c;覆盖许可与非许可频段&#xff0c;适应高速、低延迟的通信场景。 5G通信频段的一点事儿及Sivers毫米波射频…

aocache:AOCache 新增功能深度解析:从性能监控到灵活配置的全方位升级

最近对aocache 进行了重要升级&#xff0c;最新版本0.6.0增加了几项新功能&#xff1a;性能分析日志&#xff0c;AOCache性能分析工具&#xff0c;切入点自定义配置&#xff0c;全局配置&#xff0c;本文详细说明这几项目新功能的作用和使用方式。 一、性能分析日志 需求背景…

Java EE 进阶:MyBatis-plus

MyBatis-plus的介绍 MyBatis-plus是MyBatis的增强工具&#xff0c;在MyBatis的基础上做出加强&#xff0c;只要MyBatis有的功能MyBatis-plus都有。 MyBatis-plus的上手 添加依赖 在我们创建项目的时候&#xff0c;我们需要添加MyBatis-plus和mysql的依赖 MyBatis-plus的依赖…

GitHub和Gitee上的一些AI项目

以下是GitHub和Gitee上的一些AI项目&#xff1a; GitHub上的AI项目 TensorFlow&#xff1a;一个端到端开源机器学习平台&#xff0c;包含大量工具和库&#xff0c;广泛应用于图像识别、自然语言处理等领域。PyTorch&#xff1a;由Facebook开发的开源深度学习框架&#xff0c;…

JavaScript网页设计高级案例:构建交互式图片画廊

JavaScript网页设计高级案例&#xff1a;构建交互式图片画廊 在现代Web开发中&#xff0c;交互式元素已成为提升用户体验的关键因素。本文将通过一个高级案例 - 构建交互式图片画廊&#xff0c;展示如何结合HTML和JavaScript创建引人入胜的网页应用。这个案例不仅涵盖了基础的…

Linux命令大全:从入门到高效运维

适合人群&#xff1a;Linux新手 | 运维工程师 | 开发者 目录 一、Linux常用命令&#xff08;每天必用&#xff09; 1. 文件与目录操作 2. 文件内容查看与编辑 二、次常用命令&#xff08;按需使用&#xff09; 1. 系统管理与监控 2. 网络与通信 3. 权限与用户管理 三、…

Windows 10/11 使用 VSCode + SSH 免密远程连接 Ubuntu 服务器(指定端口)

摘要&#xff1a; 本文详细介绍如何在 Windows 系统上通过 VSCode Remote-SSH 免密登录远程 Ubuntu 服务器&#xff08;SSH 端口 2202&#xff09;&#xff0c;避免每次输入密码的繁琐操作&#xff0c;提高开发效率。 1. 环境准备 本地系统&#xff1a;Windows 10/11远程服务…

一些需要学习的C++库:CGAL和Eysshot

写在前面&#xff1a; 从开始工作到现在&#xff0c;去过多家公司&#xff0c;多个行业&#xff0c; 虽然大部分时间在通信业&#xff0c;但也有其它的行业的工作没有做完&#xff0c;但也很感兴趣。每次想要研究一下时&#xff0c;总是想不起来。 这里写一些信息&#xff0c;…