算法 等价类、并查集与图

等价关系与等价类

在这里插入图片描述
在这里插入图片描述
等价集的初始状态,其数值都是-1,根据等价关系对齐数值进行修改

在这里插入图片描述

假如0 = 4,于是将 4结点的数值加至 0 结点,并将0作为4结点的新数值 ,那么此时0结点就是3结点的根
在这里插入图片描述

并查集的建立

class UFSets
{
	int* parent;
	int size;
public:
	UFSets(int sz) :size(sz)
	{
		parent = new int[size];
		for (int i = 0; i < size; ++i)
		{
			parent[i] = -1;
		}
	}
	int FindRoot(int child)
	{
		while (parent[child] >= 0)
		{
			child = parent[child];
		}
		return child;
	}
	bool Union(int cha,int chb)
	{
		bool res = false;
		int left = FindRoot(cha);
		int right = FindRoot(chb);
		if (left != right)
		{
			parent[left] += parent[right]; //合并
			parent[right] = left;
			res = true;
		}
	}
};

并查集的打印

class UFSets
{
	int* parent;
	int size;

	void Print(int v) const
	{
		cout << v << "\t";
		for (int i = 0; i < size; ++i)
		{
			if (parent[i] == v)
			{
				Print(i);
			}
		}
	}
public:
	UFSets(int sz) :size(sz)
	{
		parent = new int[size];
		for (int i = 0; i < size; ++i)
		{
 			parent[i] = -1;
		}
	}
	int FindRoot(int child)
	{
		while (parent[child] >= 0)
		{
			child = parent[child];
		}
		return child;
	}
	bool Union(int cha,int chb)
	{
		bool res = false;
		int left = FindRoot(cha);
		int right = FindRoot(chb);
		if (left != right)
		{
			parent[left] += parent[right]; //合并
			parent[right] = left;
			res = true;
		}
		return res;
	}
	void Print() const
	{
		int s = 1;
		for (int i = 0; i < size; ++i)
		{
			if (parent[i] < 0) //是根
			{
				cout << "集合:" <<s<< endl;
				Print(i);
				cout << endl;
				s++;
			}
		}

	}
};
int main()
{
	UFSets set(12);

	set.Union(0, 4);
	set.Union(3, 1);
	set.Union(6, 10);
	set.Union(8, 9);
	set.Union(7, 4);
	set.Union(6, 8);
	set.Union(3, 5);
	set.Union(2, 11);
	set.Union(11, 0);

	set.Print();
	return 0;
}

图的基本概念

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

图的存储表示

邻接矩阵表视图
在这里插入图片描述
根据 0 号结点与其他结点的邻接关系,填写临界表
在这里插入图片描述

图的建立

template<class NameType,class DistType>
class Graph
{
private:
	vector<NameType> verlist;      //邻接表
	vector<vector<DistType>> Edges //边集
	int vernum;
	int edgenum;
public:
	Graph():vernum(0),edgenum(0){}
	void InitGraph()
	{
		NameType ch;
		int v, u;
		DistType d;
		cout << "请输入顶点个数: ";
		cin >> vernum;
		cout << "请输入顶点信息: ";
		for (int i = 0; i < vernum; ++i)
		{
			cin >> ch;
			verlist.push_back(ch);
		}
		Edges.resize(vernum);
		for (int i = 0; i < vernum; ++i)
		{
			Edges[i].resize(vernum, INT_MAX);
		}
		for (int i = 0; i < vernum; ++i) Edges[i][i] = 0;
		cout << "请输入边的个数: ";
		cin >> edgenum;
		for (int i = 0; i < edgenum; ++i)
		{
			cout << "请输入边: ";
			cin >> v >> u >> d;

			Edges[v][u] = d;
			Edges[u][v] = d;
		}
	}
	void PrintGraph() const
	{
		cout << endl;
		cout << "顶点信息: ";
		for (auto& x : verlist)
		{
			cout << x << " \t";
		}
		cout << endl;
		cout << "邻接矩阵: " << endl;
		for (int i = 0; i < vernum; ++i)
		{
			for (int j = 0; j < vernum; ++j)
			{
				if (Edges[i][j] == INT_MAX)
				{
					cout << "$: " << "\t";
				}
				else
				{
					cout << Edges[i][j] << " \t";
				}
			}
			cout << endl;
		}
		cout << endl;
	}
		
};
int main()
{
	Graph<char, int> myt;
	myt.InitGraph();
	myt.PrintGraph();
	return 0;
}

