北邮22信通:第五章 邻接矩阵图的深度优先遍历和广度优先遍历

北邮22信通一枚~   

跟随课程进度每周更新数据结构与算法的代码和文章 

持续关注作者  解锁更多邮苑信通专属代码~

获取更多文章  请访问专栏:

北邮22信通_青山如墨雨如画的博客-CSDN博客

目录

一.邻接矩阵图和邻接表图的对比

二.存储结构——邻接矩阵的讲解

三.深度优先遍历DFS

3.1书上重要语句提取

3.2一个修饰

3.3 DFS完整代码

四.广度优先遍历BFS

4.1广度优先遍历注意事项

4.2广度优先遍历代码部分

五.总体代码 

5.1代码效果图

5.2代码部分

 5.3运行结果

5.4复习 用顺序表描写队列的总体代码 


 一.邻接矩阵图和邻接表图的对比

        邻接矩阵图因为存储结构简单,因此实现深度优先遍历和广度优先遍历时要比邻接表图书写起来更加容易;但是邻接矩阵正是因为存储结构简单容易录入,反而占用了很大内存空间。如果图是单向图且结点多且弧的数量少,那么存储这个图数据的矩阵就是一个稀疏矩阵。如果采用三元组表或者其他存储结构优化稀疏矩阵的存储空间,那么邻接矩阵图整体的存储结构就会很复杂,还不如邻接表图。

        综上所述,使用邻接矩阵作为存储结构的优点是:1.录入数据简单;2.实现算法简单;适应邻接矩阵作为存储结构的缺点是:占用内存空间大,只对特定的图才不会过于浪费存储空间。在节省存储空间这一方面,没有很好的普适性。

二.存储结构——邻接矩阵的讲解

        同邻接表图一样,我们需要将一个图的所有信息数字化。除了邻接表这种存储方式外,我们还可以使用邻接矩阵。首先需要一个一维数组(vertex)储存所有结点,之后还需要一个二维数组(arc)储存结点和结点之间的连通情况(如果是带权图就储存权值)

        这个二维数组存储的元素个数是这个一维数组长度的平方倍,显然,二维数组每个角度的分坐标(横纵坐标),任一行(列)分别都应该代表从第一个结点到最后一个结点的下标,示意图如下。本篇文章用于测试的图:书169页图5-25(a),画出的辅助存储结构同时如下。

北邮22信通:第五章 邻接矩阵图的深度优先遍历和广度优先遍历_第1张图片

北邮22信通:第五章 邻接矩阵图的深度优先遍历和广度优先遍历_第2张图片

北邮22信通:第五章 邻接矩阵图的深度优先遍历和广度优先遍历_第3张图片

三.深度优先遍历DFS

3.1书上重要语句提取

        “为避免重复访问同一个顶点,必须记住每个顶点是否已经被访问过,所以,图的遍历算法必须添加一个布尔向量bool visited[n],初始值为FALSE,一旦访问了顶点vi,则visited[ i - 1 ]设置为TRUE。”

        “深度优先遍历类似于树的前序遍历。”

3.2一个修饰

        书上代码固然可以实现深度优先遍历,但是遍历一次之后数组visited各个元素都将被标记,无法进行第二次深度遍历。所以在这里小编添加了一个return0函数,方便将各个visited数组全部返回FALSE值。

template
void m_graph::return0(bool x[])
{
	for (int i = 0; i < maxsize; i++)
		x[i] = 0;
}

使用完DFS方法后引用此函数,就可以实现visited数组的格式化了。

3.3 DFS完整代码

DFS完整代码如下:

template
void m_graph::return0(bool x[])
{
	for (int i = 0; i < maxsize; i++)
		x[i] = 0;
}

bool visited[maxsize];

template
void m_graph::DFS_core(int v)
{
	this->vertex[v].print();
	visited[v] = 1;
	for (int i = 0; i < vnum; i++)
		if (arc[v][i] == 1 && visited[i] == 0)
			DFS_core(i);
}

template
void m_graph::DFS(int v)
{
	cout << "从" << v + 1 << "开始,广度优先遍历结果为:" << endl;
	DFS_core(v);
	return0(visited);
	cout << endl;
}

四.广度优先遍历BFS

4.1广度优先遍历注意事项

同样需要visited数组来记录是否标记过;

应用了队列思想,每一个元素出队,与这个元素直接相邻的元素依次入队,直至队空为止;

广度优先遍历类似于树的层序遍历

复习:队列也可以用之前学过的顺序表来描写。在总体代码部分会给出。

4.2广度优先遍历代码部分

