ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

图-数据结构

2021-07-22 23:06:36  阅读:181  来源: 互联网

标签:Node emplace temp int hstable nexts 数据结构


常见表达图的形式有,邻接表:数组+链表
邻接矩阵:二维数组
从这组成结构上看,邻接表适合表达稀疏图,邻接矩阵适合表达稠密图
当然表达图结构的方式不止只有上面两种结构。

下面自己定义图的结构,由以下部分组成:
1.图的结构 a.顶点,b.边 ,c.图 d.图生成器
2.图的经典算法:a,深度优先搜索 ,b.广度优先搜索 ,c.拓扑排序 ,d.最小生成树p算法 e.单源最短路径dijkstra算法

// 图.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//2021.7.21
//尽量根据实际情况舍弃一些多余的结构,比如顶点,边,图数据类型,只保存对实际情况有用的数据,使空间复杂度尽可能的小

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include <cstring>
#include <queue>
#include <set>
#include <stack>
#include <map>

using namespace std;

//前置声明
class Node;
class Edge;
class Grape;
class Grapegenerator;    //图生成器
//点
class Node {
public:
	int value;   //值
	int in;      //入度
	int out;      //出度
	//int key;
	vector<Node>* nexts;  //发散出去的点
	vector<Edge>* edges; //发散出去的边
	//构造函数
	Node(int val)
	{
		this->value = val;
		in = 0;                      //入度
		out = 0;                     //出度
		nexts = new vector<Node>();  //由该点发散出来的点集
		edges = new vector<Edge>();  //由该点发散出来的边集
	}
	bool operator < (const Node &a) const
	{
		return value < a.value;                  //图这个数据结构中,value 就是key,不存在两个值相同的顶点
	}
	//析构函数这可以不写  不可乱写,只要图不消亡就不能清内存  可以在图生成器的类中做析构,将所有new出来的数据清
	/*~Node() 
	{
		delete nexts;
		delete edges;
	}*/
};
/*
bool operator == (const Node& a,const Node &b)
{
	return a.value == b.value && a.in == b.in && a.out == b.out && a.nexts == b.nexts && a.edges == b.edges;
}
struct cmpp {
	int operator ()(const Node &a)const
	{
		int zhi = a.value;
		return std::hash<int>()(zhi);
	}
};*/
//边
class Edge {
public:
	int weight; //权重
	Node *from;  //从哪个点出发
	Node *to;    //去哪个点结束
	//构造函数
	Edge(int wgt, Node *from, Node *to) :weight(wgt), from(from), to(to) {}
	/*bool operator <(Edge &a)const
	{
		return weight > a.weight;
	}*/
};
struct cmp {
	bool operator ()(Edge &a,Edge &b)
	{
		return a.weight > b.weight;
	}
};
//图
class Grape {
public:
	unordered_map<int, Node>* nodes;
	unordered_map<string,Edge>* edges;               //点集和边集
	//构造函数
	Grape()
	{
		nodes = new unordered_map<int, Node>();   //每个点有个key作为其编号
		edges = new unordered_map<string,Edge>();    //每条边有个key 作为其编号
	}
	~Grape()
	{
		for (auto i : *nodes)
		{
			delete i.second.nexts;
		}
		delete nodes;
		delete edges;
	}
};

