圖的拓撲排序

拓撲排序

拓撲排序是對有向無圈圖的頂點的一種排序,它使得如果存在一條從viv_ivjv_j的路徑,那麼在排序中vjv_j出現在viv_i的後面。如果圖含有圈,那麼拓撲排序是不可能的。此外,排序不必是唯一的;任何合理的排序都是可以的。

算法思想

第1種

先找出任意一個沒有入邊的頂點。然後顯示出該頂點,並將它和它的邊一起從圖中刪除。然後對圖的其餘部分應用同樣的方法處理。

僞代碼

void Topsort(Graph G)
{
    int Counter;
    Vertex V, W;

    for(Counter = 0; Counter < NumVertex; Counter++)
    {
        V = FindNewVertexOfIndegreeZero();
        if(V == NotAVertex)
        {
            Error("Graph has a cycle");
            break;
        }
        TopNum[V] = Counter;    // 或打印出
        for each W adjancent to V
            Indegree[W]--;
    }
}

函數FindNewVertexOfIndegreeZero掃描Indegree數組,尋找一個尚未被分配拓撲編號的入度爲0的頂點;因爲其是對Indegree數組的一個簡單的順序掃描,所以每次對它的調用都花費O(V)O(\left | V\right |)的時間.由於有V\left | V\right |這樣的調用,因此該算法的運行時間爲O(V2)O({\left | V\right |}^2)

第2種

首先,對每一個頂點計算它的入度(可以在輸入圖時就計算)。然後將所以入度爲0的頂點放入一個初始爲空的的隊列中。當隊列不空時,刪除一個頂點vv,並將vv鄰接的所有的頂點的入度減1.只要1個頂點的入度將爲0,就把該頂點放入隊列中。此時,拓撲排序就是頂點出隊的順序。

C語言代碼

void Topsort(ALGraph G)
{
    Queue Q;
    int Counter;
    VertexType V;
    ArcNode W;

    Q = CreateQueue(MVNum);
    Counter = 0;

    for (V = 1; V <= G->vexnum; V++)
        if (G->Indegree[V] == 0)
            Enqueue(V, Q);

    while (!IsEmpty(Q))
    {
        V = FrontAndDequeue(Q);
        printf("%d->", V);
        Counter++;

        W = G->vertices[V].firstarc;
        while (W != NULL)
        {
            if (--G->Indegree[W->adjvex] == 0)
                Enqueue(W->adjvex, Q);
            W = W->nextarc;
        }
    }
    printf("^\n");

    if (Counter != G->vexnum)
        printf("Graph has a cycle\n");

    DisposeQueue(Q);
}

如果使用鄰接表,那麼執行這個算法所用的時間爲O(E+V)O(\left | E\right | +\left | V\right | )

完整C語言代碼

#include <stdio.h>
#include <stdlib.h>

#define NotAVertex (-1)
#define MVNum (10) // 最大頂點數
typedef int VertexType;
typedef int ArcType;

typedef struct ArcNode // 邊結點
{
    VertexType adjvex;       // 該邊所指向的頂點的位置
    struct ArcNode *nextarc; // 指向下一條邊的指針
    ArcType weight;          // 邊的權值
} * ArcNode;

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

typedef struct // 鄰接表
{
    AdjList vertices;
    int vexnum, arcnum;  // 圖的當前定點數和邊數
    int Indegree[MVNum]; // 每個頂點的入度
} * ALGraph;

void CreateUDG(ALGraph G)
{
    int i, j;
    int v1, v2;
    ArcNode p1, p2;
    ArcType weight;

    printf("Input vexnum: ");
    scanf("%d", &G->vexnum);
    printf("Input arcnum: ");
    scanf("%d", &G->arcnum);

    // 輸入各點,構造表頭結點表
    for (i = 1; i <= G->vexnum; i++)
    {
        G->vertices[i].firstarc = NULL;
        G->Indegree[i] = 0;
    }

    // 輸入一條邊依附的兩個頂點
    for (j = 0; j < G->arcnum; j++)
    {
        scanf("%d%d%d", &v1, &v2, &weight);
        p1 = (ArcNode)malloc(sizeof(*p1));
        if (p1 == NULL)
            exit(0);
        p1->adjvex = v2;
        p1->weight = weight;
        p1->nextarc = G->vertices[v1].firstarc;
        G->vertices[v1].firstarc = p1;
        G->Indegree[v2] += 1;
        /*p2 = (ArcNode)malloc(sizeof(struct ArcNode));
        p2->adjvex = i;
        p2->nextarc = G->vertices[j].firstarc;
        G->vertices[j].firstarc = p2;
        G->Indegree[v1] += 1;*/
    }
}