template
void m_graph::BFS_core(int v)
{
	queueq;
	this->vertex[v].print();
	visited[v] = 1;
	q.push(v);
	while (!q.empty())
	{
		v = q.front();
		q.pop();
		for (int i = 0; i < vnum; i++)
			if (this->arc[v][i] == 1 && visited[i] == 0)
			{
				this->vertex[i].print();
				visited[i] = 1;
				q.push(i);
			}
	}
}

template
void m_graph::BFS(int v)
{
	cout << "从" << v + 1 << "开始,广度优先遍历结果为:" << endl;
	BFS_core(v);
	return0(visited);
	cout << endl;
}

五.总体代码 

5.1代码效果图

北邮22信通:第五章 邻接矩阵图的深度优先遍历和广度优先遍历_第4张图片

5.2代码部分

#include
#include
#include
using namespace std;

class student
{
private:
	int ID;
	string name;
public:
	student()
	{
		this->ID = 0;
		this->name = "un_known name";
	}
	student(int ID, string name)
	{
		this->ID = ID;
		this->name = name;
	}
	void print()
	{
		cout << "ID:" << this->ID << "  name:" << this->name << endl;
	}
	friend fstream& operator>>(fstream& fin, student& s)
	{
		fin >> s.ID;
		fin >> s.name;
		return fin;
	}
};

const int maxsize = 10;
template
class m_graph
{
private:
	temp vertex[maxsize];
	int arc[maxsize][maxsize];
	int vnum, arcnum;
public:
	m_graph(ifstream& fin);
	m_graph(temp a[], int arc[][maxsize], int vnum, int arcnum);
	void return0(bool x[]);
	void DFS_core(int v);
	void DFS(int v);
	void BFS_core(int v);
	void BFS(int v);
};

template
m_graph::m_graph(ifstream& fin)
{
	fin >> this->vnum;
	fin >> this->arcnum;
	for (int i = 0; i < vnum; i++)
		fin >> this->vertex[i];
	for (int i = 0; i < this->vnum; i++)
		for (int j = 0; j < this->vnum; j++)
			fin >> this->arc[i][j];
}

template
m_graph::m_graph(temp a[], int arc[][maxsize], int vnum, int arcnum)
{
	this->vnum = vnum;
	this->arcnum = arcnum;
	for (int i = 0; i < this->vnum; i++)
		this->vertex[i] = a[i];
	for (int i = 0; i < this->vnum; i++)
		for (int j = 0; j < this->vnum; j++)
			this->arc[i][j] = arc[i][j];
}

template
void m_graph::return0(bool x[])
{
	for (int i = 0; i < maxsize; i++)
		x[i] = 0;
}

bool visited[maxsize];

template
void m_graph::DFS_core(int v)
{
	this->vertex[v].print();
	visited[v] = 1;
	for (int i = 0; i < vnum; i++)
		if (arc[v][i] == 1 && visited[i] == 0)
			DFS_core(i);
}

template
void m_graph::DFS(int v)
{
	cout << "从" << v + 1 << "开始,广度优先遍历结果为:" << endl;
	DFS_core(v);
	return0(visited);
	cout << endl;
}

template
void m_graph::BFS_core(int v)
{
	queueq;
	this->vertex[v].print();
	visited[v] = 1;
	q.push(v);
	while (!q.empty())
	{
		v = q.front();
		q.pop();
		for (int i = 0; i < vnum; i++)
			if (this->arc[v][i] == 1 && visited[i] == 0)
			{
				this->vertex[i].print();
				visited[i] = 1;
				q.push(i);
			}
	}
}

template
void m_graph::BFS(int v)
{
	cout << "从" << v + 1 << "开始,广度优先遍历结果为:" << endl;
	BFS_core(v);
	return0(visited);
	cout << endl;
}

student stu[6] =
{
	{1001,"zhang"},{2002,"wang"},{3003,"li"},
	{4004,"zhao"},{5005,"liu"},{6006,"yao"}
};
int arc[maxsize][maxsize] =
{
	{0,1,1,0,0,1},
	{1,0,1,0,1,0},
	{1,1,0,1,0,0},
	{0,0,1,0,0,0},
	{0,1,0,0,0,0},
	{1,0,0,0,0,0},
};

int main()
{
	system("color 0A");
	m_graphmm(stu, arc, 6, 12);
	mm.DFS(0);
	mm.BFS(0);
	return 0;
}

 5.3运行结果

北邮22信通:第五章 邻接矩阵图的深度优先遍历和广度优先遍历_第5张图片

5.4复习 用顺序表描写队列的总体代码 

#include
#include
using namespace std;

class student
{
private:
	int ID;
	string name;
public:
	student()
	{
		this->ID = 0;
		this->name = "un_known name";
	}
	student(int ID, string name)
	{
		this->ID = ID;
		this->name = name;
	}
	void print()
	{
		cout << "ID:" << this->ID << "  name:" << this->name << endl;
	}
	friend fstream& operator>>(fstream& fin, student& s)
	{
		fin >> s.ID;
		fin >> s.name;
		return fin;
	}
};

