示例#1
0
void Graph<Tv, Te>::DFS(int v, int &clock){   //深度优先搜索DFS算法(单个连通域)
    dTime(v) = ++clock; status(v) = DISCOVERED;  //发现当前顶点v
    for( int u = firstNbr(v); -1 < u; u = nextNbr(v, u) ){  //枚举v的所有邻居u
        switch(status(u)){
            case UNDISCOVERED://u尚未发现,意味着支撑树可在此拓展
                type(v, u) = TREE; parent(u) = v; DFS(u, clock); break;
            case DISCOVERED:  //u已被发现但未访问完毕, 应属被后代指向的祖先
                type(v, u) = BACKWARD; break;
            default: //u已访问完毕(VISITED, 有向图), 则视承袭关系分为前向边或跨边
                type(v, u) = (dTime(v) < dTime(u) ) ? FORWARD : CROSS; break; 
        }
    }
    status(v) = VISITED; fTime(v) = ++clock; //至此,当前顶点v方告访问完毕
}
示例#2
0
int outDegree(int i) {return V[i].outDegree};//出度
VStatus & status(int i) {return V[i].status;}//状态
int & dTime(int i) {return V[i].dTime;}//时间标签dTime
int & fTime(int i) {return V[i].fTime;}//时间标签fTime
int & parent(int i) {return V[i].parent;}//在遍历树中的父亲
int & priority (int i) {return V[i].priority;}//优先函数

int nextNbr( int i, int j ){//若已枚举至邻居j,则转向下一邻居
    while ( (-1 < j) && !exists(i, --j) );//逆向顺序查找,O(n)
    return j;
}//改用邻接表可提高至O(1+outDegree(i) )

int firstNbr( int i ){
    return nextNbr( i, n );//假想哨兵
}//首个邻居

//边操作
bool exists (int j, int j){//判断边(i, j)是否存在
    return (0 <= i) && (i < n) && (0 <= j) && (j < n) && E[i][j] != NULL;
}

Te & edge (int i, int j)//边(i, j)的数据
{return E[i][j]->data;}//O(1)

EType & type(int i; int j)//边(i, j)的类型
{return E[i][j]->type;}//O(1)

int & weight (int j; int j)//边(i, j)的权重
{return E[i][j]->weight;}//O(1)

//边插入
void insert (Te const & edge, int w, int i, int j){//插入(i, j, w)
    if (exists(i, j) ) return;//忽略已有边
    E[i][j] = new Edge<Te> (edge, w);//创建新边
    e++;//更新边计数
    V[i].outDegree++;//更新关联点i的出度
    V[j].inDegree++;//更新关联点j的入度
}

//边删除
Te remove(int i, int j){//删除顶点i和j之间的边(exists(i, j))
    Te eBak = edge(i, j);//备份边(i, j)的信息
    delete E[i][j];
    E[i][j] = NULL;
    e--;//更新计数
    V[i].outDegree--;
    V[j].inDegree--;
    return eBak;//返回删除边的信息
}
示例#3
0
void Graph<Tv, Te>::PFS(int s, PU prioUpdater){  //优先级搜索(单个连通域)
    priority(s) = 0; status(s) = VISITED; parent(s) = -1;  //初始化,起点s加至PFS树中
    while(1){  //将下一顶点和边加至PFS树中
        for(int w = firstNbr(s); -1 < w; w = nextNbr(s, w))  //枚举s的所有邻居w
            prioUpdater(this, s, w); //更新顶点w的优先级及其父顶点
        for(int shortest = INT_MAX, w = 0; w < n; w++)
            if(UNDISCOVERED == status(w))  //从尚未加入遍历树的顶点中
                if(shortest > priority(w)){ //选出下一个
                    shortest = priority(w);
                    s = w;  //优先级最高的顶点s
                }
        if(VISITED == status(s) )
            break;  //直至所有顶点均已加入
        status(s) = VISITED;
        type( parent(s), s ) = TREE;  //将s及与其父的联边加入遍历树
    }
}//通过定义具体的优先级更新策略prioUpdater,即可实现不同的算法功能
示例#4
0
void Graph<Tv, Te>::BFS(int v, int &clock){
    MyQueue<int> Q; //引入辅助队列
    status(v) = DISCOVERED;
    Q.enqueue(v);  //初始化起点
    while(!Q.empty()){  //在Q变空之前,不断
        int v = Q.dequeue(); dTime(v) = ++clock;  //取出队首顶点v
        for(int u = firstNbr(v); -1 < u; u = nextNbr(v, u))  //枚举v的所有邻居
            if(UNDISCOVERED == status(u)){  //尚未被发现,则
                status(u) = DISCOVERED;  //设置为已发现
                Q.enqueue(u);   //并且将该顶点入队
                type(v, u) = TREE;
                parent(u) = v;   //引入树边拓展支撑树
            }else{
                type(v, u) = CROSS; //将(v,u)归类于跨边
            }
        status(v) = VISITED;  //至此,当前节点访问完毕
    }
}
示例#5
0
bool Graph<Tv, Te>::TSort(int v, int &clock, MyStack<Tv> *S){  //assert: 0 <= v < n
    dTime(v) = ++clock;
    status(v) = DISCOVERED;  //发现顶点v
    for(int u = firstNbr(v); -1 < u; u = nextNbr(v, u))  //枚举v的所有邻居u
        switch(status(v)){
            case UNDISCOVERED:
                parent(u) = v; type(v, u) = TREE;
                if( !TSort(u, clock, S))  //从顶点u处出发深入搜索
                    return false;  //若u及其后代不能拓扑程序(则全图亦必如此), 故返回并报告
                break;
            case DISCOVERED:
                type(v, u) = BACKWARD;  //一旦发现后向边(非DAG), 则
                return false; //不必深入,故返回并报告
            default:   //VISITED(digraphs only)
                type(v, u) = (dTime(v) < dTime(u) ) ? FORWARD : CROSS;
                break;
        }
     status(v) = VISITED; S->push(vertex(v) );  //顶点被标记为VISITED时, 随即入栈
     return true; //v及其后代可以拓扑排序
}
示例#6
0
void Graph<Tv, Te>::BCC(int v, int &clock, MyStack<int> &S){  //assert: 0 <= v < n
    hca(v) = dTime(v) = ++clock; status(v) = DISCOVERED; S.push(v); //v被发现并入栈
    for(int u = firstNbr(v); -1 < u; u = nextNbr(v, u))  //枚举v的所有邻居u
        switch(status(u)){  //并视u的状态分别处理
            case UNDISCOVERED:
                parent(u) = v; type(v,u) = TREE; BCC(u, clock, S);  //从顶点u处深入
                if(hca(u) < dTime(v)) //遍历返回后, 若发现u(通过回边)可指向v的真祖先
                    hca(v) = min( hca(v), hca(u) ); //则v亦必如此
                else{  //否则,以v为关节点(u以下即是一个BCC, 且其中顶点此时正集中于栈s的顶部)
                    while( v != S.pop() );  //依次弹出当前BCC中的节点,亦可根据实际需求转存至其他结构
                    S.push(v);  //最后一个顶点(关节点)重新入栈---总计至多两次
                }
                break;
            case DISCOVERED:
                type(v, u) = BACKWARD; //标记(v,u), 并按照"越小越高"的准则
                if( u != parent(v) )
                    hca(v) = min(hca(v), dTime(u));  //更新hca(v)
                break;
            default: //VISITED(digraphs only)
                type(v, u) = (dTime(V) < dTime(u) ? FORWARD : CROSS);
                break;
        }
    status(v) = VISITED;   //对v的访问结束
}