關鍵路徑(C語言)

關於關鍵路徑的一些理解

ltv 若是某時間不完成,會影響後續其它活動的開始)數據結構

lte 若是某時間不開始,則自身的剩餘時間會不夠用,影響後面頂點狀態的完成時間點(從而推遲工期)ide

etv, ltv, ete, lte的運算關係

etv[n] 等於Vn的etv值 加上其後弧權值的和,可能存在多條路徑,取最大值指針

ete 等於 etv[n] 由於etv事件的結束,也是以其弧活動的開始code

ltv[n] 等於Vn的ltv 減去 其弧的權值,可能存在多條路徑,取最小值(也就是之後面最大權值的弧爲活動依據,不然會延期工程)blog

lte 等於 Vn的ltv 減去其弧的權值(用此值和ete比較,若是相等則說明沒有空閒,在工程的關鍵路徑上), 只計算一次排序

實現

圖來自《大話數據結構》
關鍵路徑(C語言)事件

#include <stdio.h>
#include <stdlib.h>
/* 
 * 實現《大話數據結構》p287圖7-9-11 關鍵路徑
 */ 

#define MAXVEX 32

// 邊表節點類型
typedef struct EdgeNode {
    int adjVex;
    int weight; // 弧的權值
    struct EdgeNode *next;
}EdgeNode, *PE;

// 頂點表節點類型
typedef struct VertexNode {
    int in; // 入度
    int data; // 頂點的數據,簡單用數字標識
    PE firstEdge;
}VertexNode, *PV, AdjList[MAXVEX];

// 定義圖
typedef struct {
    AdjList adjList;
    int numVertex, numEdge; // 未使用numEdge
}GraphAdjList, *PG;

// 全局變量
int ete, lte, *etv, *ltv;
int top2; // stack2的棧頂指針
int *stack2; // 複用拓撲排序的代碼,把打印頂點改成入棧操做

void create(PG);
void topological(GraphAdjList);
void display(GraphAdjList);
void criticalPath(GraphAdjList);

void criticalPath(GraphAdjList graph)
{
    int i, gettop, k;
    PE e;
    // 初始化ltv
    ltv = (int *)malloc(sizeof(int)*graph.numVertex);
    for (i=0; i<graph.numVertex; i++) {
        ltv[i] = etv[graph.numVertex-1]; // ltv默認等於etv的最大值,即v9的etv
    }

    // 開始遍歷, 計算ltv
    while (top2 != 0) {
         // 出棧,先輸出的是V9頂點
         gettop = stack2[top2--];

         // 遍歷出棧頂點的邊表節點(V9的無邊表節點,因此不會的進行此循環)
         for (e = graph.adjList[gettop].firstEdge; e; e = e->next) {
            // 保存節點下標
            k = e->adjVex;
            if (ltv[k] - e->weight < ltv[gettop]) // 取最小
                ltv[gettop] = ltv[k] - e->weight;
         }
    }

    // 比較ete lte找到關鍵路徑
    printf("關鍵路徑爲:\n");
    for (i=0; i<graph.numVertex; i++) {
        ete = etv[i]; // 直接賦值
        for (e = graph.adjList[i].firstEdge; e; e=e->next) {
            k = e->adjVex;
            lte = ltv[k] - e->weight;
            if (ete == lte) {
                printf("<%d, %d>len[%d] -> ", i, k, e->weight); // 簡單一些下村即頂點名
            }
        }
    }
    putchar('\n');

}
void display(GraphAdjList graph)
{
    int i, k;
    PE e;
    for (i=0; i<graph.numVertex; ++i) {
        printf("v%d, in %d, arcs:", graph.adjList[i].data, graph.adjList[i].in);
        e = graph.adjList[i].firstEdge;
        while (e) {
            k = e->adjVex;
            printf("->%d", graph.adjList[k].data);
            e = e->next;
        }
        putchar('\n');
    }
}

