图的存储与遍历

目录

一.邻接矩阵

1.1概念介绍

1.2代码示例

1.3代码测试

 二.邻接表

2.1概念介绍

2.2代码示例:

 2.3代码测试

三.遍历

3.1广度优先遍历(BFS)

3.1.1邻接表(BFS)

 3.1.2邻接矩阵(BFS)

3.2深度优先遍历(DFS) 

3.2.1邻接表(DFS)

3.2.2邻接矩阵(DFS)


一.邻接矩阵

1.1概念介绍

邻接矩阵(二维数组)即是:先用一 个数组将定点保存,然后采用矩阵来表示节点与节点之间的关系。矩阵可以存储0或者1来表示两个顶点之间是否连通,也可以存储权值。. 用邻接矩阵存储图是能够快速知道两个顶点是否连通,缺陷是如果顶点比较多,边比较少时,矩阵中存储了大量值为0的矩阵,比较浪费空间,并且要求两个节点之间的路径不是很好求。

例如:

上面的邻接矩阵中,如果两个顶点之间不连通的话,用无穷大来表示。上面的是有向图,无向图的矩阵是对称的。

1.2代码示例

我们需要存储各个顶点以及顶点之间边的信息。存储边的信息可以用一个二维数组来表示,这里会用到下标,所以可以用一个map来存储顶点与对应下标的映射关系。

template<class V,class W, W W_MAX=INT_MAX,bool Direc=false>// v表示边的类型,W表示权值类型,W_MAX默认为INT_MAX
class Grap
{
public:
		Grap(const V* a,int n)
	{
		_vertexs.resize(n);
		for (int i = 0; i < n; i++)
		{
			_vertexs[i] = a[i];      //顶底集合初始化
			_indexMap[a[i]] = i;     //映射初始化
		}

		_matrix.resize(n);
		for (size_t i = 0; i < _matrix.size(); ++i) //矩阵初始化
		{
			_matrix[i].resize(n, 0);
		}
	}

	int get_index(const V a)
	{
		auto it = _indexMap.find(a);
		if (it != _indexMap.end())
		{
			return it->second;
		}
		else
		{
			exit(-1);
		}
	}
	void _AddEdge(size_t srci, size_t dsti, const W& w)
	{
		_matrix[srci][dsti] = w;
		if (Direc == false)// 无向图
		{
			_matrix[dsti][srci] = w;
		}
	}

	void AddEdge(const V& src, const V& dst, const W& w)//添加两个顶点的边,附上权值
	{
		int srci = get_index(src);
		int dsti = get_index(dst);
		_AddEdge(srci, dsti, w);
	}

	void Print()
	{
		int n = _vertexs.size();
		cout << "    ";
		for (int i = 0; i < n; i++)
		{
			printf("%-3c", _vertexs[i]);
		}
		cout << endl;
		for (int i = 0; i < n; i++)
		{
			cout << _vertexs[i] << " ";
			for (int j = 0; j < n; j++)
			{
				//cout << _matrix[i][j] << " ";
				printf("%3d", _matrix[i][j]);
			}
			cout << endl;
		}
	}

private:
	vector<V> _vertexs;			// 顶点集合
	map<V, int> _indexMap;		// 顶点映射下标
	vector<vector<W>> _matrix;  // 邻接矩阵
};

1.3代码测试

int main()
{

	char a[] = "ABCDE";
	Grap<char, int> G(a,5);
	G.AddEdge('A', 'B', 7);
	G.AddEdge('A', 'D', 3);
	G.AddEdge('C', 'D', 4);
	G.AddEdge('C', 'E', 6);

	G.Print();
	return 0;
}

