基于邻接表的图的储存(c++)

基于邻接表实现图的数据存储,遍历,方便之后对图论中最短路径算法的学习

储存图的类型:

图(graph)的基本概念

通过结构体定义邻接表的两个参数(边结点,顶点表)

//图的数据结构
//边表的节点
struct Arc {
	//每条边在对应在顶表中的位置
	int arc_pos;
	//边的权重
	int arc_weight;
	//边的下一个节点指针
	Arc* arc_next;
};
//顶点表
struct Ver {
	//顶点的编号(这里就式顶点数组的下表了)
	int ver_name;
	//顶点中指向第一个节点的指针
	Arc* ver_next;
	//顶点是否访问过
	bool ver_viste = false;
};

通过类封装构一个图的数据结构

Graph_data.h

#pragma once
#include <iostream>
#include <vector>
#include <map>
#include <string>

using namespace std;
//基于邻接表的图

//图的数据结构
//边表的节点
struct Arc {
	//每条边在对应在顶表中的位置
	int arc_pos;
	//边的权重
	int arc_weight;
	//边的下一个节点指针
	Arc* arc_next;
};
//顶点表
struct Ver {
	//顶点的编号(这里就式顶点数组的下表了)
	int ver_name;
	//顶点中指向第一个节点的指针
	Arc* ver_next;
	//顶点是否访问过
	bool ver_viste = false;
};

class Graph
{
public:
	//成员函数
	Graph(int ver,int arc,string file);
	//填充顶点表
	void Creat_verset();
	//创建图
	void Creat_graph();
	//插入边
	void Creat_arc(int head,int tail,int w);
	//输入边集
	void Creat_arcset();

	检查
	//void print();
	//两种遍历
	void dfs(int n);
	void Print_DFS();
	void bfs(int n);
	void Print_BFS();
	~Graph() {};

	//成员变量
	//顶点数
	int m_vernumber;
	//边数
	int m_arcnumber;
	//顶点表
	vector<Ver> m_vertable;
	//边集
	multimap<int, int>m_arcset;
	multimap<int, multimap<int, int>> m_Arcset;
	//边集文本
	string F;
};

Graph_data.cpp

#include "Graph_data.h"
#include "Data_file.h"

using namespace std;

Graph::Graph(int ver,int arc,string file)
{
	//构造函数初始化顶点数,边数以及顶点表
	this->m_vernumber = ver;
	this->m_arcnumber = arc;
	this->m_vertable.clear();
	this->m_arcset.clear();
	this->F = file;
}

void Graph::Creat_verset()
{
	Ver temp_v;
	//循环填充数字作为顶点编号
	for (int i = 0; i < this->m_vernumber; ++i) {
		temp_v.ver_name = i;
		temp_v.ver_next = NULL;
		m_vertable.push_back(temp_v);
	}
	//通过读取文件生成顶点集
}

void Graph::Creat_arc(int head,int tail,int w)
{
	Arc* temp_a = new Arc;
	Arc* temp = NULL;
	//边的参数赋值
	temp_a->arc_pos = tail;
	temp_a->arc_weight = w;
	temp_a->arc_next = NULL;
	temp= this->m_vertable[head].ver_next;
	//当插入的边是该顶点的第一条边时
	if (this->m_vertable[head].ver_next == NULL) {
		this->m_vertable[head].ver_next = temp_a;
		return;
	}
	//当插入的边不是该顶点的第一条边时
	while (temp->arc_next != NULL) {
		temp = temp->arc_next;
	}
	temp->arc_next = temp_a;
}

void Graph::Creat_arcset()
{
	if (this->m_vertable.empty()) {
		cout << "顶点表为空" << endl;
		return;
	}
	cout << "顶点列表如下:" << endl;
	for (auto& it = this->m_vertable.begin(); it != this->m_vertable.end(); ++it) {
		cout << it->ver_name << " ";
	}
	cout << endl;
	cout << "请输入需要建立边的两个顶点:" << endl;

	int a = 0, b = 0;
	while (cin >> a >> b) {
		cout << "请输入下一组数据:" << endl;
		this->m_arcset.insert(make_pair(a, b));
	}
	//更新边数为添加的个数
	this->m_arcnumber = this->m_arcset.size();
	cout << this->m_arcnumber << endl;
}

void Graph::Creat_graph()
{
	//建立顶点集
	this->Creat_verset();

	//从文件中读取边集以及权重
	Data_file data;
	this->m_Arcset = data.Read_data(this->F);
	this->m_arcnumber = data.arc_num;
	//创建顶点之间的边
	int h, t, w;
	multimap<int, int> temp;
	for (auto& it = this->m_Arcset.begin(); it != this->m_Arcset.end(); ++it) {
		w = it->first;
		temp = it->second;
		for (auto& k:temp) {
			h = k.first;
			t = k.second;
		}
		this->Creat_arc(h,t,w);
	}

	//手动输入建立边集
	//this->Creat_arcset();
	创建顶点之间的边
	//for (auto& it = this->m_arcset.begin(); it != this->m_arcset.end(); ++it) {
	//	int head = it->first;
	//	int tail = it->second;
	//	this->Creat_arc(head, tail, 1);
	//}
}

void Graph::dfs(int n)
{
	//将顶点状态更改为已访问
	this->m_vertable[n].ver_viste = true;
	//输出顶点
	cout << this->m_vertable[n].ver_name << " ";
	//访问该顶点的邻接顶点
	Arc* tep = this->m_vertable[n].ver_next;
	int k = -1;
	while (tep != NULL) {
		k = tep->arc_pos;
		//如果邻接顶点未访问过,进入递归继续访问其的邻接顶点
		if (this->m_vertable[k].ver_viste == false) {
			dfs(k);
		}
		//否则访问其余的邻接顶点
		tep = tep->arc_next;
	}
}

