【数据结构】大连理工大学软件学院20年

最小生成树

#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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值