最小生成树
#include<iostream>
#include <stdlib.h>
#define INF 1000000
using namespace std;
//MinHeap
template <class T>
class MinHeap {
private:
T* heapArray;
int CurrentSize; /* 当前堆元素个数 */
int MaxSize; /* 堆中能存放的最大元素个数 */
public:
MinHeap(T* array, int num, int max)
{
this->heapArray = array;
this->CurrentSize = num;
this->MaxSize = max;
}
MinHeap(int num)
{
this->MaxSize=num;
this->CurrentSize=0;
heapArray=new T[num];
}
virtual ~MinHeap() {};
bool isLeaf(int pos) const;
int leftchild(int pos) const;
int rightchild(int pos) const;
int parent(int pos) const;
void BuildHeap(); /* 2.4-a 最大堆构建 */
void SiftDown(int left); /* 2.4-b SiftDown函数从left向下调整堆,使序列成为堆 */
void SiftUp(int pos); /* 2.4-c SiftUp函数从position向上调整堆,使序列成为堆 */
bool Remove(int pos, T& node); /* 2.4-d 删除给定下标的元素 */
bool Insert(const T& newNode); /* 2.4-e 从堆中插入新元素newNode */
T& RemoveMin(); /* 2.4-f 从堆顶删除最大值 */
void visit();
};
/*
* TODO:2.4-a 最大堆构建
*/
template <class T>
void MinHeap<T>::BuildHeap()
{
for (int i = CurrentSize/2 - 1;i >= 0;i--) {
SiftDown(i);
}
}
template <class T>
bool MinHeap<T>::isLeaf(int pos) const
{
if (pos >= CurrentSize) {
cout << "越界" << endl;
return (false);
}
else if (pos > (CurrentSize - 1) / 2)
return (true);
else
return (false);
}
template <class T>
int MinHeap<T>::leftchild(int pos) const
{
return (2 * pos + 1);
}
template <class T>
int MinHeap<T>::rightchild(int pos) const
{
return (2 * pos + 2);
}
template <class T>
int MinHeap<T>::parent(int pos) const
{
return ((pos - 1) / 2);
}
/*
* TODO:2.4-d 删除给定下标的元素,并将该元素的值赋值给node变量。
* 返回值说明:如果删除成功,则返回true,否则返回false
* 重要说明:如果当前堆为空,则输出打印cout << "空堆" << endl;并返回false
*/
template <class T>
bool MinHeap<T>::Remove(int pos, T& node)
{
if (CurrentSize == 0) {
cout << "空栈" << endl;
return false;
}
int i = pos;
node = heapArray[pos];
heapArray[i] = heapArray[CurrentSize - 1];
CurrentSize--;
SiftDown(i);
SiftUp(i);
return true;
}
/*
* TODO:2.4 - b SiftDown函数从left向下调整堆,使序列成为堆
*/
template <class T>
void MinHeap<T>::SiftDown(int left)
{
int i = left;
int j = 2 * i + 1;
T temp = heapArray[i];
while (j < CurrentSize) {
if ((j < CurrentSize - 1) && (heapArray[j] > heapArray[j + 1]))
j++;
if (temp > heapArray[j]) {
heapArray[i] = heapArray[j];
i = j;
j = 2 * j + 1;
}
else break;
}
heapArray[i] = temp;
}
/*
* TODO:2.4-c SiftUp函数从pos向上调整堆,使序列成为堆
*/
template <class T>
void MinHeap<T>::SiftUp(int pos)
{
int i = pos;
int j = (i - 1) / 2;
T temp = heapArray[i];
while (j >= 0 && i >= 1) {
if (heapArray[i] < heapArray[j]) {
heapArray[i] = heapArray[j];
i = j;
j = (j - 1) / 2;
}
else break;
}
heapArray[i] = temp;
}
/*
* TODO:2.4-e 从堆中插入新元素newNode, 如果插入成功,返回true,否则返回false。
* 重要说明:如果堆中元素超过堆中元素最大个数值,则输出打印cout << "堆满" << endl;并返回false
*/
template <class T>
bool MinHeap<T>::Insert(const T& newNode)
{
if (CurrentSize == MaxSize) {
cout << "堆满" << endl;
return false;
}
else {
CurrentSize++;
heapArray[CurrentSize - 1] = newNode;
BuildHeap();
}
}
template <class T>
void MinHeap<T>::visit()
{
for (int i = 0; i < CurrentSize; i++)
cout << heapArray[i] << " ";
cout << endl;
}
/*
* TODO:2.4-f 从堆顶删除最大值. 如果堆栈为空堆,则输出打印cout << "空堆" << endl;然后退出程序,退出码为1.
* 否则,从堆顶删除最大值,并将其作为返回值进行返回。
*/
template <class T>
T& MinHeap<T>::RemoveMin()
{
if (CurrentSize == 0){
cout << "空栈" << endl;
exit(1);
}
else {
T temp = heapArray[0];
heapArray[0] = heapArray[CurrentSize - 1];
CurrentSize--;
if (CurrentSize > 1)
SiftDown(0);
return temp;
}
}
//template<class EdgeType>
class Edge {
public:
int start;
int end;
int weight;
Edge(int s = 0, int e = 0, int w = 0) {
start = s;end = e;weight = w;
}
bool operator >(Edge oneEdge) {
return weight > oneEdge.weight;
}
bool operator <(Edge oneEdge) {
return weight < oneEdge.weight;
}
};
class Graph {
public:
int vNum;
int eNum;
int* Mark;
Graph(int vnum) {
vNum = vnum;
eNum = 0;
Mark = new int[vNum];
for (int i = 0;i < vNum;i++) {
Mark[i] = 0;
}
}
~Graph() {
delete[] Mark;
}
virtual Edge firstEdge(int oneVertex) = 0;
virtual Edge nextEdge(Edge oneEdge) = 0;
bool IsEdge(Edge oneEdge) {
if (oneEdge.weight > 0 && oneEdge.weight < INF && oneEdge.end >= 0)
return true;
else
return false;
}
int StartVertex(Edge oneEdge) {
return oneEdge.start;
}
int EndVertex(Edge oneEdge) {
return oneEdge.end;
}
int weight(Edge oneEdge) {
return oneEdge.weight;
}
virtual void setEdge(int start, int end, int weight) = 0;
virtual void delEdge(int start, int end) = 0;
};
//template<class EdgeType>
class AdjGraph :public Graph {
private:
int** matrix;
public:
AdjGraph(int vnum) :Graph(vnum) {
matrix = (int**)new int* [vnum];
for (int i = 0;i < vnum;i++) {
matrix[i] = new int(vnum);
}
for (int i = 0;i < vnum;i++) {
for (int j = 0;j < vnum;j++) {
matrix[i][j] = 0;
}
}
}
~AdjGraph() {
for (int i = 0;i < vNum;i++) {
delete[] matrix[i];
}
delete[]matrix;
}
Edge firstEdge(int oneVertex) {//查找以 oneVertex为起点的第一条边
Edge temp;
for (int i = 0;i < vNum;i++) {
if (matrix[oneVertex][i] != 0 && matrix[oneVertex][i] != INF) {
temp.weight = matrix[oneVertex][i];
temp.end = i;
break;
}
}
temp.start = oneVertex;
return temp;
}
Edge nextEdge(Edge oneEdge) {//返回与oneEdge共始点的下一条边
Edge temp;
int start = oneEdge.start, end = oneEdge.end;
temp.start = start;
for (int i = end + 1;i < vNum;i++) {
if (matrix[start][i] != 0 && matrix[start][i] != INF) {
temp.weight = matrix[start][i];
temp.end = i;
break;
}
}
return temp;
}
void setEdge(int start, int end, int weight) {
if (matrix[start][end] == 0) {
eNum++;
}
matrix[start][end] = weight;
}
void delEdge(int start, int end) {
if (matrix[start][end] != 0) {
matrix[start][end] = 0;
eNum--;
}
}
};
class UFsets{
private:
int n;//等价类中 等价元的个数
int *root;//root[i]表示元素i所在的等价类的代表元素编号
int *next;//next[i]表示在等价类中,i的后面元素编号
int *length;//length[i]表示i所代表的 等价类的元素个数
public:
UFsets(int size){
n = size;//初始size个元素的等价类
root = new int[n];
next = new int[n];
length = new int[n];
for (int i = 0; i < n; i++){
root[i] = next[i] = i;//各个元素独自成一个等价类
length[i] = 1;
}
}
int Find(int v){
if (v < n){
return root[v];
}//返回等价类中的代表元素编号
else
{//边界检查
cout << "参数不合法" << endl;
}
}
void Union(int v, int u);//合并v和u所在的等价类,将元素少的合并到元素多的里面去
};
void UFsets::Union(int v, int u){
if (root[u] == root[v]){
//如果两个在同一个等价类中,就返回
return;
}
else if (length[root[v]] <= length[root[u]]){
//如果u的长度比v的长度长,那么就把v合到u里面去
int rt = root[v];//记录rt值
length[root[u]] = length[root[u]] + length[root[v]];//修改u所在的等价类的元素的个数
root[rt] = root[u];//下面来修改v所在的等价类里面的元素的代表元素
for (int j = next[rt]; j != rt; j = next[j]){
root[j] = root[u];
}
//下面交换两个代表元素 rt,root[u] 的next值
int temp;
temp = next[rt];
next[rt] = next[root[u]];
next[root[u]] = temp;
}
else if (length[root[v]] > length[root[u]]){
//相反的一样
int rt = root[u];
length[root[v]] = length[root[v]] + length[root[u]];
root[rt] = root[v];
for (int k = next[rt]; k != rt; k = next[k]){
root[k] = root[v];
}
//swap
int temp;
temp = next[rt];
next[rt] = next[root[v]];
next[root[v]] = temp;
}
}
//template<class EdgeType>
Edge* Kruskal(AdjGraph& G){//最小生成树的Kruskal算法
//求含有n个顶点、e条边的连通图G的最小生成树 返回边的集合
int n = G.vNum;//记录顶点数目
UFsets sets(n);//定义n个结点的等价类
Edge *MST = new Edge[n - 1];//要返回的最小生成树的边
MinHeap<Edge> MinH(G.eNum);//定义含有e个元素的最小堆,用于寻找权值最小的边
Edge edge;
for (int i = 0; i < n; i++){
for (edge = G.firstEdge(i); G.IsEdge(edge); edge = G.nextEdge(edge)){
if (G.StartVertex(edge) < G.EndVertex(edge)){
//限制起始点的编号大小顺序,防止无向图中的边被重复加入
MinH.Insert(edge);
}
}
}
int edgeNum = 0;//生成边的个数
while (edgeNum < n - 1){//n个结点的连通图的生成树有n-1条边
//if (!MinH.isEmpty()){
//如果堆不空
edge = MinH.RemoveMin();//找到权重最小的未处理的边
int v = edge.start;
int u = edge.end;
if (sets.Find(v) != sets.Find(u)){
//判断该边关联的顶点是否在一个连通分量
sets.Union(v, u);//合并两个顶点所在的等价类
MST[edgeNum] = edge;//将符合条件的边添加到生成树的边集合中
edgeNum++;
}
/*}
else
{
assert("不存在最小生成树.");
return nullptr;
}*/
}
return MST;
}
int main(){
AdjGraph g(6);
g.setEdge(0,1,6);
g.setEdge(1,0,6);
g.setEdge(0,2,1);
g.setEdge(2,0,1);
g.setEdge(0,3,5);
g.setEdge(0,5,5);
g.setEdge(1,2,5);
g.setEdge(2,1,5);
g.setEdge(2,3,5);
g.setEdge(3,2,5);
g.setEdge(1,4,3);
g.setEdge(4,1,3);
g.setEdge(2,4,6);
g.setEdge(4,2,6);
g.setEdge(4,5,6);
g.setEdge(5,4,6);
g.setEdge(2,5,4);
g.setEdge(5,2,4);
g.setEdge(3,5,2);
g.setEdge(5,3,2);
Edge* q=Kruskal(g);
cout<<"kruskal:"<<endl;
for(int i=0;i<g.vNum-1;i++){
cout<<"("<<q[i].start<<","<<q[i].end<<","<<q[i].weight<<")"<<endl;
}
delete []q;
return 0;
}
图的遍历
/*3.3 图的遍历
a. 深度优先搜索(DFS):递归及非递归
递归 void DFSTraverse() void DFS1(int v)
非递归 void DFSNoReverse()
b. 广度优先搜索(BFS)
void BFSTraverse() void BFS1(int v)
*/
#include <iostream>
#include <queue>//这个是队列的库
#include <stack>//这个是栈的库
typedef enum {UNVISITED,VISITED}VISITORNOT;
using namespace std;//命名空间
template <class T>
class Edge {
public:
int start, end, weight;//始点,终点,权重
Edge()//空构造函数,全设0
{
start = 0;
end = 0;
weight = 0;
}
Edge(int st, int en, int w)//三有构造函数
{
start = st;
end = en;
weight = w;
}
void showEdge()//展示边的呗
{
cout << "start: " << start << " end:" << end << " weight:" << weight << endl;
}
};
template <class T>//模板啦
class Graph {//图结构啦
public:
int vertexNum; //图的顶点数目
int edgeNum; //图的边数目
int* Mark;
Graph()
{
vertexNum = 0;
edgeNum = 0;
Mark = NULL;
}
Graph(int verticesNum)//构造函数
{
vertexNum = verticesNum;
edgeNum = 0;
Mark = new int[vertexNum];
for (int i = 0; i < vertexNum; i++)
Mark[i] = 0;
}
~Graph()//析构函数
{
delete[] Mark;
}
virtual Edge<T> FirstEdge(int oneVertex) = 0;//返回第一条边啦,给顶点
virtual Edge<T> NextEdge(Edge<T> oneEdge) = 0;//给第一条边,返回下一条边
int VerticesNum() { return vertexNum; }//返回顶点数
int EdgesNum() { return edgeNum; }//返回边的数量
int StartVertex(Edge<T> oneEdge) { return oneEdge.start; }//给一条边,返回始点
int EndVertex(Edge<T> oneEdge) { return oneEdge.end; }//给一条边,返回终点
int Weight(Edge<T> oneEdge) { return oneEdge.weight; }//给一条边,返回权重
virtual void setEdge(int start, int end, int weight) = 0;//设置边,给起点终点权重
virtual void delEdge(int start, int end) = 0;
};
template <class T>
class AdjGraph : public Graph<T> {
private:
int** matrix;//矩阵指针
public:
AdjGraph(int verticesNum)//构造函数,给顶点数
{
int i, j;
this->vertexNum = verticesNum;
this->edgeNum = 0;
this->Mark = new int[verticesNum];
for (int i = 0; i < verticesNum; i++)//初始化
this->Mark[i] = 0;
matrix = (int**)new int* [this->vertexNum];//矩阵初始化
for (i = 0; i < this->vertexNum; i++)
matrix[i] = new int[this->vertexNum];
for (i = 0; i < this->vertexNum; i++)
for (j = 0; j < this->vertexNum; j++)
matrix[i][j] = 0;
}
~AdjGraph()//析构函数
{
for (int i = 0; i < this->vertexNum; i++)
delete[] matrix[i];
delete[] matrix;
}
bool isEdge(Edge<T> oneEdge)//判断是不是一条边,这个函数好啊,可以用啊,输入一条边,
{
if (oneEdge.weight > 0 && oneEdge.end >= 0)
return true;
else
return false;
}
Edge<T> FirstEdge(int oneVertex)//第一条边,给顶点
{
Edge<T> tempEdge;
tempEdge.start = oneVertex;
for (int i = 0; i < this->vertexNum; i++) {
if (matrix[oneVertex][i] != 0) {
tempEdge.end = i;
tempEdge.weight = matrix[oneVertex][i];
break;
}
}
return tempEdge;
}
Edge<T> NextEdge(Edge<T> oneEdge)//下一条边,给边
{
Edge<T> tempEdge;
tempEdge.start = oneEdge.start;
for (int i = oneEdge.end + 1; i < this->vertexNum; i++) {
if (matrix[oneEdge.start][i] != 0) {
tempEdge.end = i;
tempEdge.weight = matrix[oneEdge.start][i];
break;
}
}
return tempEdge;
}
void setEdge(int start, int end, int weight)
{
if (start < this->vertexNum && end < this->vertexNum && weight >= 0) {
if (matrix[start][end] == 0) {
this->edgeNum++;
}
matrix[start][end] = weight;
}
else
cout << "非法输入" << endl;
}
void delEdge(int start, int end)
{
if (start < this->vertexNum && end < this->vertexNum) {
if (matrix[start][end] != 0)
this->edgeNum--;
matrix[start][end] = 0;
}
else
cout << "非法输入" << endl;
}
void DFS1(int v)
{
this->Mark[v] = 1; //标记该顶点已访问
cout << v + 1 << " "; //访问该顶点:顶点0设为1
for (Edge<T> e = FirstEdge(v); isEdge(e); e = NextEdge(e)) { //由该点所关联的边进行深度优先搜索
if (this->Mark[e.end] == 0) //访问V邻接到的未被访问过的顶点,并递归地进行深度优先搜索
DFS1(e.end);
}
}
/*
TODO:a 深度优先搜索(DFS):递归,对所有顶点的标志位初始化,检查图是否有未访问的顶点,
如果有则从该顶点开始深度优先搜索,对未访问的顶点调用DFS1
*/
void DFSTraverse()
{
for (int i = 0; i < this->VerticesNum(); i++)//初始化
{
this->Mark[i] = UNVISITED;//这是什么牛逼操作,搞得这么炫酷,没有什么屌用,把地址里面的东西设置成了这个玩意,设置0它不香吗????
}
for (int i = 0; i < this->VerticesNum(); i++)
{
if (this->Mark[i] == UNVISITED)
{
DFS1(i);
}
}
}
/*
TODO:a 深度优先搜索(DFS):非递归.对所有顶点的标志位初始化
检查图是否有未访问的顶点,如果有则从该顶点开始深度优先搜索。
当遇到未访问的顶点时,需要输出打印cout << u + 1 << " "; 。比如当this->Mark[i] == 0;且要
处理它时,则通过打印语句cout << i + 1 << " ";将其位置打印出来。 具体可参考测试用例。
*/
void DFSNoReverse()//这是非递归吧
{
int i, v, u;
stack<int> s;//不大明白??????哪儿来的栈??????这不是有包吗,怎么还用ArrayStack
for (i = 0; i < this->VerticesNum(); i++)
{
this->Mark[i] = UNVISITED;
}
for (i = 0; i < this->VerticesNum(); i++)
{
if (this->Mark[i] == UNVISITED)
{
s.push(i);
cout << i + 1 << " ";//哪来的visit
this->Mark[i] = VISITED;//谜之操作
while (!s.empty())//我明白了,这特么库函数自带的栈类吧!!!!!
{
v = s.top();//出个栈,人家没有返回值,算了,用top吧
s.pop();
for (Edge<T> e = FirstEdge(v); isEdge(e); e = NextEdge(e))//遍历边
{
u = this->EndVertex(e);//u是终点
if (this->Mark[u] == UNVISITED)//没访问才干,但是还能重?????
{
s.push(u);
cout << u + 1 << " ";
this->Mark[u] = VISITED;
}
}
}
}
}
}
/*
TODO:BFS1算法,访问顶点V,并将其标志位置为已访问,访问该顶点: 打印cout << v + 1 << " ";
访问其它未被访问的顶点时,也打印cout << u + 1 << " ";其中,u是被访问的顶点
*/
void BFS1(int v)
{
queue<int> Q;
this->Mark[v] = VISITED;//标记该顶点已访问
cout << v + 1 << " "; //访问该顶点:顶点0设为1
Q.push(v);
while (!Q.empty())
{
int i = Q.front();
Q.pop();
for (Edge<T> e = FirstEdge(i); isEdge(e); e = NextEdge(e))//遍历
{
int u = this->EndVertex(e);
if (this->Mark[u] == UNVISITED)
{
cout << u + 1 << " ";
this->Mark[u] = VISITED;
Q.push(u);
}
}
}
}
/*
TODO:b. 广度优先搜索(BFS),对所有顶点的标志位初始化.
检查图中是否有未访问的顶点,如果有则从该顶点开始调用BFS1进行广度优先搜索
*/
void BFSTraverse()
{
int v;
for (v = 0; v < this->VerticesNum(); v++)//遍历
{
this->Mark[v] = UNVISITED;
}
for (v = 0; v < this->VerticesNum(); v++)//遍历
{
if (this->Mark[v] == UNVISITED)
{
BFS1(v);
}
}
}
void showGraph()
{
cout << "图有" << this->edgeNum << "条边" << endl;
cout << "图的信息为:" << endl;
for (int i = 0; i < this->vertexNum; i++) {
for (int j = 0; j < this->vertexNum; j++)
cout << matrix[i][j] << " ";
cout << endl;
}
}
};
int main()
{
Edge<int> tempEdge;
int count, start, end, weight;
cin >> count;
AdjGraph<int> adp(count); //count为图的顶点数目
adp.setEdge(1, 0, 2); //1,0,2 其中1为边的起点,0为边的终点,2为边的权重。
adp.setEdge(0, 2, 1);
adp.setEdge(0, 3, 3);
adp.setEdge(3, 2, 1);
adp.setEdge(3, 4, 1);
adp.showGraph();
cout << "深度优先搜索: ";
adp.DFSTraverse();
cout << endl;
cout << "广度优先搜索: ";
adp.BFSTraverse();
cout << endl;
return 0;
}