数据结构探险——图篇(代码实现)

imooc相关学习视频.

1、什么是图?

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

2、图的存储结构、遍历方式及最小生成树算法原理

2.1 图的存储结构

在这里插入图片描述

2.1.1 邻接矩阵

是由数组进行存储。
在这里插入图片描述
顶点索引是不能重复的。
有向图的邻接矩阵表示方法:
在这里插入图片描述
无向图的邻接矩阵表示方法:
在这里插入图片描述
邻接矩阵在代码中如何表示(表示成数组):
在这里插入图片描述
结点和图的结构体表示:
在这里插入图片描述

2.1.2 邻接表–链式存储

下面是邻接表的相关表示方式:
在这里插入图片描述
在这里插入图片描述
逆邻接表:
逆邻接表是相对邻接表来说的,邻接表记录的是出弧的链表头指针,而逆邻接表记录的入弧的链表头指针。

顶点的表示方法:

顶点索引入弧链表头指针顶点数据

弧的表示方法:

弧尾顶点索引下一条弧指针弧数据

存储方法如何通过数据结构的代码来表示:
在这里插入图片描述

2.1.3 十字链表–链式存储

在这里插入图片描述
如何通过结构体进行存储:
在这里插入图片描述

2.1.4 邻接多重表–链式存储

在这里插入图片描述
用结构体进行表示如下:
在这里插入图片描述

2.2 图的遍历

在这里插入图片描述
在这里插入图片描述
如上图中图来说,
进行深度优先搜索顺序为:A B C E F D G H
进行广度优先搜索顺序为:A B D C F G H E

2.3 最小生成树

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

2.3.1 普里姆算法

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

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

2.3.2 克鲁斯卡尔算法算法

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

3、图的编码实战

3.1 图的深度优先遍历和图的广度优先遍历

         A
      /      \
     B        D
   /   \     /  \
   C    F    G - H
    \  / 
     E
深度优先遍历搜索:A B C E F D D H
广度优先遍历搜索:A B D C F G H E



  A B C D E F G H 
A   1   1
B 1   1     1
C   1     1 1
D 1           1 1 
E     1     1
F   1     1
G       1       1
H       1     1

Node.h–>定义结点相关功能接口和元素的头文件(存入的数据都是char类型)

#ifndef NODE_H_
#define NODE_H_

class Node
{
public:
	Node(char data = 0);
	char m_cData;
	bool m_bIsVisited;
};

#endif /* NODE_H_ */

Node.cpp–>实现结点相关功能代码

#include "Node.h"

Node::Node(char data)
{
	m_cData = data;
	m_bIsVisited = false;
}

CMap.h–>定义图相关功能接口和元素的头文件(存入的数据都是Node结点类型)

#ifndef CMAP_H_
#define CMAP_H_

#include <vector>
#include "Node.h"
using namespace std;

class CMap
{
public:
	CMap(int capacity);
	~CMap();
	bool addNode(Node *pNode);   //向图中加入顶点(结点)
	void resetNode();            // 重置顶点
	bool setValueToMatrixForDirectedGraph(int row, int col, int val = 1);   //为有向图设置邻接矩阵
	bool setValueToMatrixForUndirectedGraph(int row, int col, int val = 1);  // 为无向图设置零件矩阵
	void printMatrix();   //打印邻接矩阵
	void depthFirstTraverse(int nodeIndex);    //深度优先遍历
	void breathFirstTraverse(int nodeIndex);   //广度优先遍历

private:
	bool getValueFromMatrix(int row, int col, int &val); //从矩阵中获取权值
	void breathFirstTraverseImpl(vector<int> preVec);    // 广度优先遍历实现函数

private:
	int m_iCapacity;    //图中最多可以容纳的顶点数
	int m_iNodeCount;   //已经添加的顶点(结点)个数
	Node *m_pNodeArray; //用来存放顶点数组
	int *m_pMatrix;     //用来存放邻接矩阵
};

#endif /* CMAP_H_ */

CMap.cpp–>实现图的相关功能代码

#include <iostream>
#include <vector>
#include <string.h>
#include "CMap.h"
using namespace std;

CMap::CMap(int capacity)
{
	m_iCapacity = capacity;
	m_iNodeCount = 0;
	m_pNodeArray = new Node[m_iCapacity];
	m_pMatrix = new int[m_iCapacity * m_iCapacity];
	memset(m_pMatrix, 0, m_iCapacity * m_iCapacity * sizeof(int));
	/*for (int i = 0; i < m_iCapacity * m_iCapacity; i++) {
		m_pMatrix[i] = 0;
	}*/
}

CMap::~CMap()
{
	delete[] m_pNodeArray;
	delete[] m_pMatrix;
}