class Grapegenerator {
public:
	Grapegenerator(const vector<vector<int>> &inmtx)  //以一个二维数组作为输入 根据实际需要可以对图做剪枝(只保留所需要的信息)
	{
		mygrape = new Grape();
		for (int i = 0; i < inmtx.size(); i++)
		{
			int weight = inmtx[i][0];
			int from = inmtx[i][1];
			int to = inmtx[i][2];    //获取一组点的信息
			if (mygrape->nodes->find(from) == mygrape->nodes->end())
			{
				mygrape->nodes->emplace(from, Node(from));
			}
			if (mygrape->nodes->find(to) == mygrape->nodes->end())
			{
				mygrape->nodes->emplace(to, Node(to));                     //图的点集
			}
			Node *fromNode = &(mygrape->nodes->at(from));
			Node *toNode = &(mygrape->nodes->at(to));
			Edge newEdge = Edge(weight, fromNode, toNode);
			fromNode->out++;
			toNode->in++;
			fromNode->nexts->emplace_back(*toNode);
			fromNode->edges->emplace_back(newEdge);
			string edge_key = to_string(from); // keg_edge
			edge_key.push_back('-');
			edge_key += to_string(to);
			//cout << edge_key << endl;
			mygrape->edges->emplace(edge_key, newEdge);//给边做个标号     //图的边集
		}
	}
	~Grapegenerator()
	{
		delete mygrape;
	}
	//图的深度优先遍历  需要一个出发节点
	void dfs()
	{
		Node *node = &mygrape->nodes->at(1);   //选定一个出发点
		if (node == nullptr)
		{
			return;
		}
		stack<Node*> mystack;
		set<Node> hstable;
		mystack.push(node);
		hstable.emplace(*node);
		cout << node->value << endl;
		while (!mystack.empty())
		{
			Node *temp = mystack.top();
			mystack.pop();
			for (int i = 0; i < temp->nexts->size(); i++)
			{
				if (hstable.find(temp->nexts->at(i)) == hstable.end())
				{
					mystack.push(temp);
					mystack.push(&temp->nexts->at(i));
					hstable.emplace(temp->nexts->at(i));
					cout << temp->nexts->at(i).value << endl;
					break;    //退出进入下一个节点 栈中实际上是保存了深度优先遍历的路径
				}
			}
		}
	}
	//图的宽度优先遍历  需要一个出发节点  每一层的顺序不重要,但是层的关系要体现出来 队列
	void bfs()
	{

		Node *node = &(mygrape->nodes->at(1));
		if (node == nullptr)  //无效数据直接退出
		{
			return;
		}
		queue<Node *> myqueue;     //队列
		set<Node> hstable;         //备忘录
		myqueue.emplace(node);
		hstable.emplace(*node);
		while (!myqueue.empty())
		{
			int n = myqueue.size();
			vector<int> vec;
			for (int j = 0; j < n; j++)
			{
				Node *temp = myqueue.front();
				myqueue.pop();
				//cout << temp->value << endl;
				vec.emplace_back(temp->value);
				for (int i = 0; i < temp->nexts->size(); i++)
				{
					if (hstable.find(temp->nexts->at(i)) == hstable.end())   //查备忘录
					{
						hstable.emplace(temp->nexts->at(i));
						myqueue.push(&(temp->nexts->at(i)));
					}
				}
			}
			for (auto i : vec)
			{
				cout << i << ' ';
			}
			cout << endl;

		}
	}
	//拓朴排序    顶点之间的依赖关系  有向图 有入度为0的顶点,没有环
	vector<int> tpsort()
	{
		set<Node> hstable;
		queue<Node> myqueue;
		for (auto i : *(mygrape->nodes))
		{
			hstable.emplace(i.second);
			if (i.second.in == 0)
			{
				myqueue.push(i.second);
			}
		}
		vector<int> ans;
		while (!myqueue.empty())
		{
			Node temp = myqueue.front();
			myqueue.pop();
			ans.emplace_back(temp.value);    //压入值
			for (Node i : *(temp.nexts))
			{   //这里要注意,这里很奇怪,直接修改指针指向的内容会有问题
				Node next = *hstable.find(i);
				hstable.erase(hstable.find(i));   //清除之前的那个顶点
				next.in--;
				hstable.emplace(next);            //压入改变in之后的顶点
				
				if (hstable.find(i)->in == 0)
				{
					myqueue.push(i);
				}
			}
		}
		return ans;
	}
	//最小生成树p算法 k算法需要不断的合并集合,所以不推荐
	int ptree()
	{
		priority_queue<Edge,vector<Edge>,cmp> s_heal;   //以边的weight 由小权重开始排  小根堆
		//vector<Edge> ans;                    //存放结果
		int ans = 0;
		set<Node> hstable;                  //备忘录
		for (auto i:*(mygrape->nodes))      //任何一个起点
		{
			hstable.emplace(i.second);
			for (Edge j:*i.second.edges)   //由一个点解锁一票边
			{
				s_heal.emplace(j);
			}
			while (!s_heal.empty())
			{
				Edge temp = s_heal.top();      //取出权值最小的边
				s_heal.pop();
				if (hstable.find(*temp.to) == hstable.end())   //查备忘录
				{
					//ans.emplace_back(temp);
					ans += temp.weight;
					hstable.emplace(*temp.to);
					for (Edge next : *temp.to->edges)
					{
						s_heal.emplace(next);
					}
				}
			}
			break;
		}
		return ans;
	}

	//迪杰特斯拉算法 dijkstra  适合没有权值为负数的边的图
	//用最小的点去遍历能得到最优的结果
	Node getminandunusepoint(map<Node,int> &a,set<Node> &b)
	{
		int minval = INT_MAX;
		Node ans = Node(0);  //临时对象
		for (auto i : a)
		{
			Node node = i.first;
			int distance = i.second;
			if (b.find(node) == b.end() && distance<minval)
			{
				ans = node;
				minval = distance;
			}
		}
		return ans;
	}
	map<Node, int> dijkstra()
	{
		Node node = mygrape->nodes->at(1);    //起始点
		map<Node, int> distance;
		distance.emplace(node,0);         //自己到自己距离为0
		set<Node> hstable;      //存放已经摸过的点
		Node temp = getminandunusepoint(distance,hstable);  //获取最小可用的顶点
		while (temp.value != 0 )      //0一般不为出现,因为我们的图设定从1开始的
		{
			int dis = distance[temp];
			for (Edge i : *(temp.edges))                        //放入多个点
			{
				Node toNode = *i.to;
				if (distance.find(toNode) == distance.end())  //还没加入备忘录中
				{
					distance.emplace(toNode,i.weight+dis);
				}
				else {                                      //已经加入备忘录中的
					distance[toNode] = min(distance[toNode],i.weight+dis);
				}
			}
			hstable.emplace(temp);   //不可以用了
			temp = getminandunusepoint(distance,hstable);  //更新点
		}
		return distance;
	}
private:
	Grape* mygrape;
};


int main()
{
    
	cout << "********************开始*********************" << endl;
	cout << "图中有几个点" << endl;
	cout << "权重  from  to" << endl;
	vector<vector<int>> test;
	vector<int> temp;
	int n;
	cin >> n;
	for (int i = 0;i<n;i++)
	{
		for (int j = 0;j<3;j++)
		{
			int mid;
			cin >> mid;
			temp.emplace_back(mid);
		}
		test.emplace_back(temp);
		temp.clear();
	}
	Grapegenerator zj = Grapegenerator(test);
	//zj.bfs();
	//zj.dfs();
	/*vector<int> temp1;
	temp1 = zj.tpsort();
	for (int i:temp1)
	{
		cout << i << endl;
	}*/
	/*vector<Edge> myedge;
	myedge = zj.ptree();
	for (Edge i:myedge)
	{
		cout << i.weight << endl;
	}*/
	map<Node,int> ans;
	ans = zj.dijkstra();
	for (auto i : ans)
	{
		cout << i.first.value << ':' << i.second << endl;
	}
	return 0;
}





标签:Node,emplace,temp,int,hstable,nexts,数据结构
来源: https://blog.csdn.net/weixin_41710007/article/details/119010715

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有