//队列
template
struct node
{
	temp data;
	node* next;
};

template 
class linkqueue
{
private:
	node* front;
	node* rear;
public:
	linkqueue();
	~linkqueue();
	void enqueue(temp x);
	temp dequeue();
	temp getfront();
	int getlength();
	bool empty()
	{
		return (this->front == this->rear) ? true : false;
	}
};

template
linkqueue::linkqueue()
{
	this->front = this->rear = new node ;
	this->front->next = NULL;
}

template
void linkqueue::enqueue(temp x)
{
	this->rear->next = new node;
	this->rear = this->rear->next;
	this->rear->data = x;
	this->rear->next = NULL;
}

template
temp linkqueue::dequeue()
{
	node* p = this->front->next;
	if (!p)throw"underflow";/*如果为空队列,抛出异常*/
	this->front->next = p->next;
	temp x = p->data;
	delete p;
	if (!(this->front->next))
		this->rear = this->front;
	return x;
}

template
temp linkqueue::getfront()
{
	if (!this->front->next)throw"overflow";
	return this->front->next->data;
}

template
linkqueue::~linkqueue()
{
	while (this->front != NULL)
	{
		this->rear = this->front->next;
		delete this->front;
		this->front = this->rear;
	}
}

template
int linkqueue::getlength()
{
	node* p = this->front;
	int cnt = 0;
	while (p != this->rear)
	{
		cnt++;
		p = p->next;
	}
	return cnt;
}

//图论

const int maxsize = 10;
template
class m_graph
{
private:
	temp vertex[maxsize];
	int arc[maxsize][maxsize];
	int vnum, arcnum;
public:
	m_graph(ifstream& fin);
	m_graph(temp a[], int arc[][maxsize], int vnum, int arcnum);
	void return0(bool x[]);
	void DFS_core(int v);
	void DFS(int v);
	void BFS_core(int v);
	void BFS(int v);
};

template
m_graph::m_graph(ifstream& fin)
{
	fin >> this->vnum;
	fin >> this->arcnum;
	for (int i = 0; i < vnum; i++)
		fin >> this->vertex[i];
	for (int i = 0; i < this->vnum; i++)
		for (int j = 0; j < this->vnum; j++)
			fin >> this->arc[i][j];
}

template
m_graph::m_graph(temp a[], int arc[][maxsize], int vnum, int arcnum)
{
	this->vnum = vnum;
	this->arcnum = arcnum;
	for (int i = 0; i < this->vnum; i++)
		this->vertex[i] = a[i];
	for (int i = 0; i < this->vnum; i++)
		for (int j = 0; j < this->vnum; j++)
			this->arc[i][j] = arc[i][j];
}

template
void m_graph::return0(bool x[])
{
	for (int i = 0; i < maxsize; i++)
		x[i] = 0;
}

bool visited[maxsize];

template
void m_graph::DFS_core(int v)
{
	this->vertex[v].print();
	visited[v] = 1;
	for (int i = 0; i < vnum; i++)
		if (arc[v][i] == 1 && visited[i] == 0)
			DFS_core(i);
}

template
void m_graph::DFS(int v)
{
	cout << "从" << v + 1 << "开始,广度优先遍历结果为:" << endl;
	DFS_core(v);
	return0(visited);
	cout << endl;
}

template
void m_graph::BFS_core(int v)
{
	linkqueueq;
	this->vertex[v].print();
	visited[v] = 1;
	q.enqueue(v);
	while (!q.empty())
	{
		v = q.getfront();
		q.dequeue();
		for (int i = 0; i < vnum; i++)
			if (this->arc[v][i] == 1 && visited[i] == 0)
			{
				this->vertex[i].print();
				visited[i] = 1;
				q.enqueue(i);
			}
	}
}

template
void m_graph::BFS(int v)
{
	cout << "从" << v + 1 << "开始,广度优先遍历结果为:" << endl;
	BFS_core(v);
	return0(visited);
	cout << endl;
}

student stu[6] =
{
	{1001,"zhang"},{2002,"wang"},{3003,"li"},
	{4004,"zhao"},{5005,"liu"},{6006,"yao"}
};
int arc[maxsize][maxsize] =
{
	{0,1,1,0,0,1},
	{1,0,1,0,1,0},
	{1,1,0,1,0,0},
	{0,0,1,0,0,0},
	{0,1,0,0,0,0},
	{1,0,0,0,0,0},
};

int main()
{
	system("color 0A");
	m_graphmm(stu, arc, 6, 12);
	mm.DFS(0);
	mm.BFS(0);
	return 0;
}

 

你可能感兴趣的:(北邮22信通——数据结构,深度优先,宽度优先,算法)