在图中,有很多种算法,比如最常见的P算法和K算法。这里介绍一下P算法寻找最短路径算法:
1.任意找一个索引的点,通常是索引为0的第一个节点。输出这个节点数据,向容器中添加一个节点,并标记为已经被访问过。
2.设置几个变量,value(记录边的权值),edgeCount(记录加入到边容器里的边数),temp(记录点容器加入值的下标,当成传入参数获取边上权值)。
3.下面的两个函数是最核心的代码,一个是;

//普里姆核心算法实现(P算法)
void CMap::PrimTree(int nodeIndex)
{
    int value = 0;
    int edgeCount = 0;
    vector<int> nodeVec;//节点集合
    vector<Edge>edgeVec;//边的集合

    cout << m_pNodeArray[nodeIndex].m_cData << endl;//输出第一个节点,也就是所谓的0索引节点

    nodeVec.push_back(nodeIndex);//往容器中添加一个节点。
    m_pNodeArray[nodeIndex].m_bIsVisited = true;//表示节点被访问过。

    while (edgeCount < m_iCapacity - 1)//最小生成树中m_iCapacity个节点,那么会有m_iCapacity-1个边。
    {
        int temp = nodeVec.back();//取出vector中的最后一个元素。也就是上一次循环加入的新的节点//end() 函数返回一个指向当前vector末尾元素的下一位置的迭代器.要访问末尾元素,需要先将此迭代器减1。
                                                  //  并用参数temp存储              // back() 函数返回当前vector最末一个元素的引用。
        for (int i = 0; i < m_iCapacity; i++)
        {
            getValueFromMatrix(temp, i, value);//获取边上的权值
            if (value != 0)//取到了权值
            {
                if (m_pNodeArray[i].m_bIsVisited == true)//判断与最开始节点相连的节点标记为访问过
                {
                    continue;//被访问则继续下一次循环继续找边
                }
                else
                {
                    Edge edge(temp, i, value);//新建边
                    edgeVec.push_back(edge);//将边放入边容器内
                }
            }
        }
        //从可选边集合中找出最小的边
        int edgeIndex = getMinEdge(edgeVec);//这个函数的实现也很关键,找到了最小权值边的索引,后面在此基础上继续
        edgeVec[edgeIndex].m_bSelected = true;//定义edge类时候,里面的相关成员这里全部就开始被用上了

        cout << edgeVec[edgeIndex].m_iNodeIndexA << "----" << edgeVec[edgeIndex].m_iNodeIndexB << "  ";
        cout << edgeVec[edgeIndex].m_iWeightValue << endl;//这里输出 ,边,权值

        //m_pEdge[edgeCount] = edgeVec[edgeIndex];
        edgeCount++;//这个变量的值一直增长到和m_iCapacity-1相等就退出了while(1)循环
        int nextNodeIndex = edgeVec[edgeIndex].m_iNodeIndexB;

        nodeVec.push_back(nextNodeIndex);//与上面的nodeVec.back()对应,放入边的另外一个节点
        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 < edgeVec.size(); i++)//遍历边容器中的所有边
    {
        if (edgeVec[i].m_bSelected == false)
        {
            minWeight = edgeVec[i].m_iWeightValue;
            edgeIndex = i;
            break;
        }
    }
    if (0 == minWeight)
    {
        return -1;
    }
    for (; i < 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;//返回边的索引值
}

以上是实现算法的核心函数,里面有注释。
下面给出整个工程代码:分为Node.h和Node.cpp,Edge.h和Edge.cpp,和CMap.h和CMap.cpp,最后加上Demo.cpp中的主函数调用代码。

#ifndef Node_h
#define Node_h

class Node
{
public:
    Node();//这是默认构造函数,必须要有
    Node(char data);//这个是对节点的初始化构造函数
    ~Node();
public:
    char m_cData;//定义了字符型数据
    bool m_bIsVisited;//判断当前节点是否被访问
};

#endif


#include "Node.h"
Node::Node()
{

}

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

Node::~Node()
{

}
#ifndef Edge_h_
#define Edge_h_

class Edge//这个类是边,里面的成员变量就都是边的要素(两个点,边的权值,边是否标记变量)
{
public:
    Edge(int NodeIndexA = 0, int NodeIndexB = 0,int WeightValue = 0);
    int m_iNodeIndexA;
    int m_iNodeIndexB;//A.B两个节点
    int m_iWeightValue;
    bool m_bSelected;
};


#endif
#include "Edge.h"

Edge::Edge(int NodeIndexA , int NodeIndexB , int WeightValue )
{
    m_iNodeIndexA = NodeIndexA;
    m_iNodeIndexB = NodeIndexB;
    m_iWeightValue = WeightValue;
    m_bSelected = false;
}
#ifndef Cmap_h
#define Cmap_h

#include "Node.h"
#include "Edge.h"
#include<vector>
using namespace std;
//#include<vector.h>
class CMap
{
public:
    CMap(int capacity);//capacity表示图中可以容纳节点的个数
    ~CMap();
    bool addNode(Node* pNode);//增加节点进入图
    void resetNode();//将所有节点重置为没有被访问过
    bool setValueToMatrixForDirectedGeaph(int row, int col, int val = 1);//有向图设置邻接矩阵,val为权值,这里默认值为1
    bool  setValueToMatrixForUndirectedGeaph(int row, int col, int val = 1);//无向图设置临界矩阵
    void printMatrix();//打印出邻接矩阵
    void depthFirstTraverse(int nodeIndex);//深度遍历图的节点
    //void breadthFirstTravese(int nodeIndex);


public:
    void PrimTree(int nodeIndex); //p算法产生最小生成树

private:
    bool getValueFromMatrix(int row, int col, int&val);
    //void breadthFirstTraveseImp(vector<int>preVec);

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

private:
    int m_iCapacity;//图中最多可以容纳的定点数
    int m_iNodeCount;//已经添加的节点个数
    Node* m_pNodeArray;//用来存放定点数组
    int *m_pMatrix;//和邻接矩阵有关
    Edge* m_pEdge;//这个指针是用来存放边(Edge)的,就是用指针指向一段Edge型的内存空间。来存放Edge。
};

#endif
#include "CMap.h"
#include "Edge.h"
//#include "Node.h"
#include<iostream>
#include<vector>
using namespace std;

CMap::CMap(int capacity)
{

    m_iCapacity = capacity;
    m_iNodeCount = 0;
    m_pNodeArray = new Node[m_iCapacity];//这里堆上分配的图节点数组用来存储外面传进来的节点数据,在addNode(Node* pNode)中可以看到关系
    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];//分配存放Edge边的空间
}