bool CMap::addNode(Node *pNode)
{
	if (pNode == NULL) {
		return false;
	}
	m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData;
	m_iNodeCount++;
	return true;
}

void CMap::resetNode()
{
	for(int i = 0; i < m_iNodeCount; i++) {
		m_pNodeArray[i].m_bIsVisited = false;
	}
}


bool CMap::setValueToMatrixForDirectedGraph(int row, int col, int val)
{
	if (row < 0 || row >= m_iCapacity) {
		return false;
	}
	if (col < 0 || col >= m_iCapacity) {
		return false;
	}
	m_pMatrix[row * m_iCapacity + col] = val;
	return true;
}

bool CMap::setValueToMatrixForUndirectedGraph(int row, int col, int val)
{
	if (row < 0 || row >= m_iCapacity) {
		return false;
	}
	if (col < 0 || col >= m_iCapacity) {
		return false;
	}
	m_pMatrix[row * m_iCapacity + col] = val;
	m_pMatrix[col * m_iCapacity + row] = val;
	return true;
}

bool CMap::getValueFromMatrix(int row, int col, int &val)
{
	if (row < 0 || row >= m_iCapacity) {
		return false;
	}
	if (col < 0 || col >= m_iCapacity) {
		return false;
	}
	val = m_pMatrix[row * m_iCapacity + col];
	return true;
}

void CMap::printMatrix()
{
	for (int i = 0; i < m_iCapacity; i++) {
		for (int k = 0; k < m_iCapacity; k++) {
			cout << m_pMatrix[i * m_iCapacity + k] << " ";
		}
		cout << endl;
	}
}

//深度优先遍历
void CMap::depthFirstTraverse(int nodeIndex)
{
	int value = 0;
	cout << m_pNodeArray[nodeIndex].m_cData << " ";
	m_pNodeArray[nodeIndex].m_bIsVisited = true;

	for (int i = 0; i < m_iCapacity; i++) {
		getValueFromMatrix(nodeIndex, i, value);
		if (value == 1) {
			if (m_pNodeArray[i].m_bIsVisited) {
				continue;
			} else {
				depthFirstTraverse(i);
			}
		} else {
			continue;
		}
	}
}

//广度优先遍历
void CMap::breathFirstTraverse(int nodeIndex)
{
	cout << m_pNodeArray[nodeIndex].m_cData << " ";
	m_pNodeArray[nodeIndex].m_bIsVisited = true;
	vector<int> curVec;
	curVec.push_back(nodeIndex);

	breathFirstTraverseImpl(curVec);
}

void CMap::breathFirstTraverseImpl(vector<int> preVec)
{
	int value = 0;
	vector<int> curVec;

	for (int j = 0; j < (int)preVec.size(); j++) {
		for (int i = 0; i < m_iCapacity; i++) {
			getValueFromMatrix(preVec[j], i, value);
			if (value != 0) {
				if (m_pNodeArray[i].m_bIsVisited) {
					continue;
				} else {
					cout << m_pNodeArray[i].m_cData << " ";
					m_pNodeArray[i].m_bIsVisited = true;

					curVec.push_back(i);
				}
			}
		}
	}
	if (0 == curVec.size()) {
		return;
	} else {
		breathFirstTraverseImpl(curVec);
	}
}

MapDemo.cpp–>测试入口代码文件

/*
图的形式:
         A
      /      \
     B        D
   /   \     /  \
   C    F    G - H
    \  / 
     E

*/

#include <iostream>
#include "CMap.h"

using namespace std;

int main() {
	CMap *pMap = new CMap(8);

	Node *pNodeA = new Node('A');
	Node *pNodeB = new Node('B');
	Node *pNodeC = new Node('C');
	Node *pNodeD = new Node('D');
	Node *pNodeE = new Node('E');
	Node *pNodeF = new Node('F');
	Node *pNodeG = new Node('G');
	Node *pNodeH = new Node('H');

	pMap->addNode(pNodeA);
	pMap->addNode(pNodeB);
	pMap->addNode(pNodeC);
	pMap->addNode(pNodeD);
	pMap->addNode(pNodeE);
	pMap->addNode(pNodeF);
	pMap->addNode(pNodeG);
	pMap->addNode(pNodeH);

	pMap->setValueToMatrixForUndirectedGraph(0, 1);
	pMap->setValueToMatrixForUndirectedGraph(0, 3);
	pMap->setValueToMatrixForUndirectedGraph(1, 2);
	pMap->setValueToMatrixForUndirectedGraph(1, 5);
	pMap->setValueToMatrixForUndirectedGraph(3, 6);
	pMap->setValueToMatrixForUndirectedGraph(3, 7);
	pMap->setValueToMatrixForUndirectedGraph(6, 7);
	pMap->setValueToMatrixForUndirectedGraph(2, 4);
	pMap->setValueToMatrixForUndirectedGraph(4, 5);

	pMap->printMatrix();

	pMap->depthFirstTraverse(0);

	cout << endl;
	pMap->resetNode();
	pMap->breathFirstTraverse(0);

	delete pMap;
	pMap = NULL;

	return 0;
}

