图的实现(c++)

 图(graph)是用线连接在一起的顶点或节点的集合,即两个要素:边和顶点。每一条边连接个两个顶点,用(i,j)表示顶点为 i 和 j 的边。

​ 如果用图示来表示一个图,一般用圆圈表示顶点,线段表示边。有方向的边称为有向边,对应的图成为有向图,没有方向的边称为无向边,对应的图叫无向图。对于无向图,边(i, j)和(j,i)是一样的,称顶点 i 和 j 是邻接的,边(i,j)关联于顶点 i 和 j ;对于有向图,边(i,j)表示由顶点 i 指向顶点 j 的边,即称顶点 i 邻接至顶点 j ,顶点 i 邻接于顶点 j ,边(i,j)关联至顶点 j 而关联于顶点 i 。

​ 对于很多的实际问题,不同顶点之间的边的权值(长度、重量、成本、价值等实际意义)是不一样的,所以这样的图被称为加权图,反之边没有权值的图称为无权图。所以,图分为四种:加权有向图,加权无向图,无权有向图,无权无向图。

 

图的表现有很多种,邻接表法,临接矩阵等。

图经常是以这种形式出现的[weight,from,to]的n*3维数组出现的,见名知意,三个元素分别为边的权重,从哪儿来,到哪儿去。

 

本文以一个包含全部结点和边的对象来描述加权有向图。

其他三种稍微改下即可。

以下为结点类

class Node{
public:
	Node(int val){
		value=val;
		in=0;
		out=0;
		}
	int value;
	int in; //入度,有多少个边指向此结点
	int out;	//出度,有多少条边由此结点发散
	list<Node*> nexts;  //此结点是from的情况下,邻居结点
	list<Edge*> edges;	//从此结点出发,发散出边的集合

};

边类

class Edge
{
public:
	int weight;
	Node* from;
	Node* to;
	Edge();	
	Edge(int _weight,Node* _from,Node* _to)
	{
		weight=_weight;
		from=_from;
		to=_to;	
	}	
};

图类

class Graph{
public:
	map<int,Node*> nodes;// 点序号和结点的映射集合
	set<Edge*> edges;	//边的集合
	
};

以下为创建一个图:

Graph* CreateGraph(int matrix[][3],int n)	//n表示边数 即matrix.size()
{ 
	Graph* graph=new Graph;
	for(int i=0;i!=n;i++)
	{
		int weight=matrix[i][0];
		int from=matrix[i][1];
		int to=matrix[i][2];
		if(graph->nodes.find(from)==graph->nodes.end())	
		{
			graph->nodes[from]=new Node(from);
		}	
		
		if(graph->nodes.find(to)==graph->nodes.end())	
		{
			graph->nodes[to]=new Node(to);
		}	
		
		Node* fromnode=graph->nodes[from];
		Node* tonode=graph->nodes[to];
		
		Edge* newedge=new Edge(weight,fromnode,tonode);
		fromnode->nexts.push_back(tonode);
		fromnode->out++;
		fromnode->edges.push_back(newedge);
		
		tonode->in++;
		
		graph->edges.insert(newedge);	

	}
	return graph;
}

可以清楚的看出每个结点的入度,出度,指向的结点,散发出的边。

 

图的广度(宽度)优先遍历(用队列辅助)

步骤:1 利用队列实现

2. 从源节点开始依次按照宽度进队列,然后弹出

3.每弹出一个点,把该点邻接点中没有进过队列的放队列中

4.直到队列边空。

//宽度(广度)优先遍历
void bfs(Node* node)
{
	if(node==NULL)
	{
		return;
	}	
	deque<Node*>	deq;
	set<Node*> set;
	
	deq.push_back(node);
	set.insert(node);
	while(deq.size()!=0)
	{	
		Node* cur=deq.front();	//保存deq队列首元
		deq.pop_front();//出队列打印
		cout<<cur->value<<" ";
		for(Node* next:cur->nexts)
		{
			if(set.find(next)==set.end())
			{				
				deq.push_back(next);
				set.insert(next);
			}
		}	
	}
	cout<<endl;
}

图的广度优先遍历(用栈(本段代码用的deque,实际只尾端进出))

1.利用栈实现

2.从源节点开始把节点按照深度放入栈,然后弹出

3.每弹出一个点,把该结点下一个没有进过栈的邻接点放入栈

4.直到栈变空


//图的深度优先遍历
void dfs(Node* node)
{
	if(node==NULL)
	{
		return;	
	}	
	
	deque<Node*> deq;
	set<Node*> set;
	deq.push_back(node);
	set.insert(node);
	cout<<node->value<<" ";
	while(deq.size()!=0)
	{
		Node* cur=deq.back();
		deq.pop_back();
		for(Node* next:cur->nexts)
		{
			if(set.find(next)==set.end())
			{
				deq.push_back(cur);
				deq.push_back(next);
				set.insert(next);
				cout<<next->value<<" ";
				break;
			}
		}

	}
}

谢谢阅读,欢迎指出错误!!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值