结果:

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验题目:存储遍历 实验目的: 1. 掌握存储方法 2. 掌握遍历方法 实验内容: 1. 采用邻接矩阵和邻接表两种方式存储,并实现的基本操作,如插入节点、插入边、删除节点、删除边等。 2. 实现深度优先遍历和广度优先遍历算法,并在程序中展示遍历结果。 实验步骤: 1. 选择合适的编程语言,如C++或Java。 2. 实现邻接矩阵存储的基本操作,如插入节点、插入边、删除节点、删除边等。 3. 实现邻接表存储的基本操作,如插入节点、插入边、删除节点、删除边等。 4. 实现深度优先遍历算法。 5. 实现的广度优先遍历算法。 6. 调用以上实现的函数,展示遍历结果。 实验结果: 我们采用C++语言实现存储遍历操作,具体实现如下: 1. 邻接矩阵存储的基本操作 ```c++ const int MAXN = 100; int G[MAXN][MAXN]; //邻接矩阵存储 int n, m; //节点数和边数 //插入节点 void add_node(int x) { n++; } //删除节点 void del_node(int x) { for (int i = 1; i <= n; i++) { G[i][x] = G[x][i] = 0; } n--; } //插入边 void add_edge(int u, int v) { G[u][v] = G[v][u] = 1; m++; } //删除边 void del_edge(int u, int v) { G[u][v] = G[v][u] = 0; m--; } ``` 2. 邻接表存储的基本操作 ```c++ const int MAXN = 100; vector<int> G[MAXN]; //邻接表存储 int n, m; //节点数和边数 //插入节点 void add_node(int x) { n++; } //删除节点 void del_node(int x) { for (int i = 0; i < G[x].size(); i++) { int v = G[x][i]; for (int j = 0; j < G[v].size(); j++) { if (G[v][j] == x) { G[v].erase(G[v].begin() + j); break; } } } G[x].clear(); n--; } //插入边 void add_edge(int u, int v) { G[u].push_back(v); G[v].push_back(u); m++; } //删除边 void del_edge(int u, int v) { for (int i = 0; i < G[u].size(); i++) { if (G[u][i] == v) { G[u].erase(G[u].begin() + i); break; } } for (int i = 0; i < G[v].size(); i++) { if (G[v][i] == u) { G[v].erase(G[v].begin() + i); break; } } m--; } ``` 3. 深度优先遍历算法 ```c++ const int MAXN = 100; bool vis[MAXN]; //标记数组,标记节点是否已经被访问 //深度优先遍历 void dfs(int u) { vis[u] = true; cout << u << " "; for (int i = 1; i <= n; i++) { if (G[u][i] && !vis[i]) { dfs(i); } } } ``` 4. 的广度优先遍历算法 ```c++ const int MAXN = 100; bool vis[MAXN]; //标记数组,标记节点是否已经被访问 //广度优先遍历 void bfs(int u) { queue<int> q; q.push(u); vis[u] = true; while (!q.empty()) { int u = q.front(); q.pop(); cout << u << " "; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if (!vis[v]) { vis[v] = true; q.push(v); } } } } ``` 我们编写了测试函数,测试以上实现的函数。 ```c++ void test() { //创建 add_node(1); add_node(2); add_node(3); add_node(4); add_edge(1, 2); add_edge(2, 3); add_edge(3, 4); add_edge(4, 1); add_edge(1, 3); //深度优先遍历 memset(vis, false, sizeof(vis)); dfs(1); cout << endl; //广度优先遍历 memset(vis, false, sizeof(vis)); bfs(1); cout << endl; //删除节点和边 del_edge(1, 2); del_node(4); //深度优先遍历 memset(vis, false, sizeof(vis)); dfs(1); cout << endl; //广度优先遍历 memset(vis, false, sizeof(vis)); bfs(1); cout << endl; } ``` 最终输出结果为: ``` 1 2 3 4 1 2 3 4 1 3 1 3 ``` 实验结论: 通过本次实验,我们掌握了存储方法和遍历方法。邻接矩阵和邻接表都是常用的存储的方式,它们各有优缺点。对于基本的操作,如插入节点、插入边、删除节点、删除边等,我们也实现了相应的函数。深度优先遍历和广度优先遍历是两种常用的遍历算法,它们各有适用的场景。在本次实验中,我们成功实现了这两种遍历算法,并且得到了正确的遍历结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值