测试结果为:

图的矩阵:
0 1 0 1 0 0 0 0 
1 0 1 0 0 1 0 0 
0 1 0 0 1 0 0 0 
1 0 0 0 0 0 1 1 
0 0 1 0 0 1 0 0 
0 1 0 0 1 0 0 0 
0 0 0 1 0 0 0 1 
0 0 0 1 0 0 1 0 
深度优先遍历顺序:
A B C E F D G H 
广度优先遍历顺序:
A B D C F G H E 

3.2 图的最小生成树算法(普利姆算法和克鲁斯卡尔算法)

3.2.1最小生成树之普利姆算法代码实现

/*

     A
 /   |   \
B -- F -- E
 \  / \  /
  C --- D
  
  A  B  C  D  E  F
  0  1  2  3  4  5

A-B 6 A-E 5 A-F 1
B-C 3 B-F 2
C-F 8 C-D 2
D-F 4 D-E 2
E-F 9

*/

Edge.h–>定义边的相关元素的头文件(存入的数据都是int类型)

#ifndef EDGE_H_
#define EDGE_H_

class Edge
{
public:
	Edge(int nodeIndexA = 0, int nodeIndex = 0, int weightValue = 0);
	int m_iNodeIndexA;
	int m_iNodeIndexB;
	int m_iWeightValue;
	bool m_bSelected;
};

#endif /* EDGE_H_ */

Edge.cpp–>实现边的相关功能代码

#include "Edge.h"
Edge::Edge(int nodeIndexA, int nodeIndexB, int weightValue)
{
	m_iNodeIndexA = nodeIndexA;
	m_iNodeIndexB = nodeIndexB;
	m_iWeightValue = weightValue;
	m_bSelected = false;
}

Node.h–>定义结点相关功能接口和元素的头文件(存入的数据都是char类型)

#ifndef NODE_H_
#define NODE_H_

class Node
{
public:
	Node(char data = 0);
	char m_cData;
	bool m_bIsVisited;
};

#endif /* NODE_H_ */

Node.cpp–>实现结点相关功能代码

#include "Node.h"

Node::Node(char data)
{
	m_cData = data;
	m_bIsVisited = false;
}

CMap.h–>修改后定义图相关功能接口和元素的头文件(存入的数据包含Node结点和Edge边的类型)

#ifndef CMAP_H_
#define CMAP_H_

#include <vector>
#include "Node.h"
#include "Edge.h"
using namespace std;

class CMap
{
public:
	CMap(int capacity);
	~CMap();
	bool addNode(Node *pNode);   //向图中加入顶点(结点)
	void resetNode();            // 重置顶点
	bool setValueToMatrixForDirectedGraph(int row, int col, int val = 1);   //为有向图设置邻接矩阵
	bool setValueToMatrixForUndirectedGraph(int row, int col, int val = 1);  // 为无向图设置零件矩阵
	void printMatrix();   //打印邻接矩阵
	void depthFirstTraverse(int nodeIndex);    //深度优先遍历
	void breathFirstTraverse(int nodeIndex);   //广度优先遍历

	void primTree(int nodeIndex);  //普利姆生成树

private:
	bool getValueFromMatrix(int row, int col, int &val); //从矩阵中获取权值
	void breathFirstTraverseImpl(vector<int> preVec);    // 广度优先遍历实现函数

	int getMinEdge(vector<Edge> edgeVec);  // 获取最小的边

private:
	int m_iCapacity;    //图中最多可以容纳的顶点数
	int m_iNodeCount;   //已经添加的顶点(结点)个数
	Node *m_pNodeArray; //用来存放顶点数组
	int *m_pMatrix;     //用来存放邻接矩阵

	Edge *m_pEdge;

};

#endif /* CMAP_H_ */

CMap.cpp–>修改后实现图的相关功能代码

#include <iostream>
#include <vector>
#include <string.h>
#include "CMap.h"
using namespace std;

CMap::CMap(int capacity)
{
	m_iCapacity = capacity;
	m_iNodeCount = 0;
	m_pNodeArray = new Node[m_iCapacity];
	m_pMatrix = new int[m_iCapacity * m_iCapacity];
	memset(m_pMatrix, 0, m_iCapacity * m_iCapacity * sizeof(int));
	/*for (int i = 0; i < m_iCapacity * m_iCapacity; i++) {
		m_pMatrix[i] = 0;
	}*/
	m_pEdge = new Edge[m_iCapacity - 1];
}