void topological(GraphAdjList graph)
{
    int i;
    int *stack; // 存放入度非0的頂點下標
    int top; // 棧頂指針下標
    int gettop; // 取棧頂
    int count; // 打印頂點(入度爲0)計算器
    PE e;

    count = 0;
    top = 0; // 0爲表示棧爲空
    stack = (int *)malloc(sizeof(int) * graph.numVertex);
    // 先掃一遍,初始化棧
    for (i=0; i<graph.numVertex; i++) {
        if (graph.adjList[i].in == 0)
            stack[++top] = i;
    }

    // 添加etv stack2初始化
    top2 = 0;
    stack2 = (int *)malloc(sizeof(int) * graph.numVertex);

    etv = (int *)malloc(sizeof(int) * graph.numVertex);
    for (i=0; i<graph.numVertex; i++) {
        etv[i] = 0;
    }

    // 若是存在入度爲0的頂點,則開始處理
    printf("拓撲序列:\n");
    while (top) {
        gettop = stack[top--]; // 出棧,同時更新棧頂指針
        printf("%d ", graph.adjList[gettop].data); // 打印頂點
        // 添加stack2入棧
        stack2[++top2] = gettop;
        count++;

        // 刪除頂點相關的弧(操做爲弧頭頂點入度減1,若是減到0則弧頭頂點入棧)
        e = graph.adjList[gettop].firstEdge;
        while (e) {
            i = e->adjVex;
            if (! --graph.adjList[i].in)
                stack[++top] = i;

            // 添加計算etv邏輯
            // 由於etv初始狀態都是0,因此會依次更新頂點的etv值
            if (etv[gettop] + e->weight > etv[i])
                etv[i] = etv[gettop] + e->weight;

            e = e->next;
        }
    }

    putchar('\n');
    if (count == graph.numVertex)
        printf("拓撲排序成功, 無環\n");
    else
        printf("拓撲排序失敗, 有環\n");

}

void create(PG g)
{
    int i;
    PE e;

    g->numVertex = 10;

    for (i=0; i<g->numVertex; i++) {
        g->adjList[i].data = i; // i即爲頂點名Vi
        g->adjList[i].firstEdge = NULL;
    }

    // 填充鄰接表(添加時順序保持與書中7-9-4一致《大話數據結構》)
    // v0
    g->adjList[0].in = 0;
    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 2;
    e->weight = 4;
    e->next = g->adjList[0].firstEdge;
    g->adjList[0].firstEdge = e;

    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 1;
    e->weight = 3;
    e->next = g->adjList[0].firstEdge;
    g->adjList[0].firstEdge = e;

    // v1
    g->adjList[1].in = 1;
    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 4;
    e->weight = 6;
    e->next = g->adjList[1].firstEdge;
    g->adjList[1].firstEdge = e;

    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 3;
    e->weight = 5;
    e->next = g->adjList[1].firstEdge;
    g->adjList[1].firstEdge = e;

    // v2
    g->adjList[2].in = 1;
    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 5;
    e->weight = 7;
    e->next = g->adjList[2].firstEdge;
    g->adjList[2].firstEdge = e;

    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 3;
    e->weight = 8;
    e->next = g->adjList[2].firstEdge;
    g->adjList[2].firstEdge = e;

    // v3
    g->adjList[3].in = 2;
    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 4;
    e->weight = 3;
    e->next = g->adjList[3].firstEdge;
    g->adjList[3].firstEdge = e;

    // v4
    g->adjList[4].in = 2;
    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 7;
    e->weight = 4;
    e->next = g->adjList[4].firstEdge;
    g->adjList[4].firstEdge = e;

    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 6;
    e->weight = 9;
    e->next = g->adjList[4].firstEdge;
    g->adjList[4].firstEdge = e;

    // v5
    g->adjList[5].in = 1;
    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 7;
    e->weight = 6;
    e->next = g->adjList[5].firstEdge;
    g->adjList[5].firstEdge = e;

    // v6
    g->adjList[6].in = 1;
    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 9;
    e->weight = 2;
    e->next = g->adjList[6].firstEdge;
    g->adjList[6].firstEdge = e;

    // v7
    g->adjList[7].in = 2;
    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 8;
    e->weight = 5;
    e->next = g->adjList[7].firstEdge;
    g->adjList[7].firstEdge = e;

    // v8
    g->adjList[8].in = 1;
    e = (PE)malloc(sizeof(EdgeNode));
    e->adjVex = 9;
    e->weight = 3;
    e->next = g->adjList[8].firstEdge;
    g->adjList[8].firstEdge = e;

    // v9
    g->adjList[9].in = 2;

}

int main(void)
{
    GraphAdjList graph;
    create(&graph);
    display(graph);
    topological(graph);
    criticalPath(graph);

    return 0;
}

outputv8

[root@8be225462e66 c]# gcc criticalPath.c && ./a.out
v0, in 0, arcs:->1->2
v1, in 1, arcs:->3->4
v2, in 1, arcs:->3->5
v3, in 2, arcs:->4
v4, in 2, arcs:->6->7
v5, in 1, arcs:->7
v6, in 1, arcs:->9
v7, in 2, arcs:->8
v8, in 1, arcs:->9
v9, in 2, arcs:
拓撲序列:
0 2 5 1 3 4 7 8 6 9
拓撲排序成功, 無環
關鍵路徑爲:
<0, 2>len[4] -> <2, 3>len[8] -> <3, 4>len[3] -> <4, 7>len[4] -> <7, 8>len[5] -> <8, 9>len[3] ->
[root@8be225462e66 c]#
相關文章
相關標籤/搜索