数据结构与算法——图及图的搜索算法(C++)

文章目录

  • 图的实现
    • 1. Graph类
    • 2 graphMatrix类

图的实现

1. Graph类

Graph类定义图的基本信息(边与顶点)的相关内容,以及广度优先算法与深度优先算法等。

#pragma once

#include 
#include  // INT_MAX
#include "../dsa_queue_20200717/queue.h"
#include "../dsa_stack_20200716/stack.h"

namespace dtl 
{

// 顶点状态
enum class VertexStatus {
	// 未发现
	undiscovered,
	// 已发现
	discovered,
	// 已访问
	visited,
};

// 边状态
enum class EdgeStatus {
	// 未处置
	undetermined,
	// 树边
	tree,
	// 跨边
	cross,
	// 前向边
	forward,
	// 后向边
	backward,
};

// class of GRAPH
template <typename Tv, typename Te>
class Graph
{
private:
	// 所有顶点、边的辅助信息复位
	void reset() {
		for (int i = 0; i < n; i++) {
			status(i) = VertexStatus::undiscovered;
			dTime(i) = fTime(i) = -1;
			parent(i) = -1;
			priority(i) = INT_MAX;
			for (int j = 0; j < n; j++) {
				if (exists(i, j))
					type(i, j) = EdgeStatus::undetermined;
			}
		}
	}

	// breadth first search
	void BFS(int v, int& clock) {
#if DSA_MODE
		printf("BFS in with v=%d, clock=%d\n", v, clock); 
#endif

		Queue<int> queue;
		status(v) = VertexStatus::discovered;
		queue.enqueue(v);

#if DSA_MODE
		printf("vetex v=%d", v); print(vertex(v)); printf(" status changed to VertexStatus::discovered\n");
		printf("current Q: "); print(queue);
#endif

		while (!queue.empty()) {
			int v = queue.dequeue();
			dTime(v) = ++clock;

#if DSA_MODE
			printf("visiting vertex v=%d", v); print(vertex(v)); printf("["); print(status(v)); printf("] dTime=%d\n", clock);
#endif

			for (int u = firstNbr(v); -1 < u; u = nextNbr(v, u)) {

#if DSA_MODE
				printf("visiting vertex u=%d", u); print(vertex(u)); printf("["); print(status(u)); printf("]\n");
#endif

				if (status(u) == VertexStatus::undiscovered) {
					status(u) = VertexStatus::discovered;
					queue.enqueue(u);
					type(v, u) = EdgeStatus::tree;
					parent(u) = v;
				} else {
					type(v, u) = EdgeStatus::cross;
				}

#if DSA_MODE
				printf("edge(%d, %d) ", v, u); print(vertex(v)); printf(" ->"); print(vertex(u)); printf(" now is "); print(type(v, u)); printf("\n");
#endif

			}
			status(v) = VertexStatus::visited;

#if DSA_MODE
			printf("vetex v=%d", v); print(vertex(v)); printf(" status changed to VertexStatus::visited\n");
			printf("current Q: "); print(queue);
#endif
		}
	}

	//! depth first search
	void DFS(int v, int& clock) {
#if DSA_MODE
		printf("DFS in with v=%d, clock=%d\n", v, clock);
#endif

		dTime(v) = ++clock;
		status(v) = VertexStatus::discovered;

#if DSA_MODE
		printf("vetex v=%d", v); print(vertex(v)); printf(" status changed to VertexStatus::discovered dTime=%d\n", clock);
#endif

		for (int u = firstNbr(v); -1 < u; u = nextNbr(v, u)) {

#if DSA_MODE
			printf("visiting vertex u=%d", u); print(vertex(u)); printf("["); print(status(u)); printf("]\n");
#endif

			switch (status(u)) {
				case VertexStatus::undiscovered:
					type(v, u) = EdgeStatus::tree;
					parent(u) = v;
					DFS(u, clock);
					break;
				case VertexStatus::discovered:
					type(v, u) = EdgeStatus::backward;
					break;
				default: // VertexStatus::visited
					type(v, u) = dTime(v) < dTime(u) ? EdgeStatus::forward : EdgeStatus::cross;
					break;
			}

#if DSA_MODE
			printf("edge(%d, %d) ", v, u); print(vertex(v)); printf(" ->"); print(vertex(u)); printf(" now is "); print(type(v, u)); printf("\n");
#endif
		}

		status(v) = VertexStatus::visited;
		fTime(v) = ++clock;

#if DSA_MODE
		printf("vetex v=%d", v); print(vertex(v)); printf(" status changed to VertexStatus::visited fTime=%d\n", clock);
#endif
	}