CMap::~CMap()
{
	delete[] m_pNodeArray;
	delete[] m_pMatrix;
}

bool CMap::addNode(Node *pNode)
{
	if (pNode == NULL) {
		return false;
	}
	m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData;
	m_iNodeCount++;
	return true;
}

void CMap::resetNode()
{
	for(int i = 0; i < m_iNodeCount; i++) {
		m_pNodeArray[i].m_bIsVisited = false;
	}
}


bool CMap::setValueToMatrixForDirectedGraph(int row, int col, int val)
{
	if (row < 0 || row >= m_iCapacity) {
		return false;
	}
	if (col < 0 || col >= m_iCapacity) {
		return false;
	}
	m_pMatrix[row * m_iCapacity + col] = val;
	return true;
}

bool CMap::setValueToMatrixForUndirectedGraph(int row, int col, int val)
{
	if (row < 0 || row >= m_iCapacity) {
		return false;
	}
	if (col < 0 || col >= m_iCapacity) {
		return false;
	}
	m_pMatrix[row * m_iCapacity + col] = val;
	m_pMatrix[col * m_iCapacity + row] = val;
	return true;
}

bool CMap::getValueFromMatrix(int row, int col, int &val)
{
	if (row < 0 || row >= m_iCapacity) {
		return false;
	}
	if (col < 0 || col >= m_iCapacity) {
		return false;
	}
	val = m_pMatrix[row * m_iCapacity + col];
	return true;
}

void CMap::printMatrix()
{
	for (int i = 0; i < m_iCapacity; i++) {
		for (int k = 0; k < m_iCapacity; k++) {
			cout << m_pMatrix[i * m_iCapacity + k] << " ";
		}
		cout << endl;
	}
}

//深度优先遍历
void CMap::depthFirstTraverse(int nodeIndex)
{
	int value = 0;
	cout << m_pNodeArray[nodeIndex].m_cData << " ";
	m_pNodeArray[nodeIndex].m_bIsVisited = true;

	for (int i = 0; i < m_iCapacity; i++) {
		getValueFromMatrix(nodeIndex, i, value);
		if (value == 1) {
			if (m_pNodeArray[i].m_bIsVisited) {
				continue;
			} else {
				depthFirstTraverse(i);
			}
		} else {
			continue;
		}
	}
}

//广度优先遍历
void CMap::breathFirstTraverse(int nodeIndex)
{
	cout << m_pNodeArray[nodeIndex].m_cData << " ";
	m_pNodeArray[nodeIndex].m_bIsVisited = true;
	vector<int> curVec;
	curVec.push_back(nodeIndex);

	breathFirstTraverseImpl(curVec);
}

void CMap::breathFirstTraverseImpl(vector<int> preVec)
{
	int value = 0;
	vector<int> curVec;

	for (int j = 0; j < (int)preVec.size(); j++) {
		for (int i = 0; i < m_iCapacity; i++) {
			getValueFromMatrix(preVec[j], i, value);
			if (value != 0) {
				if (m_pNodeArray[i].m_bIsVisited) {
					continue;
				} else {
					cout << m_pNodeArray[i].m_cData << " ";
					m_pNodeArray[i].m_bIsVisited = true;

					curVec.push_back(i);
				}
			}
		}
	}
	if (0 == curVec.size()) {
		return;
	} else {
		breathFirstTraverseImpl(curVec);
	}
}

// 普利姆生成树
void CMap::primTree(int nodeIndex)
{
	int value = 0;
	int edgeCount = 0;     // 边的数量
	vector<int> nodeVec;   // 点的集合
	vector<Edge> edgeVec;  // 最小边的集合

	cout << m_pNodeArray[nodeIndex].m_cData << endl;

	nodeVec.push_back(nodeIndex);
	m_pNodeArray[nodeIndex].m_bIsVisited = true;

	while (edgeCount < m_iCapacity - 1) {
		int temp = nodeVec.back();
		for (int i = 0; i < m_iCapacity; i++) {
			getValueFromMatrix(temp, i, value);
			if (value != 0) {
				if (m_pNodeArray[i].m_bIsVisited) {
					continue;
				} else {
					Edge edge(temp, i, value);
					edgeVec.push_back(edge);
				}
			}
		}

		// 从可选边集合中找到最小的边
		int edgeIndex = getMinEdge(edgeVec);
		edgeVec[edgeIndex].m_bSelected = true;

		cout << edgeVec[edgeIndex].m_iNodeIndexA << "----" << edgeVec[edgeIndex].m_iNodeIndexB << "  ";
		cout << edgeVec[edgeIndex].m_iWeightValue << endl;

		m_pEdge[edgeCount] = edgeVec[edgeIndex];
		edgeCount++;

		int nextNodeIndex = edgeVec[edgeIndex].m_iNodeIndexB;

		nodeVec.push_back(nextNodeIndex);
		m_pNodeArray[nextNodeIndex].m_bIsVisited = true;
		cout << m_pNodeArray[nextNodeIndex].m_cData << endl;
	}
}

