圖的實現 鄰接矩陣+無向圖
阿新 • • 發佈:2019-01-25
#include <iostream>
#include <string.h>
#include <vector>
#include <stdlib.h>
using namespace std;
class Node
{
public:
Node(char data = 0);//建構函式 初始化
char m_Data; //值
bool m_blsVisited; //標識是否被訪問過
};
class Edge
{
public:
Edge(int nodeIndexA = 0, int nodeIndexB = 0 , int weightValue = 0);
int m_iNodeIndexA;
int m_iNodeIndexB;
int m_iWeightValue;
bool m_bSelected;
};
class CMap
{
public:
CMap(int iCapacity);
~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 BreadthFirstTraverse(int NodeIndex);
//最小生成樹
void primTree(int nodeIndex); //nodeIndex指定的第一個點
void KruskalTree();
private :
bool GetValueFromMatrix(int row, int col, int &val);
void BreadthFirstTraverseImpl(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; //存最小生成樹中的邊
};
Node::Node(char data)
{
m_Data = data;
m_blsVisited = false;
}
CMap::CMap(int iCapacity)
{
m_iCapacity = iCapacity;
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));
m_pEdge = new Edge[iCapacity - 1];
}
CMap::~CMap()
{
delete [] m_pNodeArray;
delete [] m_pMatrix;
delete [] m_pEdge;
}
bool CMap::AddNode(Node* pNode)
{
m_pNodeArray[m_iNodeCount].m_Data = pNode->m_Data;
m_iNodeCount++;
return true;
}
void CMap::ResetNode()
{
for(int i = 0; i < m_iNodeCount; i++)
{
m_pNodeArray[i].m_blsVisited = false;
}
}
//有向圖鄰接矩陣
bool CMap::SetValueToMatrixForDirectedGraph(int row, int col, int val)
{
m_pMatrix[row*m_iCapacity + col] = val;
return true;
}
bool CMap::SetValueToMatrixForUndirectedGraph(int row, int col, int val)
{
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)
{
val = m_pMatrix[row*m_iCapacity + col];
return true;
}
void CMap::PrintMatrix()
{
for(int i = 0; i < m_iCapacity; i++)
{
for(int j = 0; j < m_iCapacity; j++)
{
cout << m_pMatrix[i*m_iCapacity + j] << " ";
}
cout << endl;
}
}
void CMap::DepthFirstTraverse(int NodeIndex)
{
int value = 0;
cout << m_pNodeArray[NodeIndex].m_Data << " ";
m_pNodeArray[NodeIndex].m_blsVisited = true;
for(int i =0; i < m_iCapacity; i++)
{
GetValueFromMatrix(NodeIndex, i, value);
if(value == 1)
{
if(m_pNodeArray[i].m_blsVisited)
{
continue;
}
else
{
DepthFirstTraverse(i);
}
}
else
{
continue;
}
}
}
void CMap::BreadthFirstTraverse(int NodeIndex)
{
cout << m_pNodeArray[NodeIndex].m_Data << " ";
m_pNodeArray[NodeIndex].m_blsVisited = true;
vector<int> curVec;
curVec.push_back(NodeIndex);
BreadthFirstTraverseImpl(curVec);
}
void CMap::BreadthFirstTraverseImpl(vector<int> preVec)
{
int value = 0;
vector<int> curVec; //儲存當前這一層所有節點
//preVec 上一層所有節點
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_blsVisited)
{
continue;
}
else
{
cout << m_pNodeArray[i].m_Data << " ";
m_pNodeArray[i].m_blsVisited = true;
curVec.push_back(i);
}
}
}
}
if(curVec.size() == 0)
{
return ;
}
else
{
BreadthFirstTraverseImpl(curVec);
}
}
Edge::Edge(int nodeIndexA, int nodeIndexB, int weightValue)
{
m_iNodeIndexA = nodeIndexA;
m_iNodeIndexB = nodeIndexB;
m_iWeightValue = weightValue;
m_bSelected = false;
}
//普利姆生成樹
void CMap::primTree(int nodeIndex)
{
int value = 0; //取邊的權值
int edgeCount = 0;
vector<int> NodeVec; //儲存點的集合
vector<Edge> EdgeVec; //備選邊的集合
cout << m_pNodeArray[nodeIndex].m_Data << endl;
m_pNodeArray[nodeIndex].m_blsVisited = true;
NodeVec.push_back(nodeIndex);
while(edgeCount < m_iCapacity - 1)
{
int temp = NodeVec.back(); //取出最尾部的元素
//將與temp節點所連的所有的邊都放入備選邊集合
for(int i = 0; i < m_iCapacity; i++)
{
GetValueFromMatrix(temp, i, value);
if(value != 0)
{
if(m_pNodeArray[i].m_blsVisited)
{
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];
//找到與當前最小邊所連線的點
int nextNodeIndex= EdgeVec[edgeIndex].m_iNodeIndexB;
NodeVec.push_back(nextNodeIndex);
m_pNodeArray[nextNodeIndex].m_blsVisited = true;
cout << m_pNodeArray[nextNodeIndex].m_Data << endl;
}
}
int CMap::GetMinEdge(vector<Edge> EdgeVec)
{
int minWeight = 0;
int edgeIndex = 0;
int i= 0;
//取出第一條未訪問的邊
for(; i < EdgeVec.size(); i++)
{
if(!EdgeVec[i].m_bSelected)
{
minWeight = EdgeVec[i].m_iWeightValue;
edgeIndex = i;
break;
}
}
if(minWeight == 0)
{
return -1;
}
//剩餘邊中找最小邊
for(; i < EdgeVec.size(); i++)
{
if(!EdgeVec[i].m_bSelected)
{
if(minWeight > EdgeVec[i].m_iWeightValue)
{
minWeight = EdgeVec[i].m_iWeightValue;
edgeIndex = i;
}
}
else
{
continue ;
}
}
return edgeIndex;
}
bool CMap::IsInSet(vector<int> nodeSet, int target)
{
for(int i = 0; i < 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 < nodeSetB.size(); i++)
{
nodeSetA.push_back(nodeSetB[i]);
}
}
void CMap::KruskalTree()
{
int value = 0;
int edgeCount = 0;
//定義一個點集合的陣列
vector< vector<int> > NodeSets;
//1.取出所有的邊
vector<Edge> EdgeVec;
for(int i = 0; i < m_iCapacity; i++)
{
for(int j = i + 1; j < m_iCapacity; j++) //取出鄰接矩陣上半個三角,不含主對角線上的資料
{
GetValueFromMatrix(i, j, value);
if(value != 0)
{
Edge edge(i, j, value);
EdgeVec.push_back(edge);
}
}
}
//2. 從所有邊中取出組成最小生成樹的邊
// 找到演算法結束條件 邊數 = 頂點數 - 1
while(edgeCount < m_iCapacity - 1)
{
// 從邊集合中找到最小邊
int minEdgeIndex = GetMinEdge(EdgeVec);
EdgeVec[minEdgeIndex].m_bSelected = true;
//找到最小邊連線的點
int nodeAIndex = EdgeVec[minEdgeIndex].m_iNodeIndexA;
int nodeBIndex = EdgeVec[minEdgeIndex].m_iNodeIndexB;
bool nodeAIsInSet = false;
bool nodeBIsInSet = false;
int nodeAInSetLabel = -1;
int nodeBInSetLabel = -1;
//找出A點所在的集合
for(int i = 0; i < NodeSets.size(); i++)
{
nodeAIsInSet = IsInSet(NodeSets[i], nodeAIndex);
if(nodeAIsInSet)
{
nodeAInSetLabel = i;
}
}
//找出B點所在的集合
for(int i = 0; i < NodeSets.size(); i++)
{
nodeBIsInSet = IsInSet(NodeSets[i], nodeAIndex);
if(nodeBIsInSet)
{
nodeBInSetLabel = i;
}
}
//根據點所在的集合做出不同的處理
if(nodeAInSetLabel == -1 && nodeBInSetLabel == -1)
{
vector<int> vec;
vec.push_back(nodeAInSetLabel);
vec.push_back(nodeBInSetLabel);
NodeSets.push_back(vec);
}
else if(nodeAInSetLabel == -1 && nodeBInSetLabel != -1)
{
NodeSets[nodeBInSetLabel].push_back(nodeAInSetLabel);
}
else if(nodeAInSetLabel != -1 && nodeBInSetLabel == -1)
{
NodeSets[nodeAInSetLabel].push_back(nodeBInSetLabel);
}
else if(nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel != nodeBInSetLabel)
{
MergeNodeSet(NodeSets[nodeAInSetLabel], NodeSets[nodeBInSetLabel]);//合併集合
for(int k = nodeBInSetLabel; k < (int)NodeSets.size() - 1; k++) //類似於在佇列中刪除一個節點
{
NodeSets[k] = NodeSets[k + 1];
}
}
else if(nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel == nodeBInSetLabel)
{
continue ;
}
m_pEdge[edgeCount++] = EdgeVec[minEdgeIndex];
cout << EdgeVec[minEdgeIndex].m_iNodeIndexA << "......" << EdgeVec[minEdgeIndex].m_iNodeIndexB << " ";
cout << EdgeVec[minEdgeIndex].m_iWeightValue << endl;
}
}
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');
// 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);
#if 0
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);
#endif
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->PrintMatrix();
cout << endl;
#if 0
pMap->ResetNode();
pMap->DepthFirstTraverse(0);
cout << endl;
pMap->ResetNode();
pMap->BreadthFirstTraverse(0);
cout << endl;
#endif
pMap->KruskalTree();
system("pause");
return 0;
}