在这里插入图片描述
在这里插入图片描述

深度优先遍历

在这里插入图片描述

深度优先遍历,从1号顶点出发遍历邻接顶点B,再从B出发,遍历CFHI,然后进行回溯去遍历没有遍历过的顶点

当邻接矩阵固定后,其遍历结果就会固定,从0出发,去寻找邻接结点第一个 为1,那么跳转到从1出发,去寻找第一个邻接结点为2,跳转到2出发,接着跳转到5出发,发现遍历结束则回退到2接着遍历,发现2也遍历完成则回退至1继续遍历
在这里插入图片描述

void DFS(int v, vector<bool>& visited)
{
	visited[v] = true;
	cout << verlist[v] << " "; 
	for (int i = 0; i < vernum; ++i)
	{
		if (!visited[i] && Edges[v][i] == 1)
		{
			DFS(i, visited);
		}
	}  
}
void DFS(int v)
{
	vector<bool> visited(vernum, false);
	DFS(v, visited);
}

广度优先遍历

将某个结点入队列,并将与该顶点相邻的所有顶点全部入队列

void BFS(int v)
{
	vector<bool> visited(vernum, false);
	queue<int> 	qu;	
	qu.push(v);
	visited[v] = true; //被访问过
	while (!qu.empty())
	{
		cout << verlist[v] << " ";
		for (int i = 0; i < vernum; ++i)
		{
		//是邻接结点并且未被访问过
		if (!visited[i] && Edges[v][i] == 1)
			{
				qu.push(i);
				visited[i] = true;
			}
		}
	}
}

最小生成树问题(克鲁斯卡尔算法)

在这里插入图片描述
将图中所有边取出,放入一个列表中,并且按照边的权值进行排列,接着从列表中按次序,每次取出一条边回帖至图中,并且没回贴一次就要判断一次图的状态,是否成环;没有生产环则该边被选中,否则该边被丢弃选择下一条边;直到选择了n-1(n代表顶点数)条边,则最小生成树完成

#include<iostream>
#include<thread>
#include<type_traits>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;

class UFSets
{
	int* parent;
	int size;

	void Print(int v) const
	{
		cout << v << "\t";
		for (int i = 0; i < size; ++i)
		{
			if (parent[i] == v)
			{
				Print(i);
			}
		}
	}
public:
	UFSets(int sz) :size(sz)
	{
		parent = new int[size];
		for (int i = 0; i < size; ++i)
		{
			parent[i] = -1;
		}
	}
	int FindRoot(int child)
	{
		while (parent[child] >= 0)
		{
			child = parent[child];
		}
		return child;
	}
	bool Union(int cha, int chb)
	{
		bool res = false;
		int left = FindRoot(cha);
		int right = FindRoot(chb);
		if (left != right)
		{
			parent[left] += parent[right];
			parent[right] = left;
			res = true;
		}
		return res;		
	}
	void Print() const
	{
		int s = 1;
		for (int i = 0; i < size; ++i)
		{
			if (parent[i] < 0) // root 
			{
				cout << "闆嗗悎: " << s++<< endl;
				Print(i);
				cout << endl;
			}
		}
	}
};
template<class DistType>
struct 	MinSpanTree
{
	int head, tail;			//鐢熸垚鏍戝悇杈圭殑涓ら《鐐?
	DistType cost;	           //鐢熸垚鏍戝悇杈圭殑浠d环