CMap::~CMap()
{
    delete[]m_pNodeArray;//节点数组
    delete[]m_pMatrix;//邻接矩阵数组
}

/*
此为增加数据节点函数,节点内存在构造函数里已经被分配了。
这里只需要将pNode中的数据传入构造函数里分配的内存节点
*/
bool CMap::addNode(Node* pNode)
{
    if (pNode == NULL)
    {
        return false;
    }
    m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData;
    m_iNodeCount++;//没加一个节点,节点计数变量加一
    return true;
}

/*
m_bIsVisited表示节点在遍历的时候是否被访问,这是个bool型的变量,被访问为true,没有被被访问为false。
这个函数就是将所有有的节点标志为未被访问过。
*/
void CMap::resetNode()
{
    for (int i = 0; i < m_iNodeCount; i++)
    {
        m_pNodeArray[i].m_bIsVisited = false;
    }
}

/*
函数名称:向有向图添加节点(注意是有向图,那么其邻接矩阵的值就不会关于对角线对称,有一个三角形就可以)
*/

bool CMap::setValueToMatrixForDirectedGeaph(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::setValueToMatrixForUndirectedGeaph(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;
}
/*
函数功能:打印出图的邻接矩阵
函数实现:两个for循环
*/
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;
    }
}
/*
函数名称:从邻接矩阵中获取指定坐标值
*/
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;
}

/*
函数功能:图的深度优先遍历
函数实现:传入参数nodeIndex表示从第几个节点开始遍历
*/
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++)//每一次循环 i 都会加1
    {
        getValueFromMatrix(nodeIndex, i, value);//获得邻接矩阵中的值,1代表有弧相连,0代表两个节点没有弧相互连接
        if (value == 1)//有弧存在
        {
            if (m_pNodeArray[i].m_bIsVisited == true)//
            {
                continue;//节点被访问过,则i+1,进入
            }
            else
            {
                depthFirstTraverse(i);//这是核心的递归操作代码,这里要仔细对照邻接矩阵和图来理解,不同于广度优先遍历
            }
        }

        else
        {
            continue;
        }
    }
}

