基于邻接表实现图的数据存储,遍历,方便之后对图论中最短路径算法的学习
储存图的类型:
通过结构体定义邻接表的两个参数(边结点,顶点表)
//图的数据结构
//边表的节点
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;
}