int CMap::getMinEdge(vector<Edge> edgeVec)
{
	int minWeight = 0;
	int edgeIndex = 0;
	int i = 0;
	for (; i< (int)edgeVec.size(); i++) {
		if (!edgeVec[i].m_bSelected) {
			minWeight = edgeVec[i].m_iWeightValue;
			edgeIndex = i;
			break;
		}
	}

	if (minWeight == 0) {
		return -1;
	}
	for (; i < (int)edgeVec.size(); i++) {
		if (edgeVec[i].m_bSelected) {
			continue;
		} else {
			if (minWeight > edgeVec[i].m_iWeightValue) {
				minWeight = edgeVec[i].m_iWeightValue;
				edgeIndex = i;
			}
		}
	}

	return edgeIndex;
}

MapDemo.cpp–>修改后的测试入口代码文件

#include <iostream>
#include "CMap.h"

using namespace std;


/*
     A
 /   |   \
B -- F -- E
 \  / \  /
  C --- D

A  B  C  D  E  F
0  1  2  3  4  5
  
A-B 6    A-E 5     A-F 1
B-C 3    B-F 2
C-F 8    C-D 2
D-F 4     D-E 2
E-F 9
 */
int main() {
	CMap *pMap = new CMap(6);

	Node *pNodeA = new Node('A');
	Node *pNodeB = new Node('B');
	Node *pNodeC = new Node('C');
	Node *pNodeD = new Node('D');
	Node *pNodeE = new Node('E');
	Node *pNodeF = new Node('F');

	pMap->addNode(pNodeA);
	pMap->addNode(pNodeB);
	pMap->addNode(pNodeC);
	pMap->addNode(pNodeD);
	pMap->addNode(pNodeE);
	pMap->addNode(pNodeF);

	pMap->setValueToMatrixForUndirectedGraph(0, 1, 6);
	pMap->setValueToMatrixForUndirectedGraph(0, 4, 5);
	pMap->setValueToMatrixForUndirectedGraph(0, 5, 1);
	pMap->setValueToMatrixForUndirectedGraph(1, 2, 3);
	pMap->setValueToMatrixForUndirectedGraph(1, 5, 2);
	pMap->setValueToMatrixForUndirectedGraph(2, 5, 8);
	pMap->setValueToMatrixForUndirectedGraph(2, 3, 7);
	pMap->setValueToMatrixForUndirectedGraph(3, 5, 4);
	pMap->setValueToMatrixForUndirectedGraph(3, 4, 2);
	pMap->setValueToMatrixForUndirectedGraph(4, 5, 9);

	pMap->primTree(0);

	delete pMap;
	pMap = NULL;

	return 0;
}

测试结果为:

A
0----5  1
F
5----1  2
B
1----2  3
C
5----3  4
D
3----4  2
E

3.2.2 最小生成树之克鲁斯卡尔算法代码实现

/*

     A
 /   |   \
B -- F -- E
 \  / \  /
  C --- D
  
  A  B  C  D  E  F
  0  1  2  3  4  5

A-B 6 A-E 5 A-F 1
B-C 3 B-F 2
C-F 8 C-D 2
D-F 4 D-E 2
E-F 9

*/

Edge.h–>定义边的相关元素的头文件(存入的数据都是int类型)

#ifndef EDGE_H_
#define EDGE_H_

class Edge
{
public:
	Edge(int nodeIndexA = 0, int nodeIndex = 0, int weightValue = 0);
	int m_iNodeIndexA;
	int m_iNodeIndexB;
	int m_iWeightValue;
	bool m_bSelected;
};

#endif /* EDGE_H_ */

Edge.cpp–>实现边的相关功能代码

#include "Edge.h"
Edge::Edge(int nodeIndexA, int nodeIndexB, int weightValue)
{
	m_iNodeIndexA = nodeIndexA;
	m_iNodeIndexB = nodeIndexB;
	m_iWeightValue = weightValue;
	m_bSelected = false;
}

Node.h–>定义结点相关功能接口和元素的头文件(存入的数据都是char类型)

#ifndef NODE_H_
#define NODE_H_

class Node
{
public:
	Node(char data = 0);
	char m_cData;
	bool m_bIsVisited;
};

#endif /* NODE_H_ */

Node.cpp–>实现结点相关功能代码

#include "Node.h"

Node::Node(char data)
{
	m_cData = data;
	m_bIsVisited = false;
}