ALGraph CreateGraph(void)
{
    ALGraph G;
    G = (ALGraph)malloc(sizeof(*G));
    if (G == NULL)
        exit(0);
    return G;
}

typedef VertexType ElementType;
typedef struct QueueNode *Queue;
struct QueueNode
{
    ElementType Array[MVNum];
    int Capacity;
    int Size;
    int Front;
    int Rear;
};
int IsFull(Queue Q)
{
    return Q->Size == Q->Capacity;
}
int IsEmpty(Queue Q)
{
    return Q->Size == 0;
}

Queue CreateQueue(int Capacity)
{
    Queue Q;
    Q = (Queue)malloc(sizeof(struct QueueNode));
    if (Q == NULL)
        exit(0);
    Q->Capacity = Capacity;
    Q->Size = 0;
    Q->Front = 1;
    Q->Rear = 0;
    return Q;
}

void Enqueue(ElementType X, Queue Q)
{
    if (IsFull(Q))
    {
        printf("The queue is full\n");
        system("pause");
        exit(0);
    }
    Q->Size++;
    if (++Q->Rear == Q->Capacity)
        Q->Rear = 0;
    Q->Array[Q->Rear] = X;
}

void Dequeue(Queue Q)
{
    if (IsEmpty(Q))
    {
        printf("The queue is empty\n");
        system("pause");
        exit(0);
    }
    Q->Size--;
    if (++Q->Front == Q->Capacity)
        Q->Front = 0;
}

ElementType Front(Queue Q)
{
    if (IsEmpty(Q))
    {
        printf("The queue is empty\n");
        system("pause");
        exit(0);
    }
    return Q->Array[Q->Front];
}

ElementType FrontAndDequeue(Queue Q)
{
    if (IsEmpty(Q))
    {
        printf("The queue is empty\n");
        system("pause");
        exit(0);
    }
    Q->Size--;
    return Q->Array[(Q->Front++) % Q->Capacity];
}

void DisposeQueue(Queue Q)
{
    free(Q);
}

void Topsort(ALGraph G)
{
    Queue Q;
    int Counter;
    VertexType V;
    ArcNode W;

    Q = CreateQueue(MVNum);
    Counter = 0;

    for (V = 1; V <= G->vexnum; V++)
        if (G->Indegree[V] == 0)
            Enqueue(V, Q);

    while (!IsEmpty(Q))
    {
        V = FrontAndDequeue(Q);
        printf("%d->", V);
        Counter++;

        W = G->vertices[V].firstarc;
        while (W != NULL)
        {
            if (--G->Indegree[W->adjvex] == 0)
                Enqueue(W->adjvex, Q);
            W = W->nextarc;
        }
    }
    printf("^\n");

    if (Counter != G->vexnum)
        printf("Graph has a cycle\n");

    DisposeQueue(Q);
}

int main()
{
    ALGraph G;
    G = CreateGraph();
    CreateUDG(G);
    Topsort(G);
    system("pause");
    return 0;
}

輸入/輸出

頂點按數字編號,第3個數子爲邊上的權值。

Input vexnum: 7
Input arcnum: 12
1 2 1
1 3 1
3 6 1
7 6 1
5 7 1
2 5 1
1 4 1
2 4 1
5 4 1
4 7 1
4 6 1
4 3 1
1->2->5->4->3->7->6->^
請按任意鍵繼續. . .
發佈了30 篇原創文章 · 獲贊 16 · 訪問量 2971
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章