	operator DistType() const
	{
		return cost;
	}
};
template<class NameType, class DistType>
class Graph
{
private:
	vector<NameType> verlist;
	vector<vector<DistType> > Edges;
	int vernum;
	int edgenum;
public:
	Graph() :vernum(0), edgenum(0) {}
	~Graph() {}
	void InitGraph()
	{
		NameType ch;
		int v, u;
		DistType d;
		cout << "璇疯緭鍏ラ《鐐逛釜鏁?: ";
		cin >> vernum;
		cout << "璇疯緭鍏ラ《鐐逛俊鎭?: ";
		for (int i = 0; i < vernum; ++i)
		{
			cin >> ch;
			verlist.push_back(ch);
		}
		Edges.resize(vernum);
		for (int i = 0; i < vernum; ++i)
		{
			Edges[i].resize(vernum, INT_MAX);
		}
		for (int i = 0; i < vernum; ++i) Edges[i][i] = 0;
		cout << "璇疯緭鍏ヨ竟鐨勪釜鏁?: ";
		cin >> edgenum;
		for (int i = 0; i < edgenum; ++i)
		{
			cout << "璇疯緭鍏ヨ竟: ";
			cin >> v >> u >> d;

			Edges[v][u] = d;
			Edges[u][v] = d;
		}
	}
	void PrintGraph() const
	{
		cout << endl;
		cout << "椤剁偣淇℃伅: ";
		for (auto& x : verlist)
		{
			cout << x << " \t";
		}
		cout << endl;
		cout << "閭绘帴鐭╅樀: " << endl;
		for (int i = 0; i < vernum; ++i)
		{
			for (int j = 0; j < vernum; ++j)
			{
				if (Edges[i][j] == INT_MAX)
				{
					cout << "$: " << "\t";
				}
				else
				{
					cout << Edges[i][j] << " \t";
				}
			}
			cout << endl;
		}
		cout << endl;
	}
	void DFS(int v, vector<bool>& visited)
	{
		visited[v] = true;
		cout << verlist[v] << " ";
		for (int i = 0; i < vernum; ++i)
		{
			if (!visited[i] && Edges[v][i] == 1)
			{
				DFS(i, visited);
			}
		}  // 
	}
	void DFS(int v)
	{
		vector<bool> visited(vernum, false);
		DFS(v, visited);
	}
	void BFS(int v)
	{
		vector<bool> visited(vernum, false);
		queue<int> 	qu;
		qu.push(v);
		visited[v] = true;
		while (!qu.empty())
		{
			cout << verlist[v] << " ";
			for (int i = 0; i < vernum; ++i)
			{
				if (!visited[i] && Edges[v][i] == 1)
				{
					qu.push(i);
					visited[i] = true;
				}
			}
		}
	}
	void Kruskal(vector<MinSpanTree<int> > & mst)
	{
		UFSets set(vernum);	 //
		std::priority_queue< MinSpanTree<int>,
			vector<MinSpanTree<int> >,
			greater< MinSpanTree<int> > > pq;
		for (int i = 1; i < vernum; ++i)
		{
			for (int j = 0; j < i; ++j)
			{
				if (Edges[i][j] != INT_MAX)
				{
					MinSpanTree<int> e = { i,j,Edges[i][j] };
					pq.push(e);
				}
			}
		}
		int i = 0;
		while (i < vernum - 1)
		{
			MinSpanTree<int> e = pq.top();	pq.pop();
			if (set.Union(e.head, e.tail))
			{
				mst.push_back(e);
				++i;
			}
		}
	}
};
int main()
{
	Graph<char, int> myt;
	vector<MinSpanTree<int> > mst;

	myt.InitGraph();
	myt.PrintGraph();
	myt.Kruskal(mst);
	
	for (auto& x : mst)
	{
		cout << x.head << " -> " << x.tail << " : " << x.cost << endl;
	}

	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值