CMap.h–>修改后定义图相关功能接口和元素的头文件(存入的数据包含Node结点和Edge边的类型)

#ifndef CMAP_H_
#define CMAP_H_

#include <vector>
#include "Node.h"
#include "Edge.h"
using namespace std;

class CMap
{
public:
	CMap(int capacity);
	~CMap();
	bool addNode(Node *pNode);   //向图中加入顶点(结点)
	void resetNode();            // 重置顶点
	bool setValueToMatrixForDirectedGraph(int row, int col, int val = 1);   //为有向图设置邻接矩阵
	bool setValueToMatrixForUndirectedGraph(int row, int col, int val = 1);  // 为无向图设置零件矩阵
	void printMatrix();   //打印邻接矩阵
	void depthFirstTraverse(int nodeIndex);    //深度优先遍历
	void breathFirstTraverse(int nodeIndex);   //广度优先遍历

	void primTree(int nodeIndex);  //普利姆生成树
	void kruskalTree();            //克鲁斯卡尔算法生成树

private:
	bool getValueFromMatrix(int row, int col, int &val); //从矩阵中获取权值
	void breathFirstTraverseImpl(vector<int> preVec);    // 广度优先遍历实现函数

	int getMinEdge(vector<Edge> edgeVec);          // 获取最小的边
	bool isInSet(vector<int> nodeSet, int target);  //判断顶点是否在点集合中
	void mergeNodeSet(vector<int> &nodeSetA, vector<int> nodeSetB);  //合并两个顶点集合

private:
	int m_iCapacity;    //图中最多可以容纳的顶点数
	int m_iNodeCount;   //已经添加的顶点(结点)个数
	Node *m_pNodeArray; //用来存放顶点数组
	int *m_pMatrix;     //用来存放邻接矩阵

	Edge *m_pEdge;

};

#endif /* CMAP_H_ */

CMap.cpp–>修改后实现图的相关功能代码

#include <iostream>
#include <vector>
#include <string.h>
#include "CMap.h"
using namespace std;

CMap::CMap(int capacity)
{
	m_iCapacity = capacity;
	m_iNodeCount = 0;
	m_pNodeArray = new Node[m_iCapacity];
	m_pMatrix = new int[m_iCapacity * m_iCapacity];
	memset(m_pMatrix, 0, m_iCapacity * m_iCapacity * sizeof(int));
	/*for (int i = 0; i < m_iCapacity * m_iCapacity; i++) {
		m_pMatrix[i] = 0;
	}*/
	m_pEdge = new Edge[m_iCapacity - 1];
}

CMap::~CMap()
{
	delete[] m_pNodeArray;
	delete[] m_pMatrix;
}

bool CMap::addNode(Node *pNode)
{
	if (pNode == NULL) {
		return false;
	}
	m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData;
	m_iNodeCount++;
	return true;
}

void CMap::resetNode()
{
	for(int i = 0; i < m_iNodeCount; i++) {
		m_pNodeArray[i].m_bIsVisited = false;
	}
}


bool CMap::setValueToMatrixForDirectedGraph(int row, int col, int val)
{
	if (row < 0 || row >= m_iCapacity) {
		return false;
	}
	if (col < 0 || col >= m_iCapacity) {
		return false;
	}
	m_pMatrix[row * m_iCapacity + col] = val;
	return true;
}

bool CMap::setValueToMatrixForUndirectedGraph(int row, int col, int val)
{
	if (row < 0 || row >= m_iCapacity) {
		return false;
	}
	if (col < 0 || col >= m_iCapacity) {
		return false;
	}
	m_pMatrix[row * m_iCapacity + col] = val;
	m_pMatrix[col * m_iCapacity + row] = val;
	return true;
}

bool CMap::getValueFromMatrix(int row, int col, int &val)
{
	if (row < 0 || row >= m_iCapacity) {
		return false;
	}
	if (col < 0 || col >= m_iCapacity) {
		return false;
	}
	val = m_pMatrix[row * m_iCapacity + col];
	return true;
}

void CMap::printMatrix()
{
	for (int i = 0; i < m_iCapacity; i++) {
		for (int k = 0; k < m_iCapacity; k++) {
			cout << m_pMatrix[i * m_iCapacity + k] << " ";
		}
		cout << endl;
	}
}

//深度优先遍历
void CMap::depthFirstTraverse(int nodeIndex)
{
	int value = 0;
	cout << m_pNodeArray[nodeIndex].m_cData << " ";
	m_pNodeArray[nodeIndex].m_bIsVisited = true;

	for (int i = 0; i < m_iCapacity; i++) {
		getValueFromMatrix(nodeIndex, i, value);
		if (value == 1) {
			if (m_pNodeArray[i].m_bIsVisited) {
				continue;
			} else {
				depthFirstTraverse(i);
			}
		} else {
			continue;
		}
	}
}

