注册 登录
编程论坛 数据结构与算法

再发邻接表实现的带权无向图的抽象数据类型,及其相关算法的实现,(oop)大家多探讨:

geninsf009 发布于 2008-12-07 20:24, 3516 次点击
涉及到的成员函数实现的算法在类的声明中已经详细列出了,大家参考,这里基本涉及到了我们常见的无向图的所有算法:
#ifndef GRAPHLINK_H
#define GRAPHLINK_H

#include"BaseGraph.h"
#include<iostream.h>
#include<stdlib.h>
#include"LinkedQueue.h"
#include"GenTree.h"
#include"Forest.h"

/////////////////////////////////////////////////
//Edge 边结点结构的定义
/////////////////////////////////////////////////
template<class T,class E>
struct Edge
{
    int dest;             //目的结点的结点号
    E cost;               //边对应的权值
    Edge<T,E>* link;      //下一条边结点的指针
    Edge(){};             //默认构造函数
    Edge(int num,E weight)//带参数的构造函数
    :dest(num),cost(weight),link(NULL){};
    bool operator!=(Edge<T,E>& R)const
    {                     //成员重载运算符
        if(R.dest==dest)  //判断两个边结点是否相等
            return true;
        else
            return false;
    };
};
///////////////////////////Edge边结点结构定义结束

/////////////////////////////////////////////////
//Vertex结构 图的顶点结点的定义
/////////////////////////////////////////////////
template<class T,class E>
struct Vertex
{
    T data;        //结点的数据域
    Edge<T,E>* adj;//边链表的首指针
};
///////////////////////////Vertex顶点结构定义结束

/////////////////////////////////////////////////
//Graphlink<T,E>类模板的实现
//以邻接链表方式实现的图的类模板的声明和实现
//该类以Graph<T,E>为虚基类
//T是顶点数据域类型,E是边的权值类型
/////////////////////////////////////////////////
template<class T,class E>
class Graphlink:public Graph<T,E>
{
private:
    Vertex<T,E>* NodeTable;                 //顶点表数组
    int getVertexPos(const T vertex)        //给出指定顶点Vertex的结点号
    {
        for(int i=0;i<numVertices;i++)      //遍历所有的邻接顶点
            if(NodeTable[i]==vertex)
                return i;
        return -1;                          //没有找到
    };
    bool* visited;                          //用于标记第i个结点是否被访问的数组
    void DFS(int start);                    //递归:深度优先遍历本图,start是起始结点
    int* Path;                              //用于存放最短路径的辅助数组
public:
    Graphlink(int sz=DefaultVertices);      //默认构造函数
    ~Graphlink();                           //析构函数
    T getValue(int i)                       //取结点号为i的结点里的数据
    {
        if(i>=0 && i<maxVertices)
            return NodeTable[i].data;
        else
            return 0;
    };
    
    E getWeight(int v1,int v2);              //取得边(v1,v2)上的权值
    bool insertVertex(const T vertex);       //在图中插入一个顶点vertex
    bool removeVertex(int v);                //在图中删除指定结点号v的结点
    bool insertEdge(int v1,int v2,E cost);   //插入一条边以及对应的权值
    bool removeEdge(int v1,int v2);          //删除边(v1,v2)
    int getFirstNeighbor(int v);             //取得结点v的第一个邻接结点
    int getNextNeighbor(int v,int w);        //取得v的邻接结点中w后的那个邻接结点

    void DFSGraphic(int start);              //深度优先遍历当前图所有结点
    void BFSGraphic();                       //广度优先遍历
    void Find_Connected_Component();         //求图的所有的连通分量顶点集
    TreeNode<T>* DFSTree(int v);             //递归:得到以v为出发点的深度优先生成树TS
    void DisplayDFSTree(int v);              //调用上面的递归函数求图的深度优先生成树
    TreeNode<T>* DFSForest(int v);           //则求其所有连通分量的的深度优先生成森林
    void Find_DFSForest(int v)               //得到非连通图的深度优先生成森林
    {
        Forest<char> F;
        F.setRoot(DFSForest(0));
        cout<<"深度优先生成森林是:"<<endl;
        F.Display();
    };
    int getFirstUnvisit(int p,bool* visited);     //得到当前未访问的第一个邻接结点
    int getNextUnvisit(int p,int v,bool* visited);//得到下个未访问的邻接结点
    void DepthFirst(int start);                   //非递归深度优先遍历当前图
    void Dijkstra(int v);                         //求v到其他顶点的最短路径
    void DisplayPath(int v,E* d);                 //显示当前图中从顶点v到其他所有顶点的最短路径
    int DFSArticul(int v0,int* dfn,int* low);     //递归:从顶点v0出发DFS当前图,查找并输出关节点
    void FindArticul();                           //找出当前图中所有的关节点

