【数据结构】无向图(构造+遍历)

说在前面

  • 实现语言:c++
  • vs版本:2017

无向图

  • 相关概念

    以下图为例
    在这里插入图片描述
    • 邻接矩阵
      无向图,只要一半就行
      顶点0与顶点1之间存在边,则在矩阵[0][1]位置填上1;酱紫

在这里插入图片描述

  • 邻接表
    与顶点0相连的顶点有顶点4与顶点1,那么将这两点的数据填入0后的链表;酱紫

在这里插入图片描述

  • 图的表示

    在以下实现中使用了STL容器(vector、queue、stack等)以及智能指针(shared_ptr),相关概念自行了解。
    在该示例中,图的存储使用邻接表
    //边结构体
    struct ArcNode
    {
    	int adjvex;//边的另一个顶点
    	shared_ptr<ArcNode> nextarc;//下一条边
    	//使用智能指针shared_ptr自动释放,不需要delete
    };
    
    //顶点结构体
    struct VNode
    {
    	int val;//顶点值
    	int color;//颜色值,白/黑
    	shared_ptr<ArcNode> firstarc;//第一条边
    	//使用链表存储所有以当前顶点为起始点的边
    };
    
    //顶点颜色
    enum Color
    {
    	black,//黑色表示已访问
    	white//白色表示未访问
    };
    
    class MGraph
    {
    private:
    	int vernum;//顶点数
    	int arcnum;//边数
    	vector<VNode> vertices;//邻接表
    
    public:
    	
    	MGraph(vector<vector<int>>);//构造函数,使用邻接矩阵进行初始化
    	void BFS(int s);//广度优先搜索
    
    	void DFS(int s);//深度优先搜索-非递归
    	void DFSRecursive();//深度优先搜索-递归
    
    	void DFSRecursive_Visit(int s);//深度优先搜索-递归-辅助函数
    	void setWhite();//将所有顶点置为白色
    };
    
  • 构造

    使用邻接矩阵来进行初始化
    MGraph::MGraph(vector<vector<int>> arr)
    {
    	vernum = arr.size();
    	vertices.resize(vernum);
    
    	for (int i = 0; i < vernum; i++)
    	{
    		vertices[i].firstarc = nullptr;
    		vertices[i].color = white;
    		vertices[i].val = i;//为便于理解,顶点值设置为i
    		for (int j = i; j < vernum; j++)
    		{
    			if (arr[i][j])
    			{
    				arcnum++;
    				//使用头插法
    				//			 → p →
    				//vertices[i]       firstarc
    				shared_ptr<ArcNode> p = make_shared<ArcNode>();
    				p->adjvex = j;
    				p->nextarc = vertices[i].firstarc;
    				vertices[i].firstarc = p;
    			}
    		}
    	}
    }
    
  • 广度优先遍历

    (这是个gif)
    在这里插入图片描述
    /*
    * 广度优先遍历
    * @param{s}:开始的顶点
    */
    void MGraph::BFS(int s)
    {
    	queue<VNode> que;//定义队列
    	vertices[s].color = black;//顶点s已访问
    
    	que.push(vertices[s]);//将顶点s入队列
    	while (!que.empty())
    	{
    		VNode temp = que.front();//取队首
    		que.pop();
    
    		cout << temp.val << endl;//输出队首顶点数据
    
    		shared_ptr<ArcNode> p = temp.firstarc;//遍历队首顶点所有边
    		while (p)
    		{
    			if (vertices[p->adjvex].color == white)//若边的另一顶点未访问
    			{
    				vertices[p->adjvex].color = black;//访问
    				que.push(vertices[p->adjvex]);//并放入队列
    			}
    			p = p->nextarc;//指向下一条边
    		}
    	}
    }
    
  • 深度优先遍历-递归

    递归的比较简单,就不画图了 (好难画啊)
    /*
    * 深度优先遍历-递归方式
    */
    void MGraph::DFSRecursive()
    {
    	for (int i = 0; i < vernum; i++)
    		if (vertices[i].color == white)
    			DFSRecursive_Visit(i);
    }
    
    /*
    * 深度优先遍历-递归方式-辅助函数
    */
    void MGraph::DFSRecursive_Visit(int s)
    {
    	vertices[s].color = black;
    	cout << vertices[s].val << endl;
    
    	shared_ptr<ArcNode> p = vertices[s].firstarc;
    	while (p)
    	{
    		if (vertices[p->adjvex].color == white)
    			DFSRecursive_Visit(p->adjvex);
    		p = p->nextarc;
    	}
    }
    
  • 深度优先遍历-非递归

    非递归遍历使用到了栈,但是与广度优先遍历时使用到的队列有一些不同,在入栈操作时仅需要将第一个未访问的节点入栈注意其中的break
    (这是个gif)
    在这里插入图片描述
    /*
    * 深度优先遍历-非递归
    * @param{s}:起始顶点
    */
    void MGraph::DFS(int s)
    {
    	for (int i = 0; i < vernum; i++)
    	{
    		if (vertices[i].color == white)
    		{
    			stack<VNode> mstack;
    
    			vertices[s].color = black;
    			mstack.push(vertices[s]);
    
    			while (!mstack.empty())
    			{
    				cout << mstack.top().val << endl;
    				VNode temp = mstack.top();
    
    				mstack.pop();
    
    				shared_ptr<ArcNode> p = temp.firstarc;
    				while (p)
    				{
    					if (vertices[p->adjvex].color == white)
    					{
    						vertices[p->adjvex].color = black;
    						mstack.push(vertices[p->adjvex]);
    						break;//这里注意要跳出循环
    					}
    					p = p->nextarc;
    				}
    			}
    		}
    	}
    }
    

