建图方法总结(采用哈希map的链式建图法)

摘要

本文将介绍利用哈希map进行建图操作的方法,使用C++STL:unordered_map 进行建图。该建图方法具有一定的局限性,但能适用于大部分图论的建图需求。相比于邻接表建图法,更容易理解和入门。

原理分析

选择unordered_map是由于其相对于map,查找速度更快,在遍历图时可以缩短时间复杂度。建图原理类似于邻接表,由一个元素映射一个集合。实现父节点与子节点集的对应。

该方法在定义时常搭配线性结构进行储存,如对于一般的图,可搭配vector初始化为: unordered_map<int,vector<int>>  mp; 

 <键值> 使用int表示某个节点,<实值>使用vector储存该节点的所有子节点的集合。

建图和遍历

  • 建图

定义了上述结构之后,可以以边为单位建立图结构。

假如一个图存在 4个节点5条边,具有(1,2)(1,3)(1,4)(2,3)(4,3)的结构,即

则建图时可以通过 mp[1] .push_bak(2)操作,来向节点1 对应的子节点集中添加节点2 。继续这个操作,使得mp内部存在 < 1,  {2,3,4} >的数据,则完成了对节点1和其子节点的入图操作。类似的,可以将整个图储存下来。

 

对于测试点n个节点,m条边,建图操作的代码如下:

#include<iostream>
#include<unordered_map>
#include<vector>
using namespace std;
unordered_map<int, vector<int>> mp;
int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < m; i++)
	{
		int a, b;        //由a指向b的一条边
		cin >> a >> b;
		mp[a].push_back(b);        //如果需要建立无向图,再构建mp[b].push_back(a)的关系即可; 
	}
}

 

  • 遍历

如果要遍历一个点的所有子节点,可以使用迭代器的方法进行遍历。

如对于上述例图,遍历1的所有子节点。可以采用

for(auto i : mp[1])
{
   cout << i;  //即子节点
}

 使用迭代器迭代节点1所指的vector数组中的所有元素,元素即为子节点。 

由此可以看出,该遍历方法比起数组支持的邻接表建图法十分简便,且利于理解和分析记忆。

DFS遍历的代码如下:

void DFS(int u)
{
	cout << u << " ";
	st[u] = 1;        //记录是否遍历过;
	for (auto i : mp[u])
	{
		if (!st[i]) DFS(i);        //搜索未遍历过的子点。
	}
}

BFS遍历的代码如下:

void BFS(int u)
{
	memset(st, 0, sizeof st);
	cout << u << " ";
	queue<int> q;
	q.push(u);
	st[u] = 1;
	while (!q.empty())
	{
		int temp = q.front();
		q.pop();
		for (auto i : mp[temp])    //取队列中头元素的子节点集
		{
			if (!st[i])
			{
				cout << i << " ";
                st[i]=1;
				q.push(i);
			}
		}
	}
}

优缺点分析

  • 优点:

使用该方法的优点是映射关系浅显易懂,建图和遍历操作都十分简便,对于初学图论更加利于使用。在代码量上减少很多。且由于使用了STL储存,可以随意更改元素类型。

  • 缺点:

由于unordered_map的创建耗时较多。所以相较于使用数组实现的邻接表建图更慢。

拓展...

如果题目要求建立带权图,那么可以更改mp数据结构的定义。

使用

unordered_map<int,vector<pair<int,int>>>  mp; 

在建图操作时,以a指向b的长度为c的边可以表示为

mp[a].push_back({b,c});

在遍历时,需要对vector迭代的过程中,取pair元素的first即可获得子节点,取second即可获得当前节点与子节点的距离。 

    
    for (int i = 0; i < m; i++)
	{
		int a, b, c;
		cin >> a >> b >> c;
		mp[a].push_back({ b,c });
	}


void DFS(int u)
{
	memset(st, 0, sizeof st);
	cout << u << " ";
	st[u] = 1;
	for (auto i : mp[u])
	{
		int j = i.first;
        int len = i.second;
		if (!st[j]) DFS(j);
	}
}

同时,哈希map也可以模拟邻接矩阵的思想进行建图,相比之下,可以储存邻接矩阵储存不了的稀疏图,对于节点数较大的图也可储存,其方法为;

unordered_map<int, unordered_map<int, int>>mp;

建图操作为 mp[a][b]=c;  可直接表示a到b的距离c;

遍历操作与vector和pair结合的结构进行的操作类似,其优点在于可以直接取任意两点:a到b的距离,通过操作mp[a].find(b)实现。其返回值如果为真,说明存在这样一条边。则查找边的时间复杂度可以降为O(1)。

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哈希map,可以使用以下方法: 1. 使用Java的HashMap类创哈希map对象。示例代码如下: ``` HashMap<KeyType, ValueType> hashMap = new HashMap<>(); ``` 其中KeyType是键的类型,ValueType是值的类型。可以根据实际需要替换为合适的类型。 2. 调用HashMap的put()方法来向哈希map中添加键值对。示例代码如下: ``` hashMap.put(key, value); ``` 其中key是键,value是对应的值。 3. 可以使用HashMap的get()方法来获取哈希map中特定键对应的值。示例代码如下: ``` ValueType value = hashMap.get(key); ``` 其中key是要获取值的键,value是对应的值。 4. 可以使用HashMap的containsKey()方法来检查哈希map中是否存在特定的键。示例代码如下: ``` boolean contains = hashMap.containsKey(key); ``` 其中key是要检查的键,contains是一个布尔值,表示是否存在对应的键。 需要注意的是,对于自定义的类作为键,需要覆写hashCode()和equals()方法来确保哈希map正常工作。还要注意,哈希map的性能受到哈希函数的选择和冲突处理机制的影响。正确地选择哈希函数和解决冲突的方法,可以提高哈希map的性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [c-hashmap:用于C编程语言的快速哈希maphash表(无论您要调用什么)](https://download.csdn.net/download/weixin_42139042/19057348)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Map&Set哈希表(基础+常用方法总结)](https://blog.csdn.net/m0_67995737/article/details/127467375)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值