void Graph::Print_DFS()
{
	//遍历顶点表中的所有顶点
	for (int i = 0; i < this->m_vertable.size();++i) {
		//如果之前访问过直接跳过
		if (this->m_vertable[i].ver_viste == false) {
			//如果第一次访问进入递归
			dfs(i);
		}
	}
	cout << endl;
}

void Graph::bfs(int n)
{
	//如果第一次访问,就输出,否则跳过
	if (this->m_vertable[n].ver_viste == false) {
		this->m_vertable[n].ver_viste = true;
		cout << this->m_vertable[n].ver_name << " ";
	}
	//访问该顶点的所有邻接顶点
	Arc* tep = this->m_vertable[n].ver_next;
	int k = -1;
	while (tep != NULL) {
		k = tep->arc_pos;
		//未访问过就输出,否则访问下一个
		if (this->m_vertable[k].ver_viste == false) {
			this->m_vertable[k].ver_viste =true;
			cout << k << " ";
		}
		tep = tep->arc_next;
	}

}

void Graph::Print_BFS()
{
	//遍历顶点表中的所有顶点
	for (int i = 0; i < this->m_vertable.size(); ++i) {
		bfs(i);
	}
	cout << endl;
}

//void Graph::print()
//{
//	cout << "与0连接的点:";
//	Arc* temp = this->m_vertable[0].ver_next;
//	while (temp != NULL) {
//		cout << temp->arc_pos << " ";
//		temp = temp->arc_next;
//	}
//	
//}

其中对于边权重的输入,为了方便输入,就采用读写文本来进行边的建立,和权重赋值

#include "Data_file.h"
#include <map>

using namespace std;

multimap<int,multimap<int, int>> Data_file::Read_data(string file)
{
	int h = -1, t = -1,w=-1;
	multimap<int, int> arc;
	multimap<int,multimap<int,int>> arcset;
	ifstream ifs(file, ios::in);
	if (!ifs.is_open())
	{
		cout << "未成功打开文件" << endl;
	}

	while (!ifs.eof())
	{
		ifs >> h >> t >> w;
		arc.insert(make_pair(h, t));
		arcset.insert(make_pair(w,arc));
		this->arc_num++;
	}
	ifs.close();
	return arcset;
}

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是基于邻接表的无向的广度优先遍历的C代码: ```c #include <stdio.h> #include <stdlib.h> #define MAXV 1000 // 顶点数的最大值 typedef struct node *node_pointer; struct node{ int vertex; // 邻接点在顶点表中的下标 node_pointer next; // 下一个邻接点 }; typedef struct graph *graph_pointer; struct graph{ node_pointer adj_list[MAXV]; int nvertices; // 中顶点数 }; int visited[MAXV]; void bfs(graph_pointer G, int start){ int queue[MAXV], front = -1, rear = -1; node_pointer ptr; int v; queue[++rear] = start; visited[start] = 1; while(front != rear){ v = queue[++front]; printf("%d ", v); // 访问顶点v // 将顶点v的邻接点加入队列中 for (ptr = G->adj_list[v]; ptr != NULL; ptr = ptr->next){ if(!visited[ptr->vertex]){ queue[++rear] = ptr->vertex; visited[ptr->vertex] = 1; } } } } int main(){ graph_pointer G; int i, j, n, m, v1, v2; printf("输入顶点数和边数:"); scanf("%d%d", &n, &m); G = (graph_pointer)malloc(sizeof(struct graph)); G->nvertices = n; // 初始化邻接表 for (i = 1; i <= n; i++){ G->adj_list[i] = NULL; } // 建立邻接表 for (i = 1; i <= m; i++){ printf("输入一条边的两个顶点:"); scanf("%d%d", &v1, &v2); node_pointer new_node1 = (node_pointer)malloc(sizeof(struct node)); node_pointer new_node2 = (node_pointer)malloc(sizeof(struct node)); new_node1->vertex = v2; new_node1->next = G->adj_list[v1]; G->adj_list[v1] = new_node1; new_node2->vertex = v1; new_node2->next = G->adj_list[v2]; G->adj_list[v2] = new_node2; } // 广度优先遍历 printf("广度优先遍历的结果:"); for (i = 1; i <= n; i++){ visited[i] = 0; } bfs(G, 1); return 0; } ``` 代码中,我们定义了一个结构体 `graph` 来存储邻接表,其中 `adj_list` 数组存储每个顶点的邻接点链表,`nvertices` 存储中的顶点数。`node` 结构体用于定义邻接点,其中 `vertex` 存储邻接点在顶点表中的下标,`next` 存储下一个邻接点的指针。我们还定义了一个 `visited` 数组,用于标记每个顶点是否已经遍历过。 在 `main()` 函数中,我们首先从用户输入中读入的顶点数和边数,然后利用 `malloc()` 动态分配 `graph` 结构体的存储空间。接着,我们初始化邻接表,将每个顶点的邻接点指针初始化为 `NULL`。然后,我们读入每一条边,并且根据边的两个顶点建立邻接表。最后,我们调用 `bfs()` 函数进行广度优先遍历,从顶点 `1` 开始遍历整个。 `bfs()` 函数中,我们使用 `queue` 数组来存储待遍历的顶点,`front` 和 `rear` 分别指向队列的头和尾。我们首先将起始顶点 `start` 加入队列中,并标记为已访问。然后,我们不断从队列中取出一个顶点 `v`,访问该顶点,并将其邻接点加入队列中(如果邻接点尚未访问过)。这一过程一直持续到队列为空。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值