//广度优先遍历
void CMap::breathFirstTraverse(int nodeIndex)
{
	cout << m_pNodeArray[nodeIndex].m_cData << " ";
	m_pNodeArray[nodeIndex].m_bIsVisited = true;
	vector<int> curVec;
	curVec.push_back(nodeIndex);

	breathFirstTraverseImpl(curVec);
}

void CMap::breathFirstTraverseImpl(vector<int> preVec)
{
	int value = 0;
	vector<int> curVec;

	for (int j = 0; j < (int)preVec.size(); j++) {
		for (int i = 0; i < m_iCapacity; i++) {
			getValueFromMatrix(preVec[j], i, value);
			if (value != 0) {
				if (m_pNodeArray[i].m_bIsVisited) {
					continue;
				} else {
					cout << m_pNodeArray[i].m_cData << " ";
					m_pNodeArray[i].m_bIsVisited = true;

					curVec.push_back(i);
				}
			}
		}
	}
	if (0 == curVec.size()) {
		return;
	} else {
		breathFirstTraverseImpl(curVec);
	}
}

// 普利姆生成树
void CMap::primTree(int nodeIndex)
{
	int value = 0;
	int edgeCount = 0;     // 边的数量
	vector<int> nodeVec;   // 点的集合
	vector<Edge> edgeVec;  // 最小边的集合

	cout << m_pNodeArray[nodeIndex].m_cData << endl;

	nodeVec.push_back(nodeIndex);
	m_pNodeArray[nodeIndex].m_bIsVisited = true;

	while (edgeCount < m_iCapacity - 1) {
		int temp = nodeVec.back();
		for (int i = 0; i < m_iCapacity; i++) {
			getValueFromMatrix(temp, i, value);
			if (value != 0) {
				if (m_pNodeArray[i].m_bIsVisited) {
					continue;
				} else {
					Edge edge(temp, i, value);
					edgeVec.push_back(edge);
				}
			}
		}

		// 从可选边集合中找到最小的边
		int edgeIndex = getMinEdge(edgeVec);
		edgeVec[edgeIndex].m_bSelected = true;

		cout << edgeVec[edgeIndex].m_iNodeIndexA << "----" << edgeVec[edgeIndex].m_iNodeIndexB << "  ";
		cout << edgeVec[edgeIndex].m_iWeightValue << endl;

		m_pEdge[edgeCount] = edgeVec[edgeIndex];
		edgeCount++;

		int nextNodeIndex = edgeVec[edgeIndex].m_iNodeIndexB;

		nodeVec.push_back(nextNodeIndex);
		m_pNodeArray[nextNodeIndex].m_bIsVisited = true;
		cout << m_pNodeArray[nextNodeIndex].m_cData << endl;
	}
}

int CMap::getMinEdge(vector<Edge> edgeVec)
{
	int minWeight = 0;
	int edgeIndex = 0;
	int i = 0;
	for (; i< (int)edgeVec.size(); i++) {
		if (!edgeVec[i].m_bSelected) {
			minWeight = edgeVec[i].m_iWeightValue;
			edgeIndex = i;
			break;
		}
	}

	if (minWeight == 0) {
		return -1;
	}
	for (; i < (int)edgeVec.size(); i++) {
		if (edgeVec[i].m_bSelected) {
			continue;
		} else {
			if (minWeight > edgeVec[i].m_iWeightValue) {
				minWeight = edgeVec[i].m_iWeightValue;
				edgeIndex = i;
			}
		}
	}

	return edgeIndex;
}