	//! topological sort
	bool TSORT(int v, int& clock, Stack<Tv>* s) {
		assert(0 <= v && v < n);

#if DSA_MODE
		printf("TSORT in with v=%d, clock=%d\n", v, clock);
		printf("statck="); print(s);
#endif
		
		dTime(v) = ++clock;
		status(v) = VertexStatus::discovered;

#if DSA_MODE
		printf("vetex v=%d", v); print(vertex(v)); printf(" status changed to VertexStatus::discovered dTime=%d\n", clock);
#endif

		for (int u = firstNbr(v); -1 < u; u = nextNbr(v, u)) {

#if DSA_MODE
			printf("visiting vertex u=%d", u); print(vertex(u)); printf("["); print(status(u)); printf("]\n");
#endif

			switch (status(u)) {
				case VertexStatus::undiscovered:
					parent(u) = v;
					type(v, u) = EdgeStatus::tree; 

#if DSA_MODE
					printf("edge(%d, %d) ", v, u); print(vertex(v)); printf(" ->"); print(vertex(u)); printf(" now is "); print(type(v, u)); printf("\n");
#endif

					if (!TSORT(u, clock, s)) {
						return false;
					}
					break;
				case VertexStatus::discovered:
					type(v, u) = EdgeStatus::backward;
#if DSA_MODE
					printf("edge(%d, %d) ", v, u); print(vertex(v)); printf(" ->"); print(vertex(u)); printf(" now is "); print(type(v, u)); printf("\n");
#endif

					return false;
					break;
				default: // visited
					type(v, u) = (dTime(v) < dTime(u)) ? EdgeStatus::forward : EdgeStatus::cross;
#if DSA_MODE
					printf("edge(%d, %d) ", v, u); print(vertex(v)); printf(" ->"); print(vertex(u)); printf(" now is "); print(type(v, u)); printf("\n");
#endif

					break;
			}


		}

		status(v) = VertexStatus::visited;
		s->push(vertex(v));

#if DSA_MODE
		printf("vetex v=%d", v); print(vertex(v)); printf(" status changed to VertexStatus::visited\n");
#endif

		return true;
	}

public:
	//! 顶点总数
	int n;
	//! 插入顶点,返回编号
	virtual int insert(Tv const& v) = 0;
	//! 删除顶点及其关联边,返回该顶点
	virtual Tv remove(int v) = 0;
	//! 顶点数据(该顶点的确存在)
	virtual Tv& vertex(int v) = 0;
	//! 顶点的入度(该顶点的确存在)
	virtual int inDegree(int v) = 0;
	//! 顶点的出度(该顶点的确存在)
	virtual int outDegree(int v) = 0;
	//! 顶点的首个邻接顶点
	virtual int firstNbr(int v) = 0;
	//! 顶点v的(相对于顶点j的)下一个邻接顶点
	virtual int nextNbr(int v, int j) = 0;
	//! 顶点状态
	virtual VertexStatus& status(int v) = 0;
	//! 顶点 discovered time
	virtual int& dTime(int v) = 0;
	//! 顶点 finished time
	virtual int& fTime(int v) = 0;
	//! 顶点在遍历树中的父亲
	virtual int& parent(int v) = 0;
	//! 顶点在遍历树中的优先级
	virtual int& priority(int v) = 0;

	//! 边总数
	int e;
	//! 边(v,u)是否存在
	virtual bool exists(int v, int u) = 0;
	//! 在顶点v、u之间插入权重为w的边e
	virtual void insert(Te const& e, int w, int v , int u) = 0;
	//! 的喊出顶点v、u之间的边e,返回该边信息
	virtual Te remove(int v, int u) = 0;
	//! 边(v,u)的数据(该边的确存在)
	virtual EdgeStatus& type(int v, int u) = 0;
	//! 边(v,u)的权重
	virtual int& weight(int v, int u) = 0;

	//********* algorithms *********************//

	//! 广度优先搜索
	void bfs(int s) {
		reset();
		int clock = 0;
		int v = s;
		do {
			if (VertexStatus::undiscovered == status(v)) {
				BFS(v, clock);
			}
		} while (s != (v = (++v % n)));
	}

	//! 深度优先搜索
	void dfs(int s) {
		reset();
		int clock = 0;
		int v = s;
		do {
			if (VertexStatus::undiscovered == status(v)) {
				DFS(v, clock);
			}
		} while (s != (v = (++v % n)));
	}

	//! 基于DFS的拓扑排序算法
	Stack<Tv>* tsort(int s) {
		assert(0 <= s && s < n);
		reset();
		int clock = 0, v = s;
		auto S = new Stack<Tv>();
		do {
			if (status(v) == VertexStatus::undiscovered) {
				if (!TSORT(v, clock, S)) {
					S->clear();
					break;
				}
			}
		} while (s != (v = (++v % n)));
		return S;
	}
};

}