/*
函数名称:广度优先算法

*/
//void CMap::breadthFirstTravese(int nodeIndex)
//{
//
//}
//void CMap::breadthFirstTraveseImp(vector<int>preVec)
//{
//
//}
//普里姆核心算法实现(P算法)
void CMap::PrimTree(int nodeIndex)
{
    int value = 0;
    int edgeCount = 0;
    vector<int> nodeVec;//节点集合
    vector<Edge>edgeVec;//边的集合

    cout << m_pNodeArray[nodeIndex].m_cData << endl;//输出第一个节点,也就是所谓的0索引节点

    nodeVec.push_back(nodeIndex);//往容器中添加一个节点。
    m_pNodeArray[nodeIndex].m_bIsVisited = true;//表示节点被访问过。

    while (edgeCount < m_iCapacity - 1)//最小生成树中m_iCapacity个节点,那么会有m_iCapacity-1个边。
    {
        int temp = nodeVec.back();//取出vector中的最后一个元素。也就是上一次循环加入的新的节点//end() 函数返回一个指向当前vector末尾元素的下一位置的迭代器.要访问末尾元素,需要先将此迭代器减1。
                                                  //  并用参数temp存储              // back() 函数返回当前vector最末一个元素的引用。
        for (int i = 0; i < m_iCapacity; i++)
        {
            getValueFromMatrix(temp, i, value);//获取边上的权值
            if (value != 0)//取到了权值
            {
                if (m_pNodeArray[i].m_bIsVisited == true)//判断与最开始节点相连的节点标记为访问过
                {
                    continue;//被访问则继续下一次循环继续找边
                }
                else
                {
                    Edge edge(temp, i, value);//新建边
                    edgeVec.push_back(edge);//将边放入边容器内
                }
            }
        }
        //从可选边集合中找出最小的边
        int edgeIndex = getMinEdge(edgeVec);//这个函数的实现也很关键,找到了最小权值边的索引,后面在此基础上继续
        edgeVec[edgeIndex].m_bSelected = true;//定义edge类时候,里面的相关成员这里全部就开始被用上了

        cout << edgeVec[edgeIndex].m_iNodeIndexA << "----" << edgeVec[edgeIndex].m_iNodeIndexB << "  ";
        cout << edgeVec[edgeIndex].m_iWeightValue << endl;//这里输出 ,边,权值

        //m_pEdge[edgeCount] = edgeVec[edgeIndex];
        edgeCount++;//这个变量的值一直增长到和m_iCapacity-1相等就退出了while(1)循环
        int nextNodeIndex = edgeVec[edgeIndex].m_iNodeIndexB;

        nodeVec.push_back(nextNodeIndex);//与上面的nodeVec.back()对应,放入边的另外一个节点
        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 < edgeVec.size(); i++)//遍历边容器中的所有边
    {
        if (edgeVec[i].m_bSelected == false)
        {
            minWeight = edgeVec[i].m_iWeightValue;
            edgeIndex = i;
            break;
        }
    }
    if (0 == minWeight)
    {
        return -1;
    }
    for (; i < 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;//返回边的索引值
}

最后的Demo代码

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

int main()
{
    CMap* pMap = new CMap(6);//这里是建立一个CMap*型指针。来调用相关函数

    Node* nodeA = new Node('A');//这里是创建8个节点。
    Node* nodeB = new Node('B');
    Node* nodeC = new Node('C');
    Node* nodeD = new Node('D');
    Node* nodeE = new Node('E');
    Node* nodeF = new Node('F');

    pMap->addNode(nodeA);//将节点增加到图中
    pMap->addNode(nodeB);
    pMap->addNode(nodeC);
    pMap->addNode(nodeD);
    pMap->addNode(nodeE);
    pMap->addNode(nodeF);
    /*pMap->addNode(nodeG);
    pMap->addNode(nodeH);*/

    pMap->setValueToMatrixForUndirectedGeaph(0, 1,6);//表示那几个节点相连,在临界矩阵中表现出来
    pMap->setValueToMatrixForUndirectedGeaph(0, 4,5);
    pMap->setValueToMatrixForUndirectedGeaph(0, 5,1);
    pMap->setValueToMatrixForUndirectedGeaph(1, 2,3);
    pMap->setValueToMatrixForUndirectedGeaph(1, 5,2);
    pMap->setValueToMatrixForUndirectedGeaph(2, 5,8);
    pMap->setValueToMatrixForUndirectedGeaph(2, 3,7);
    pMap->setValueToMatrixForUndirectedGeaph(3, 5,4);
    pMap->setValueToMatrixForUndirectedGeaph(3, 4,2);
    pMap->setValueToMatrixForUndirectedGeaph(4, 5,9);

    //pMap->printMatrix();
    pMap->PrimTree(0);

    cout << endl;

    //pMap->depthFirstTraverse(0);

    system("pause");
    return 0;
}

仅供参考。