Code

#include <iostream>
#include <stack>
#include <queue>
#include <memory>
#include <unordered_map>
using namespace std;

//边结构体
struct ArcNode
{
	int adjvex;//边的另一个顶点
	shared_ptr<ArcNode> nextarc;//下一条边
};

//顶点结构体
struct VNode
{
	int val;//顶点值
	int color;//颜色值,白/黑
	shared_ptr<ArcNode> firstarc;//第一条边
	//使用链表存储所有以当前顶点为起始点的边
};

//顶点颜色
enum Color
{
	black,//黑色表示已访问
	white//白色表示未访问
};

class MGraph
{
private:
	int vernum;//顶点数
	int arcnum;//边数
	vector<VNode> vertices;//邻接表

public:
	
	MGraph(vector<vector<int>>);//构造函数,使用邻接矩阵进行初始化
	void BFS(int s);//广度优先搜索

	void DFS();//深度优先搜索-非递归
	void DFSRecursive();//深度优先搜索-递归

	void DFSRecursive_Visit(int s);//深度优先搜索-递归-辅助函数
	void setWhite();//将所有顶点置为白色
};

MGraph::MGraph(vector<vector<int>> arr)
{
	vernum = arr.size();
	vertices.resize(vernum);

	for (int i = 0; i < vernum; i++)
	{
		vertices[i].firstarc = nullptr;
		vertices[i].color = white;
		vertices[i].val = i;
		for (int j = i; j < vernum; j++)
		{
			if (arr[i][j])
			{
				arcnum++;
				//使用头插法
				//			 → p →
				//vertices[i]       firstarc
				shared_ptr<ArcNode> p = make_shared<ArcNode>();
				p->adjvex = j;
				p->nextarc = vertices[i].firstarc;
				vertices[i].firstarc = p;
			}
		}
	}
}

/*
* 广度优先遍历
* @param{s}:起始顶点
*/
void MGraph::BFS(int s)
{
	queue<VNode> que;
	vertices[s].color = black;

	que.push(vertices[s]);
	while (!que.empty())
	{
		VNode temp = que.front();
		que.pop();

		cout << temp.val << endl;

		shared_ptr<ArcNode> p = temp.firstarc;
		while (p)
		{
			if (vertices[p->adjvex].color == white)
			{
				vertices[p->adjvex].color = black;
				que.push(vertices[p->adjvex]);
			}
			p = p->nextarc;
		}
	}

}

/*
* 深度优先遍历-非递归
* @param{s}:起始顶点
*/
void MGraph::DFS()
{
	for (int i = 0; i < vernum; i++)
	{
		if (vertices[i].color == white)
		{
			stack<VNode> mstack;

			vertices[i].color = black;
			mstack.push(vertices[i]);

			while (!mstack.empty())
			{
				cout << mstack.top().val << endl;
				VNode temp = mstack.top();

				mstack.pop();

				shared_ptr<ArcNode> p = temp.firstarc;
				while (p)
				{
					if (vertices[p->adjvex].color == white)
					{
						vertices[p->adjvex].color = black;
						mstack.push(vertices[p->adjvex]);
						break;
					}
					p = p->nextarc;
				}
			}
		}
	}
}

/*
* 深度优先遍历-递归方式
*/
void MGraph::DFSRecursive()
{
	for (int i = 0; i < vernum; i++)
		if (vertices[i].color == white)
			DFSRecursive_Visit(i);
}

/*
* 深度优先遍历-递归方式-辅助函数
*/
void MGraph::DFSRecursive_Visit(int s)
{
	vertices[s].color = black;
	cout << vertices[s].val << endl;

	shared_ptr<ArcNode> p = vertices[s].firstarc;
	while (p)
	{
		if (vertices[p->adjvex].color == white)
			DFSRecursive_Visit(p->adjvex);
		p = p->nextarc;
	}
}

void MGraph::setWhite()
{
	for (int i = 0; i < vernum; i++)
		vertices[i].color = white;
}

int main()
{
	vector<vector<int>> arr(5, vector<int>(5, 0));

	cout << "BFS:" << endl;
	arr[0][1] = 1; arr[0][4] = 1;
	arr[1][2] = 1; arr[1][3] = 1; arr[1][4] = 1;
	arr[2][3] = 1;
	arr[3][4] = 1;

	MGraph m(arr);

	m.BFS(0);

	cout << "DFS(测试用例不同):"<<endl;
	arr[0][1] = 1; arr[0][4] = 1;
	arr[1][2] = 1; arr[1][3] = 1; arr[1][4] = 0;
	arr[2][3] = 0;
	arr[3][4] = 1;

	m.setWhite();
	m.DFS();

	return 0;
}
  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值