    //友元重载输出运算符
    friend ostream& operator<<(ostream& os,Graphlink<T,E>& G);
    //友元重载输入运算符
    friend istream& operator>>(istream& is,Graphlink<T,E>& G);
};
/////////////////////Graphlink<T,E>类模板声明结束
25 回复
#2
geninsf0092008-12-07 20:25
/////////////////////////////////////////////////
//默认构造函数
/////////////////////////////////////////////////
template<class T,class E>
Graphlink<T,E>::Graphlink(int sz)
{
    maxVertices=sz;     //图中最大的顶点数
    numEdges=0;         //初始边数
    numVertices=0;      //初始顶点数
    
    //顶点表数组开辟内存区域
    NodeTable=new Vertex<T,E>[sz];
    if(NodeTable==NULL)
    {
        cout<<"内存分配失败!"<<endl;
        exit(1);
    };
    //初始化顶点数组里的内容
    for(int i=0;i<maxVertices;i++)
        //把每个边链表的手指指针初始化为空
        NodeTable[i].adj=NULL;
};
/////////////////////////////////默认构造函数结束
#3
geninsf0092008-12-07 20:25
/////////////////////////////////////////////////
//析构函数
//释放所有的边链表的内存以及结点数组的内存
/////////////////////////////////////////////////
template<class T,class E>
Graphlink<T,E>::~Graphlink()
{
    //首先遍历每条边链表的首结点
    for(int i=0;i<numVertices;i++)
    {
        Edge<T,E>*& ptr=NodeTable[i].adj;//游标指针
        Edge<T,E>* pre;                  //前个边结点的指针
        while(ptr!=NULL)
        {
            pre=ptr;                     //保留当前边结点
            ptr=ptr->link;               //指向下个边结点
            delete  pre;                 //释放结点内存
        };
    };
};
/////////////////////////////////////析构函数结束
#4
geninsf0092008-12-07 20:26
/////////////////////////////////////////////////
//getWeight()公有成员函数
//得到指定边(v1,v2)上的权值
/////////////////////////////////////////////////
template<class T,class E>
E Graphlink<T,E>::getWeight(int v1,int v2)
{
    Edge<T,E>* ptr=NodeTable[v1].adj;//得到v1结点的边链表的首指针
    while(ptr!=NULL)                 //遍历该边链表找结点v2
    {
        if(ptr->dest==v2)            //如果找到就返回
            return ptr->cost;
        ptr=ptr->link;
    }
    return maxWeight;                //即这两点之间不存在边
};
//////////////////////getWeight()公有成员函数结束
#5
geninsf0092008-12-07 20:26
/////////////////////////////////////////////////
//insertVertex()公有成员函数
//在图中插入一个顶点
/////////////////////////////////////////////////
template<class T,class E>
bool Graphlink<T,E>::insertVertex(const T vertex)
{
    if(numVertices<maxVertices)      //结点表不满则插入新结点
    {
         NodeTable[numVertices++].data=vertex;
        return true;                 //插入成功
    }
    else
        return false;                //表满插入失败
};
///////////////////////////insertVertex()函数结束
#6
geninsf0092008-12-07 20:26
/////////////////////////////////////////////////
//removeVertex()公有成员函数
//在图中删除指定结点号的结点v,也删除和v关联的边
/////////////////////////////////////////////////
template<class T,class E>
bool Graphlink<T,E>::removeVertex(int v)
{
    if(v<0 || v>=numVertices)       //如果给出的结点号不存在
        return false;
    /*首先删除和结点v相关联的边链表*/
    Edge<T,E>* ptr=NodeTable[v].adj;//游标指针
    Edge<T,E>* pre;                 //指向释放的前一个结点
    while(ptr!=NULL)                //释放边链表中所有结点
    {
        pre=ptr;
        ptr=ptr->link;
        delete pre;
        numEdges--;                 //每删去一个边结点,numEdges减1
    };
    NodeTable[v].adj=NULL;          //该与结点的边链表置空

    /*在其他的边链表中也对称删除dest为v的边结点*/
    for(int i=0;i<numVertices;i++)  //遍历每一个边链表
    {
        ptr=NodeTable[i].adj;       //取得每个边链表的首指针
        if(ptr==NULL)               //如果边链表是空的
            continue;
        else if(ptr!=NULL           //如果是在头部删除
            && ptr->dest==v)
        {
            NodeTable[i].adj=ptr->link;
            delete ptr;
        }
        else
        {
            while(ptr->link!=NULL)
            {
                if(ptr->link->dest==v)
                {                   //如果找到该结点
                    pre=ptr->link;
                    ptr->link=ptr->link->link;
                    delete pre;
                    break;
                };
                ptr=ptr->link;      //指针向后推进一格
            };
        };
    };
    /*把NodeTable中的最后一个元素填补到v对应的位置*/
    NodeTable[v].data=NodeTable[numVertices-1].data;
    NodeTable[v].adj=NodeTable[numVertices-1].adj;
    NodeTable[numVertices-1].adj=NULL;
   
    /*把所有的原来结点号是numVertices-1的结点
    的结点号改为v*/
    int p=numVertices-1;            //原来最后一个结点的结点号
    for(i=0;i<numVertices-1;i++)    //遍历所有的边链表
    {
        ptr=NodeTable[i].adj;       //游标指针
        while(ptr!=NULL)            //遍历每个边结点
        {
            if(ptr->dest==p)        //原来目的结点是p的
                ptr->dest=v;        //现在改为v
            ptr=ptr->link;
        };
    };
    numVertices--;                  //结点的个数减1
    return true;                    //删除成功
};
///////////////////////////removeVertex()函数结束
#7
geninsf0092008-12-07 20:27
/////////////////////////////////////////////////
//insertEdge()公有成员函数  
//在结点v1和v2之间建立一条边,同时对称建立边链表结点
/////////////////////////////////////////////////
template<class T,class E>
bool Graphlink<T,E>::insertEdge(int v1,int v2,E cost)
{
    if(v1<0 || v2<0 || v1>=numVertices || v2>=numVertices)
        return false;
    /*在v1的边链表中插入v2*/
    Edge<T,E>* ptr=NodeTable[v1].adj;         //游标指针
    Edge<T,E>* newEdge1=new Edge<T,E>(v2,cost);//新建边链表
    
    if(NodeTable[v1].adj==NULL)               //如果边链表本来是空的
    {
        NodeTable[v1].adj=newEdge1;
    }
    else if(v2<NodeTable[v1].adj->dest)       //在头部插入
    {
        newEdge1->link=NodeTable[v1].adj;
        NodeTable[v1].adj=newEdge1;
    }
    else
    {
        while(ptr->link!=NULL)                //寻找位置插入
        {
            if(ptr->dest<v2 && ptr->link->dest>v2)
            {
                newEdge1->link=ptr->link;
                ptr->link=newEdge1;
                break;
            }
            ptr=ptr->link;
        };
        if(ptr->link==NULL)                   //如果在尾部插入
            ptr->link=newEdge1;
    };
    /*在v2的边链表中插入v1*/
    ptr=NodeTable[v2].adj;
    Edge<T,E>* newEdge2=new Edge<T,E>(v1,cost);//新建边链表
    
    if(NodeTable[v2].adj==NULL)               //如果边链表本来是空的
    {
        NodeTable[v2].adj=newEdge2;
    }
    else if(v1<NodeTable[v2].adj->dest)       //在头部插入
    {
        newEdge2->link=NodeTable[v2].adj;
        NodeTable[v2].adj=newEdge2;
    }
    else
    {
        while(ptr->link!=NULL)                //寻找位置插入
        {
            if(ptr->dest<v1 && ptr->link->dest>v1)
            {
                newEdge2->link=ptr->link;
                ptr->link=newEdge2;
                break;
            }
            ptr=ptr->link;
        };
        if(ptr->link==NULL)                   //如果在尾部插入
            ptr->link=newEdge2;
    };
    numEdges++;                               //边数加1
    return true;
};
/////////////////////insertEdge()公有成员函数结束
#8
geninsf0092008-12-07 20:27
/////////////////////////////////////////////////
//removeEdge()公有成员函数
//删除图中指定的一条变
/////////////////////////////////////////////////
template<class T,class E>
bool Graphlink<T,E>::removeEdge(int v1,int v2)
{
    if(v1<0 || v1>=maxWeight              //如果v1和v2是合法的
    || v2<0 || v2>=maxWeight)
        return false;                     //删除失败
    Edge<T,E>* ptr;                       //游标指针
    Edge<T,E>* pre;                       //前一个结点

    /*在v1的边链表中删除边结点v2*/
    ptr=NodeTable[v1].adj;                //v1边链表的首指针
    if(NodeTable[v1].adj==NULL)           //比边链表是空的
        return false;                     //删除失败
    else if(NodeTable[v1].adj->dest==v2)  //如果是在头部删
    {                                     //删除结点
        pre=NodeTable[v1].adj;
        NodeTable[v1].adj=NodeTable[v1].adj->link;
        delete pre;
    }
    else                                  //如果是在头结点以外结点删除
    {
        int flag=0;                       //是否有结点删除
        while(ptr->link!=NULL)            //寻找要删除的v2边结点
        {
            if(ptr->link->dest==v2)       //删除v2边结点
            {
                flag=1;                  
                pre=ptr->link;
                ptr->link=ptr->link->link;
                delete pre;
                break;
            };
            ptr=ptr->link;                //指针向后推进一格
        };
        if(flag==0)                       //如果没有找到边结点v2
        {
            cout<<"该边不存在!"<<endl;
            return false;                 //该边不存在删除失败
        };
    };
    /*在v2的边链表中删除边结点v1*/
    ptr=NodeTable[v2].adj;                //v1边链表的首指针
    if(NodeTable[v2].adj==NULL)           //比边链表是空的
        return false;                     //删除失败
    else if(NodeTable[v2].adj->dest==v1)  //如果是在头部删
    {                                     //删除结点
        pre=NodeTable[v2].adj;
        NodeTable[v2].adj=NodeTable[v2].adj->link;
        delete pre;
    }
    else                                  //如果是在头结点以外结点删除
    {
        int flag=0;                       
        while(ptr->link!=NULL)            //寻找要删除的v2边结点
        {
            if(ptr->link->dest==v1)       //删除v2边结点
            {
                flag=1;
                pre=ptr->link;
                ptr->link=ptr->link->link;
                delete pre;
                break;
            };
            ptr=ptr->link;                //指针向后推进一格
        };
        if(flag==0)        
            //该边不存在
            return false;                 //删除失败
    };
    numEdges--;                           //边的个数减1
    return true;
};
/////////////////////////////removeEdge()函数结束
#9
geninsf0092008-12-07 20:27
/////////////////////////////////////////////////
//getFirstNeighbor()公有成员函数
//得到指定结点v的第一个相邻的结点
/////////////////////////////////////////////////
template<class T,class E>
int Graphlink<T,E>::getFirstNeighbor(int v)
{
    if(v>=0 && v<numVertices)         //如果指定的结点存在
    {
        Edge<T,E>* p=NodeTable[v].adj;//边链表的首结点指针
        if(p!=NULL)
            return p->dest;
        else
            return -1;
    }
    else
        return -1;
};
///////////////////////getFirstNeighbor()函数结束
#10
geninsf0092008-12-07 20:28
/////////////////////////////////////////////////
//getNextNeighbor()公有成员函数
//得到当前结点v的邻接顶点w下个邻接顶点的顶点号
/////////////////////////////////////////////////
template<class T,class E>
int Graphlink<T,E>::getNextNeighbor(int v,int w)
{
    if(v>=0 && v< maxWeight             //如果结点号合法
    && w>=0 && w< maxWeight)
    {
        Edge<T,E>* ptr=NodeTable[v].adj;//获得和结点v对应的边链表的首指针
        while(ptr!=NULL)                //遍历该边链表对应的多有的边结点
        {
            if(ptr->dest==w)            //如果找到目的结点为w的边结点
                break;                  //结束查找
            ptr=ptr->link;
        };
        if(ptr!=NULL && ptr->link!=NULL)//如果ptr和ptr的下个结点都不空
            return ptr->link->dest;
        else
            return -1;                  //这样的结点不存在,查找失败
    }
    else
        return -1;
};
////////////////////////getNextNeighbor()函数结束
#11
geninsf0092008-12-07 20:28
/////////////////////////////////////////////////
//DFS()私有成员函数
//递归:深度优先遍历图所有结点,start是起始结点
/////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::DFS(int start)
{
    cout<<getValue(start)<<" ";      //访问当前的起始结点
    visited[start]=true;             //把对应的访问标志置为"已访问"

    int p=getFirstNeighbor(start);   //获取start的第一个邻接结点
    while(p!=-1)                     //递归访问start的所有邻接结点
    {
        if(visited[p]==false)        //如果neighbor没有被访问过
            DFS(p);                  //以neighbor为当前结点继续递归访问
        p=getNextNeighbor(start,p);  //获取下个邻接结点的结点号
    };
};
////////////////////////////DFS()私有成员函数结束
#12
geninsf0092008-12-07 20:28
/////////////////////////////////////////////////
//DFSGraphic()公有成员函数
//深度优先遍历图所有结点,通过键盘输入起始结点
/////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::DFSGraphic(int start)
{
    visited=new bool[numVertices];
    for(int i=0;i<numVertices;i++)
        visited[i]=false;//把每个结点的访问标志置为否

    cout<<endl<<"深度优先遍历的结果是:"<<endl;
    if(start>=0 && start<numVertices)
         DFS(start);      //如果输入的结点号合法就开始遍历
    else
        exit(1);
    delete [] visited;   //释放标记数组的内存空间
};
/////////////////////DFSGraphic()公有成员函数结束
#13
geninsf0092008-12-07 20:28
/////////////////////////////////////////////////
//BFSGraphic()公有成员函数
/////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::BFSGraphic()
{
    cout<<"请输入遍历的起始顶点号:";
    int start;                         //起始的结点号
    cin>>start;
    visited=new bool[numVertices];     //开辟标记数组的内存空间
    for(int i=0;i<numVertices;i++)
        visited[i]=false;              //把标记数组置为未访问
    LinkedQueue<int> Q;                //用于存放结点号的队列
    Q.EnQueue(start);                  //首先把起始顶点的标号压入队列
    if(start<0 || start>=numVertices)  //如果起始的结点号不合法
        exit(1);
    int p;                             //当前正在访问的顶点的顶点号
    int q;                             //所有邻接结点的游标指针

    while(!Q.IsEmpty())                //按层次遍历图的所有顶点
    {
        Q.DeQueue(p);                  //从队列中取出一个结点
        if(visited[p]==false)          //如果不曾被访问
        {
            cout<<getValue(p)<<" ";    //访问该结点
            visited[p]=true;           //已经被访问过
            q=getFirstNeighbor(p);     //获取当前访问结点的第一个邻接结点
            while(q!=-1)               //把所有的未被访问过的邻接结点全部送入队列
            {
                if(visited[q]==false)
                    Q.EnQueue(q);      //如果没有被访问过就压入队列
                q=getNextNeighbor(p,q);//获取下个邻接结点号
            };
        };
    };
    delete [] visited;                 //释放标记数组的内存空间
};
/////////////////////////BFSGraphic()公有函数结束
#14
geninsf0092008-12-07 20:29
/////////////////////////////////////////////////
//Find_Connected_Component()公有成员函数
//寻找当前图的所有的连通分量(极大连通子图)
/////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::Find_Connected_Component()
{
    visited=new bool[numVertices];    //开辟标记数组的空间
    for(int i=0;i<numVertices;i++)
        visited[i]=false;             //标记全部初始化为未被访问
    cout<<"所有连通分量顶点的集合如下:";
    cout<<endl;
    for(i=0;i<numVertices;i++)
    {
        if(visited[i]==false)         //如果没有被访问,则可以顺次找出
        {
            DFS(i);                   //连通分量
            cout<<endl;
        }
    };
    delete [] visited;
};
///////Find_Connected_Component()公有成员函数结束
#15
geninsf0092008-12-07 20:29
/////////////////////////////////////////////////
//DFSTree()公有成员函数
//递归:得到当前图的深度优先生成树的算法
//其中该树采用FirstChild-NextSibling存储结束
//v是遍历起始的顶点,subTree是以v为当前顶点的生成子树
/////////////////////////////////////////////////
template<class T,class E>
TreeNode<T>* Graphlink<T,E>::DFSTree(int v)
{
    T value=getValue(v);                 //通过结点v创建一个树的结点
    TreeNode<T>* subTree;
    subTree=new TreeNode<T>(value);      //作为当前生成子树的根结
    visited[v]=true;                     //当前结点v已经访问过

    int flag=1;                          //判断是否是长子结点
    TreeNode<T>* ptr=NULL;               //获取长子树的树根
    TreeNode<T>* pre=NULL;               //保留前棵兄弟子树的根结点

    for(int p=getFirstNeighbor(v);       //递归遍历v的所有未访问的邻接结点
        p!=-1;p=getNextNeighbor(v,p))
    {                                    
        if(visited[p]==false)            //如果邻接点p还未被访问过
        {
            ptr=DFSTree(p);              //递归生成一棵子树
            if(flag==1)                  //如果是长子结点
            {
                subTree->firstChild=ptr;
                flag=0;                  //标志表示已经不是长子结点
            }
            else
                pre->nextSibling=ptr;    //接到前面的子树的后面
            pre=ptr;
        };
    };
    return subTree;                      //返回根结点指针
};
////////////////////////////////DFSTree()函数结束
#16
geninsf0092008-12-07 20:30
/////////////////////////////////////////////////
//DisplayDFSTree()公有成员函数
//调用上面的DFSTree()递归函数求当前图的深度优先生成树
/////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::DisplayDFSTree(int v)
{
    visited=new bool[numVertices];
    for(int i=0;i<numVertices;i++)
        visited[i]=false;
    cout<<"先根遍历以"<<getValue(v)
        <<"为起点的深度优先生成树:";
    Tree<T> T;             //定义一棵空树
    T.setRoot(DFSTree(v)); //设置根结点
    T.pre();               //先根遍历该树
    cout<<endl<<"深度优先生成树是:";
    T.Display();
    cout<<endl;
    cout<<"广度优先遍历的结果是:";
    T.levelOrder();

    delete [] visited;
};
/////////////////////////DisplayDFSTree()函数结束
#17
geninsf0092008-12-07 20:30
/////////////////////////////////////////////////
//DisplayDFSTree()公有成员函数
//调用上面的DFSTree()递归函数求当前图的深度优先生成树
/////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::DisplayDFSTree(int v)
{
    visited=new bool[numVertices];
    for(int i=0;i<numVertices;i++)
        visited[i]=false;
    cout<<"先根遍历以"<<getValue(v)
        <<"为起点的深度优先生成树:";
    Tree<T> T;             //定义一棵空树
    T.setRoot(DFSTree(v)); //设置根结点
    T.pre();               //先根遍历该树
    cout<<endl<<"深度优先生成树是:";
    T.Display();
    cout<<endl;
    cout<<"广度优先遍历的结果是:";
    T.levelOrder();

    delete [] visited;
};
/////////////////////////DisplayDFSTree()函数结束
#18
geninsf0092008-12-07 20:30
/////////////////////////////////////////////////
//DisplayDFSTree()公有成员函数
//调用上面的DFSTree()递归函数求当前图的深度优先生成树
/////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::DisplayDFSTree(int v)
{
    visited=new bool[numVertices];
    for(int i=0;i<numVertices;i++)
        visited[i]=false;
    cout<<"先根遍历以"<<getValue(v)
        <<"为起点的深度优先生成树:";
    Tree<T> T;             //定义一棵空树
    T.setRoot(DFSTree(v)); //设置根结点
    T.pre();               //先根遍历该树
    cout<<endl<<"深度优先生成树是:";
    T.Display();
    cout<<endl;
    cout<<"广度优先遍历的结果是:";
    T.levelOrder();

    delete [] visited;
};
/////////////////////////DisplayDFSTree()函数结束
#19
geninsf0092008-12-07 20:31
/////////////////////////////////////////////////
//DFSForest()公有成员函数
//如果图是非连通的,则求其深度优先生成森林
//即每个连通分量的深度优先树构成的森林
/////////////////////////////////////////////////
template<class T,class E>
TreeNode<T>* Graphlink<T,E>::DFSForest(int v)
{
    visited=new bool[numVertices];
    for(int i=0;i<numVertices;i++)
        visited[i]=false;            //标志数组清为未访问
    TreeNode<T>* root;               //森林的根
    TreeNode<T>* ptr;                //游标指针
    TreeNode<T>* pre;                //前一棵生成树树的根结点
    int flag=1;                      //是否是森林里的第一棵树的标志
    for(int p=0;p<numVertices;p++)   //试着以每个结点开始寻找每个连通分量
    {                                //的深度优先生成树
        if(visited[p]==false)
        {
            ptr=DFSTree(p);          //找出以p为根的连通分量的深度优先生成树
            if(flag==1)              //是森林里的第一棵树
            {
                root=ptr;            //把ptr作为森林的根
                flag=0;
            }
            else
                pre->nextSibling=ptr;//把树连接入前面已经形成的森林中
            pre=ptr;                 //保留前棵树的根结点
        };
    };
    delete [] visited;
    return root;
};
//////////////////////////////DFSForest()函数结束
#20
geninsf0092008-12-07 20:31
/////////////////////////////////////////////////
//getFirstUnvisit()公有成员函数
//得到p的第一个邻接的结点
/////////////////////////////////////////////////
template<class T,class E>
int Graphlink<T,E>::getFirstUnvisit(int p,bool* visited)
{
    Edge<T,E>* ptr=NodeTable[p].adj; //获得p的边链表的头指针
    while(ptr!=NULL)                 //搜索该边链表
    {
        int des=ptr->dest;           //获得每条边的目的结点号
        if(visited[des]==false)      //如果第一个碰到一个未访问的
            return des;              //返回结点号
        ptr=ptr->link;
    };
    return -1;                       //没有找到就返回-1
};
////////////////////////getFirstUnvisit()函数结束

