拓撲排序(求頂點的入度算法)

拓撲排序

實現鄰接鏈表和逆鄰接鏈表兩種求頂點入度的算法,並在拓撲排序算法中應用ios

有:利用逆鄰接表求出各頂點的入度存入數組indegree中
也有:正鄰接表求頂點的入度算法

//算法6.12 拓撲排序

#include <iostream>
using namespace std;

#define MVNum 100                           //最大頂點數
#define OK 1
#define ERROR 0

typedef char VerTexType;

//- - - - -圖的鄰接表存儲表示- - - - -
typedef struct ArcNode{                     //邊結點
    int adjvex;                             //該邊所指向的頂點的位置
    struct ArcNode *nextarc;                //指向下一條邊的指針
}ArcNode;

typedef struct VNode{
    VerTexType data;                        //頂點信息
    ArcNode *firstarc;                      //指向第一條依附該頂點的邊的指針
}VNode, AdjList[MVNum];                     //AdjList表示鄰接表類型

typedef struct{
    AdjList vertices;                       //鄰接表
    AdjList converse_vertices;              //逆鄰接表
    int vexnum, arcnum;                     //圖的當前頂點數和邊數
}ALGraph;
//- - - - - - - - - - - - - - - -

//- - - - -順序棧的定義- - - - -
typedef struct{
    int *base;
    int *top;
    int stacksize;
}spStack;
//- - - - - - - - - - - - - - - -

int indegree[MVNum];                        //數組indegree存放個頂點的入度
spStack S;

//------------棧的相關操做----------------------
void InitStack(spStack &S){
    //初始化棧
    S.base = new int[MVNum];
    if(!S.base)
        exit(1);
    S.top = S.base;
    S.stacksize = MVNum;
}//InitStack

void Push(spStack &S , int i){
    //進棧
    if(S.top - S.base == S.stacksize)
        return;
    *S.top++ = i;
}//Push

void Pop(spStack &S , int &i){
    //出棧
    if(S.top == S.base)
        return;
    i = *--S.top;
}//Pop

bool StackEmpty(spStack S){
    //判斷棧是否爲空
    if(S.top == S.base)
        return true;
    return false;
}//StackEmpty
//-------------------------------------------------

int LocateVex(ALGraph G , VerTexType v){
    //肯定點v在G中的位置
    for(int i = 0; i < G.vexnum; ++i)
        if(G.vertices[i].data == v)
            return i;
        return -1;
}//LocateVex

int CreateUDG(ALGraph &G){
    //建立有向圖G的鄰接表、逆鄰接表
    int i , k;

    cout <<"請輸入總頂點數,總邊數,以空格隔開:";
    cin >> G.vexnum >> G.arcnum;                //輸入總頂點數,總邊數
    cout << endl;

    cout << "輸入點的名稱,如a" << endl;

    for(i = 0; i < G.vexnum; ++i){              //輸入各點,構造表頭結點表
        cout << "請輸入第" << (i+1) << "個點的名稱:";
        cin >> G.vertices[i].data;              //輸入頂點值
        G.converse_vertices[i].data = G.vertices[i].data;
        //初始化表頭結點的指針域爲NULL
        G.vertices[i].firstarc=NULL;
        G.converse_vertices[i].firstarc=NULL;
    }//for
    cout << endl;
    cout << "輸入邊依附的頂點,如a b" << endl;
    for(k = 0; k < G.arcnum;++k){               //輸入各邊,構造鄰接表
        VerTexType v1 , v2;
        int i , j;
        cout << "請輸入第" << (k + 1) << "條邊依附的頂點:";
        cin >> v1 >> v2;                        //輸入一條邊依附的兩個頂點
        i = LocateVex(G, v1);  j = LocateVex(G, v2);
        //肯定v1和v2在G中位置,即頂點在G.vertices中的序號

        ArcNode *p1=new ArcNode;                //生成一個新的邊結點*p1
        p1->adjvex=j;                           //鄰接點序號爲j
        p1->nextarc = G.vertices[i].firstarc;  G.vertices[i].firstarc=p1;
        //將新結點*p1插入頂點vi的邊表頭部

        ArcNode *p2=new ArcNode;                //生成一個新的邊結點*p1
        p2->adjvex=i;                           //逆鄰接點序號爲i
        p2->nextarc = G.converse_vertices[j].firstarc;  G.converse_vertices[j].firstarc=p2;
        //將新結點*p1插入頂點vi的邊表頭部
    }//for
    return OK;
}//CreateUDG

// void FindInDegree(ALGraph G){
//  //利用逆鄰接表求出各頂點的入度存入數組indegree中
//  int i , count;
//
//  for(i = 0 ; i < G.vexnum ; i++){
//      count = 0;
//      ArcNode *p = G.converse_vertices[i].firstarc;
//      if(p){
//          while(p){
//              p = p->nextarc;
//              count++;
//          }
//      }
//      indegree[i] = count;
//  }
// }//FindInDegree
 void FindInDegree(ALGraph G)
 { // 正鄰接表求頂點的入度
   int i;
   ArcNode *p;
   for(i=0;i<G.vexnum;i++)
     indegree[i]=0; // 賦初值
   for(i=0;i<G.vexnum;i++)
   {
     p=G.vertices[i].firstarc;
     while(p)
     {
       indegree[p->adjvex]++;
       p = p->nextarc;
     }
   }
 }

int TopologicalSort(ALGraph G , int topo[]){
    //有向圖G採用鄰接表存儲結構
    //若G無迴路,則生成G的一個拓撲序列topo[]並返回OK,不然ERROR
    int i , m;
    FindInDegree(G);                            //求出各頂點的入度存入數組indegree中
    InitStack(S);                               //棧S初始化爲空
    for(i = 0; i < G.vexnum; ++i)
        if(!indegree[i]) Push(S, i);            //入度爲0者進棧
    m = 0;                                      //對輸出頂點計數,初始爲0
    while(!StackEmpty(S)){                      //棧S非空
        Pop(S, i);                              //將棧頂頂點vi出棧
        topo[m]=i;                              //將vi保存在拓撲序列數組topo中
        ++m;                                    //對輸出頂點計數
        ArcNode *p = G.vertices[i].firstarc;    //p指向vi的第一個鄰接點
        while(p){
            int k = p->adjvex;                  //vk爲vi的鄰接點
            --indegree[k];                      //vi的每一個鄰接點的入度減1
            if(indegree[k] ==0)  Push(S, k);    //若入度減爲0,則入棧
            p = p->nextarc;                     //p指向頂點vi下一個鄰接結點
        }//while
    }//while

    if(m < G.vexnum)  return ERROR;             //該有向圖有迴路
    else return OK;
}//TopologicalSort

int main(){
    cout << "************算法6.12 拓撲排序**************" << endl << endl;
    ALGraph G;
    CreateUDG(G);
    int *topo = new int [G.vexnum];

    cout << endl;
    cout << "有向圖的鄰接表、逆鄰接表建立完成!" << endl << endl;

    if(TopologicalSort(G , topo)){
        cout << "該有向圖的拓撲有序序列爲:";
        for(int j = 0 ; j < G.vexnum; j++){
            if(j != G.vexnum - 1)
                cout << G.vertices[topo[j]].data << " , ";
            else
                cout << G.vertices[topo[j]].data << endl << endl;
        }//for
    }
    else
        cout << "網中存在環,沒法進行拓撲排序!" <<endl << endl;
    return OK;
}//main
相關文章
相關標籤/搜索