2 graphMatrix类

graphMatrisx类是图的实现方法之一——邻接矩阵的类。这个类主要致力于实现图这个数据结构。

#pragma once

#include "graph.h"
#include "../dsa_vector_200622/dsa_vector.h"
#include 

namespace dtl 
{

//! 顶点
template <typename T>
struct Vertex
{
	T data;
	int inDegree;//入度
	int outDegree;//出度
	VertexStatus status;//定点状态: 未发现undiscovered// 已发现discovered,// 已访问visited
	//! discovered time
	int dTime;
	//! finished visit time
	int fTime;
	int parent;
	int priority;//优先级

	Vertex(T const& data = T(0))
		: data(data)
		, inDegree(0)
		, outDegree(0)
		, status(VertexStatus::undiscovered)
		, dTime(-1)
		, fTime(-1)
		, parent(-1)
		, priority(INT_MAX)
	{}
};

//! 边
template <typename T>
struct Edge
{
	T data;//数据
	int weight;//权重
	EdgeStatus status;//状态

	Edge(T const& data, int weight)
		: data(data)
		, weight(weight)
		, status(EdgeStatus::undetermined)
	{}
};

//邻接矩阵
template <typename Tv, typename Te>
class GraphMatrix : public Graph<Tv, Te>
{
private:
	//! vertexes
	Vector<Vertex<Tv>> V;//顶点
	//! edges
	Vector<Vector<Edge<Te>*>> E;//边

public:
	typedef Graph<Tv, Te> GraphType;

	GraphMatrix() {
		GraphType::n = GraphType::e = 0;
	}

	~GraphMatrix() {
		for (int j = 0; j < GraphType::n; j++) {
			for (int k = 0; k < GraphType::n; k++) {
				delete E[j][k];
			}
		}
	}

	// vertex basic opration
	virtual Tv& vertex(int i) { return V[i].data; }
	virtual int inDegree(int i) { return V[i].inDegree; }
	virtual int outDegree(int i) { return V[i].outDegree; }
	virtual VertexStatus& status(int i) { return V[i].status; }
	virtual int& dTime(int i) { return V[i].dTime; }
	virtual int& fTime(int i) { return V[i].fTime; }
	virtual int& parent(int i) { return V[i].parent; }
	virtual int& priority(int i) { return V[i].priority; }

	virtual int firstNbr(int i) { return nextNbr(i, GraphType::n); }
	virtual int nextNbr(int i, int j) {
		while ((-1 < j) && (!exists(i, --j))) {}
		return j;
	}

	// vertex dynamic operation
	virtual int insert(Tv const& vertex) {
		for (int j = 0; j < GraphType::n; j++) {
			E[j].insert(nullptr);
		}
		GraphType::n++;
		E.insert(Vector<Edge<Te>*>(GraphType::n, GraphType::n, (Edge<Te>*)nullptr));
		return V.insert(Vertex<Tv>(vertex));
	}

	virtual Tv remove(int i) {
		assert(0 <= i && i < GraphType::n);
		for (int j = 0; j < GraphType::n; j++) {
			if (exists(i, j)) {
				delete E[i][j];
				V[j].inDegree--;
			}
		}
		E.remove(i);
		GraphType::n--;
		Tv vBak = vertex(i);
		V.remove(i);
		for (int j = 0; j < GraphType::n; j++) {
			if (Edge<Te>* e = E[j].remove(i)) {
				delete e;
				V[j].outDegree--;
			}
		}
		return vBak;
	}

	// edge operation
	virtual bool exists(int i, int j) {
		return (0 <= i) && (i < GraphType::n) && (0 <= j) && (j < GraphType::n) && E[i][j] != nullptr;
	}

	virtual EdgeStatus& type(int i, int j) { assert(exists(i, j)); return E[i][j]->status; }
	virtual Te& edge(int i, int j) { assert(exists(i, j)); return E[i][j]->data; }
	virtual int& weight(int i, int j) { assert(exists(i, j)); return E[i][j]->weight; }

	virtual void insert(Te const& edge, int weight, int i, int j) {
		if (exists(i, j)) { return; }
		E[i][j] = new Edge<Te>(edge, weight);
		GraphType::e++;
		V[i].outDegree++;
		V[j].inDegree++;
	}

	virtual Te remove(int i, int j) {
		assert(exists(i, j));
		Te eBak = edge(i, j);
		delete E[i][j];
		E[i][j] = nullptr;
		GraphType::e--;
		V[i].outDegree--;
		V[j].inDegree--;
		return eBak;
	}
};

}

你可能感兴趣的:(数据结构及实现)