/////////////////////////////////////////////////
//getNextUnvisit()公有成员函数
//得到p的w之后的未访问的邻接结点号
/////////////////////////////////////////////////
template<class T,class E>
int Graphlink<T,E>::getNextUnvisit(int p,int v,bool* visited)
{
    Edge<T,E>* ptr=NodeTable[p].adj;//获得p的边链表的首指针
    int flag=0;                     //判断是否已经找到v
    while(ptr!=NULL)                //搜索边链表中v的指针
    {
        int des=ptr->dest;          //获得每条边的目的结点号
        if(des==v)                  //如果找到
        {
            flag=1;                 //已经找到
            break;
        }
        ptr=ptr->link;
    };
    if(flag==0)                     //边链表中连v都没有
        return -1;
    ptr=ptr->link;                  //指向v后的第一个结点
    while(ptr!=NULL)                //从边结点v后的第一个结点开始搜索
    {
        int des=ptr->dest;          //搜索v后的第一个未被访问的邻接结点
        if(visited[des]==false)
            return des;
        ptr=ptr->link;
    };
    return -1;
};
/////////////////////////getNextUnvisit()函数结束
#21
geninsf0092008-12-07 20:31
/////////////////////////////////////////////////
//DepthFirst()公有成员函数
//采用非递归的方式深度遍历当前图
/////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::DepthFirst(int start)
{
    visited=new bool[numVertices];   //是否被访问过的标记
    for(int i=0;i<numVertices;i++)
        visited[i]=false;

    LinkedStack<int> Stack;          //回溯过程中用到的堆栈
    int p=start;                     //指向当前的结点
    int parent=-1;                   //指向当前结点的遍历父结点
    int first;                       //存放获取长子结点号
    int next;                        //存放下个兄弟结点的地址
    do
    {
        cout<<getValue(p)<<" ";                //访问当前结点p
        visited[p]=true;                       //设置已经访问过

        first=getFirstNeighbor(p);             //获取当前访问结点p的未访问过的第一个邻接结点号
        while(first!=-1 && visited[first]==true)
            first=getNextNeighbor(p,first);    //继续看下个邻接结点
 
        if(first!=-1)                          //如果不是根结点而且长子结点不空
        {
            if(p==start)                       //如果当前访问的结点是根结点
                next=-1;                       //则没有下个兄弟结点
            else
            {
                next=getNextNeighbor(parent,p);//寻找p之后第一个未被访问的第一个兄弟结点
                while(next!=-1 && visited[next]==true)
                    next=getNextNeighbor(parent,next);
            };
            
            if(next!=-1)                       //如果p的下个兄弟结点存在,且不在堆栈中
            {
                Stack.Push(parent);            //先把父结点压入堆栈
                Stack.Push(next);              //再把该下个兄弟结点压入堆栈
            };
            parent=p;
            p=first;                           //下个结点
        }
        else                                   //如果长子结点是空的
        {
            if(p==start)                       //如果就是根结点
                break;                         //推出遍历循环
            else
            {
                do
                {
                    Stack.Pop(p);              //从堆栈中弹出一个结点作为下个结点
                    Stack.Pop(parent);         //从堆栈中同时获得
                }
                while(visited[p]!=false);      //弹出的结点如果是已经访问过的,就继续弹
            };
        };
    }while(first!=-1 || !Stack.IsEmpty());     //如果堆栈和长子结点都空了,说明遍历结束
};
/////////////////////////DepthFirst()公有函数结束
#22
geninsf0092008-12-07 20:32
/////////////////////////////////////////////////
//Dijkstra()公有成员函数,Dijkstra求最短路径的算法
//求当前图中从结点v出发到其它所有顶点的路径长度
//T是关键码的数据类型,E是路径长度的数据类型
/////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::Dijkstra(int v)
{
    /*初始化工作*/
    int n=numVertices;         //图的当前顶点的个数
    E* dist=new E[n];          //定义存放最短路径长度的数组
    Path=new int[n];           //开辟最短路径数组的空间
    for(int i=0;i<n;i++)
        dist[i]=maxWeight;
    bool* s=new bool[n];       //当前已经求出最短路径的顶点集合
    for(i=0;i<n;i++)
        s[i]=false;            //初始并未全部加入
    if(v>=n)                   //如果开始的结点号溢出
        return;
    for(i=0;i<=n-1;i++)        //对dist[]数组进行初始化
    {
        dist[i]=getWeight(v,i);//把所有开始与v相邻接的边的长度加入dist[]
        if(dist[i]<maxWeight
            && dist[i]!=0)     //把当前处理的顶点的前驱顶点放入Path[]数组   
            Path[i]=v;
        else
            Path[i]=-1;
    }
    s[v]=true;                 //先把结点v加入到集合中去
    dist[v]=0;
    /*依次把图中其他
    的结点加入s求
    出他它们的最短
    路径*/
    int count=1;
    int min;                   //求当前dist[]数组中的最小值
    int k;                     //存放当前从dist[]找出的最小值的标号
    for(int p=1;p<=n-1;p++)    //一共有n-1个顶点要陆续加入到s中
    {
        int isfirst=1;
        /*找要加入s的结点即
        当dist[]中权最小点*/
        for(i=0;i<=n-1;i++)    //遍历dist[]数组
        {
            if(s[i]!=true
                && isfirst==1) //如果结点i还没有加进s
            {
                min=dist[i];
                k=i;
                isfirst=0;
                continue;
            };
            if(s[i]!=true && dist[i]<min)
            {
                min=dist[i];   //找权值最小的及其标号
                k=i;
            };
        };
        s[k]=true;             //把找到的k加入到s中去
        /*修改dist[]数组的值*/
        for(i=0;i<=n-1;i++)
        {
            if(s[i]!=true)     //如果结点i还没有被加入s
            {                  //则需要被修改
                if(dist[i]>dist[k]+getWeight(k,i))
                {
                    dist[i]=dist[k]+getWeight(k,i);
                    Path[i]=k; //把顶点i的当前最短路径上的前驱加入Path[]中
                };
            };
        };
    };
    /*显示生成的每条最短路径*/
    DisplayPath(v,dist);
    /*释放辅助的存储空间*/
    delete [] dist;
    delete [] Path;
};
/////////////////////////////////Dijkstra()函数结束