// 克鲁斯卡尔算法生成树
void CMap::kruskalTree()
{
	int value= 0;
	int edgeCount = 0;

	//定义存放结点集合的数组
	vector<vector<int> > nodeSets;

	//第一步:取出所有边
	vector<Edge> edgeVec;
	for (int i = 0; i < m_iCapacity; i++) {
		for (int k = i + 1; k < m_iCapacity; k++) {
			getValueFromMatrix(i, k, value);
			if (value != 0) {
				Edge edge(i, k, value);
				edgeVec.push_back(edge);
			}
		}
	}

	//第二步:从所有边中取出组成最小生成树的边
	//1.找到算法结束条件
	while(edgeCount < m_iCapacity - 1) {
		//2.从边集合中找到最小边
		int minEdgeIndex = getMinEdge(edgeVec);
		edgeVec[minEdgeIndex].m_bSelected = true;

		//3.找到最小边链接的点
		int nodeAIndex = edgeVec[minEdgeIndex].m_iNodeIndexA;
		int nodeBIndex = edgeVec[minEdgeIndex].m_iNodeIndexB;

		bool nodeAIsInSet = false;
		bool nodeBIsInSet = false;

		int nodeAInSetLabel = -1;
		int nodeBInSetLabel = -1;

		//4.找出点所在的点集合
		for (int i = 0; i < (int)nodeSets.size(); i++) {
			nodeAIsInSet = isInSet(nodeSets[i], nodeAIndex);
			if (nodeAIsInSet) {
				nodeAInSetLabel = i;
			}
		}

		for (int i = 0; i < (int)nodeSets.size(); i++) {
			nodeBIsInSet = isInSet(nodeSets[i], nodeBIndex);
			if (nodeBIsInSet) {
				nodeBInSetLabel = i;
			}
		}

		//5.根据点所在集合的不同做出不同处理
		if (nodeAInSetLabel == -1 && nodeBInSetLabel == -1) {
			vector<int> vec;
			vec.push_back(nodeAIndex);
			vec.push_back(nodeBIndex);
		} else if (nodeAInSetLabel == -1 && nodeBInSetLabel != -1) {
			nodeSets[nodeBInSetLabel].push_back(nodeAIndex);
		} else if (nodeAInSetLabel != -1 && nodeBInSetLabel == -1) {
			nodeSets[nodeAInSetLabel].push_back(nodeBIndex);
		} else if (nodeAInSetLabel != -1 && nodeBInSetLabel != -1
				&& nodeAInSetLabel != nodeBInSetLabel) {
			mergeNodeSet(nodeSets[nodeAInSetLabel], nodeSets[nodeBInSetLabel]);
			for (int k = nodeBInSetLabel; k < (int)nodeSets.size(); k++) {
				nodeSets[k] = nodeSets[k + 1];
			}
		} else if (nodeAInSetLabel != -1 && nodeBInSetLabel != -1
				&& nodeAInSetLabel != nodeBInSetLabel) {
			continue;
		}
		m_pEdge[edgeCount] = edgeVec[minEdgeIndex];
		edgeCount++;
		cout << edgeVec[minEdgeIndex].m_iNodeIndexA << "---" << edgeVec[minEdgeIndex].m_iNodeIndexB << " ";
		cout << edgeVec[minEdgeIndex].m_iWeightValue << endl;;
	}
}

bool CMap::isInSet(vector<int> nodeSet, int target)
{
	for (int i = 0; i < (int)nodeSet.size(); i++) {
		if (nodeSet[i] == target) {
			return true;
		}
	}
	return false;
}

void CMap::mergeNodeSet(vector<int> &nodeSetA, vector<int> nodeSetB)
{
	for (int i = 0; i < (int)nodeSetB.size(); i++) {
		nodeSetA.push_back(nodeSetB[i]);
	}
}

MapDemo.cpp–>修改后的测试入口代码文件

#include <iostream>
#include "CMap.h"

using namespace std;


/*
     A
 /   |   \
B -- F -- E
 \  / \  /
  C --- D

  A  B  C  D  E  F
  0  1  2  3  4  5
A-B 6    A-E 5     A-F 1
B-C 3    B-F 2
C-F 8    C-D 2
D-F 4     D-E 2
E-F 9
 */
int main() {
	CMap *pMap = new CMap(6);

	Node *pNodeA = new Node('A');
	Node *pNodeB = new Node('B');
	Node *pNodeC = new Node('C');
	Node *pNodeD = new Node('D');
	Node *pNodeE = new Node('E');
	Node *pNodeF = new Node('F');

	pMap->addNode(pNodeA);
	pMap->addNode(pNodeB);
	pMap->addNode(pNodeC);
	pMap->addNode(pNodeD);
	pMap->addNode(pNodeE);
	pMap->addNode(pNodeF);

	pMap->setValueToMatrixForUndirectedGraph(0, 1, 6);
	pMap->setValueToMatrixForUndirectedGraph(0, 4, 5);
	pMap->setValueToMatrixForUndirectedGraph(0, 5, 1);
	pMap->setValueToMatrixForUndirectedGraph(1, 2, 3);
	pMap->setValueToMatrixForUndirectedGraph(1, 5, 2);
	pMap->setValueToMatrixForUndirectedGraph(2, 5, 8);
	pMap->setValueToMatrixForUndirectedGraph(2, 3, 7);
	pMap->setValueToMatrixForUndirectedGraph(3, 5, 4);
	pMap->setValueToMatrixForUndirectedGraph(3, 4, 2);
	pMap->setValueToMatrixForUndirectedGraph(4, 5, 9);

	pMap->kruskalTree();

	delete pMap;
	pMap = NULL;

	return 0;
}

测试结果为:

0---5 1
1---5 2
3---4 2
1---2 3
3---5 4

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值