///////////////////////////////////////////////////
//DisplayPath()公有成员函数
//显示当前图的从定点v到其他定点的所有最短路径
//即把当前Path数组中的最短路径显示出来
///////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::DisplayPath(int v,E* d)
{
    int n=numVertices;
    for(int i=0;i<n;i++)       //遍历除v以外的所有的定点
    {
        if(i!=v)               //显示从v到i的最短路径
        {
            cout<<"从"<<i<<"到"<<v<<"的最短路径:";
            cout<<"其长度是:"<<d[i]<<';'<<"路径是:";
            int p=i;           //游标指针从v开始
            cout<<'{'<<p<<"<-";
            do
            {
                cout<<Path[p]; //显示 最短路径的前驱
                p=Path[p];
                if(p!=v)
                    cout<<"<-";//路径上的最后一个结点不需要显示','
            }while(p!=v);      //到i表示循环结束
            cout<<'}';
        };
        cout<<endl;
    };
};
////////////////////////////DisplayPath()函数结束
#23
geninsf0092008-12-07 20:32
/////////////////////////////////////////////////
//友元重载<<输出运算符
/////////////////////////////////////////////////
template<class T,class E>
ostream& operator<<(ostream& os,Graphlink<T,E>& G)
{
    cout<<"当前图的内容是:"<<endl;
    Edge<T,E>* ptr;
    for(int i=0;i<G.numVertices;i++)
    {
        cout<<"第"<<i<<"个顶点"<<T(G.NodeTable[i].data)<<"边结点:";
        ptr=G.NodeTable[i].adj;
        while(ptr!=NULL)
        {
            cout<<"("<<ptr->dest<<","<<ptr->cost<<")"<<" ";
            ptr=ptr->link;
        };
        cout<<endl;
    };
    cout<<"当前图的总结点数是:"<<G.numVertices<<endl;
    cout<<"当前图的总边的个数:"<<G.numEdges<<endl;
    return os;
};
///////////////////////////////////<<友元重载结束
#24
geninsf0092008-12-07 20:33
/////////////////////////////////////////////////
//友元重载>>输入运算符
/////////////////////////////////////////////////
template<class T,class E>
istream& operator>>(istream& is,Graphlink<T,E>& G)
{
    cout<<"通过键盘输入输入顶点和边";
    cout<<"请输入顶点的个数:";
    is>>G.numVertices;
    cout<<endl;
    for(int i=0;i<G.numVertices;i++)
    {
        cout<<"请输入第"<<i<<"个结点的数据内容:";
        is>>G.NodeTable[i].data;
    };
    cout<<"请输入边的个数:";
    is>>G.numEdges;
    cout<<endl;
    int v1,v2;
    E weight;
    for(i=0;i<G.numEdges;i++)
    {
        cout<<"输入起点:";
        is>>v1;
        cout<<"输入终点:";
        is>>v2;
        cout<<"输入权值:";
        is>>weight;
        G.insertEdge(v1,v2,weight);
        cout<<endl;
    }
    return is;
};
/////////////////////////////>>输入运算符重载结束
#25
geninsf0092008-12-07 20:33
/////////////////////////////////////////////////
//DFSArticul()公有成员函数
//递归:从v0出发,通过深度优先遍历当前图,
//查找并输出该深度优先生成树上的所有关节点
//算法描述概要:定义了dfn[]函数,存放结点的DFS遍历
//序数,low[]函数存放通过,当前结点可以
/////////////////////////////////////////////////
template<class T,class E>
int Graphlink<T,E>::DFSArticul(int v0,int* dfn,int* low)
{
    static int count=0;        //得到DFS序数的计数器
    count++;                  
    int min=count;             //当前访问的结点v0的DFS序数
    dfn[v0]=count;             //得到当前访问顶点的DFS序数
    for(int ptr=getFirstNeighbor(v0)  
        ;ptr!=-1               //遍历结点v0所有的邻接结点
        ;ptr=getNextNeighbor(v0,ptr))
    {
        int w=ptr;             //w是v0的邻接结点,w也是v0的子结点
        if(dfn[w]==0)          //如果v0的子结点w没有被访问过
        {
            DFSArticul(        //递归:对以w为开始顶点的子图进行递归求关节点
                w,dfn,low);
            if(low[w]<min)     //退出递归以后,如果子结点u能达到的顶点DFS序数比
                min=low[w];    //比v0能达到的更小
            if(low[w]>=dfn[v0])//如果子结点u所能到达的顶点的DFS序数还没有v0大
                cout<<v0<<":"  //说明v0就是一个关节点
                <<getValue(v0)
                <<"是一个关节点."<<endl;
        }
        else if(dfn[w]<min)    //如果w的DFS序数比当前v0的最小回边系数更小
            min=dfn[w];        //说明w已经在v0之前访问过了<v0,w>是一条回边
    }
    low[v0]=min;               //得到当前结点v0的low[]函数值
    return count;              //返回当前遍历过的顶点的个数
};
/////////////////////DFSArticul()公有成员函数结束

/////////////////////////////////////////////////
//FindArticul()公有成员函数
//调用DFSArticul()函数找出当前图的
//所有的关节点,并显示出来,思想:首先判断根结点
//是否有多于一个子树,如果是说明根也是关节点,然后
//以根的每棵子树根结点为起点继续找关节点
/////////////////////////////////////////////////
template<class T,class E>
void Graphlink<T,E>::FindArticul()
{
    int n=numVertices;
    int* dfn=new int[n];        //dfn[]函数的数组
    int* low=new int[n];        //low[]函数的数组
    for(int i=0;i<n;i++)        //初始化dfn[]函数
        dfn[i]=0;
    dfn[0]=1;                   //以0号顶点为遍历的根结点
    int p=getFirstNeighbor(0);  //获取根结点0的第一个子结点
    int k=DFSArticul(p,dfn,low);//对第一棵子树进行寻找,得到第一棵子树顶点个数
    if(k!=n-1)                  //如果顶点个数不是总顶点数-1
    {                           //怎说明根结点是关节点
        cout<<0<<":"<<getValue(0)
            <<"是一个关节点."<<endl;
        p=getNextNeighbor(0,p); //获得子树p的兄弟子树
        while(p!=-1)            //对其他的子树进行再次的关节点寻找
        {
            if(dfn[p]==0)       //如果p还没有被访问过,就从该顶点开始寻找
                DFSArticul(p,dfn,low);
            p=getNextNeighbor(0,p);
        };
    };
};
////////////////////////////FindArticul()函数结束

#endif
#26
xihuazhoujin2010-06-06 22:54
请问老师能否把#include"BaseGraph.h"的内容写出来么???还有,设计一个主函数能否??
谢谢!!
1