拓扑排序和关键路径算法实现

一、代码实现

#include <stdio.h>
#include <string.h>
#include <malloc.h>

#define MAX_VEX_NUM 20
#define TRUE 1
#define FALSE 0

#define OK   1
#define ERROR 0

int visited[MAX_VEX_NUM];
typedef int status;
typedef int q_elemtype;
int g_print_stack = 0;

int ve[MAX_VEX_NUM];
int vl[MAX_VEX_NUM];

/* 邻接表的数据结构 */
enum GraphyKind
{
    DG,
    DN,
    UDG,
    UDN
};

struct ArcNode 
{
    int adjvex_no;
    int arcinfo[MAX_VEX_NUM];
    struct ArcNode *nextarc;
};

struct VNode 
{
    char data[3];
    struct ArcNode * firstarc; 
};

struct ALGraphy
{
    int vexnum;
    int arcnum;
    enum GraphyKind kind; 
    struct VNode *HeadNode;
};

/* 链队列的数据结构  */
struct QNode
{
    q_elemtype data; 
    struct QNode *next;
};

struct linked_queue
{
    struct QNode *front;
    struct QNode *rear;
};

typedef int s_elemtype; //存放图的顶点序号
#define STACK_INIT_SIZE 128
/* 顺序栈的数据结构 */
struct stack
{
    s_elemtype *base;
    s_elemtype *top;
    int stack_size;
};

status init_stack(struct stack *S)
{
     (*S).base = (s_elemtype*)malloc(sizeof(s_elemtype) * STACK_INIT_SIZE);
     if (!(*S).base)
     {
         printf("%s: malloc failed\n", __FUNCTION__);
         return ERROR;
     }

     (*S).top = (*S).base;
     (*S).stack_size = STACK_INIT_SIZE;

     return OK;
}

status get_top_of_stack(struct stack S, s_elemtype *e)
{
    if (S.base == S.top)
    {
        return ERROR;
    }
    else
    {
        (*e) = *(S.top - 1);
    }

    return OK;
}

status stack_empty(struct stack S)
{
    return (S.base == S.top? 1 : 0);
}

void push_stack(struct stack *S, s_elemtype e)
{
    *((*S).top++) = e;
    
    if (1 == g_print_stack)
    {
        printf("push %c\n", e);
    }
}

void pop_stack(struct stack *S, s_elemtype *e)
{
    (*e) = *(--(*S).top);

    if (1 == g_print_stack)
    {
        printf("pop  %c\n", *e);
    }
}

status init_queue(struct linked_queue *Q)
{
    (*Q).front = (*Q).rear = NULL;

    return OK;
}

int queue_empty(struct linked_queue Q)
{
    if (!Q.rear && !Q.front)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

status enqueue(struct linked_queue *Q, q_elemtype elem)
{
    struct QNode *p;

    p = (struct QNode*)malloc(sizeof(struct QNode));
    if (!p)
    {
        return ERROR;
    }

    p->data = elem;
    p->next = NULL;
 
    if (queue_empty(*Q))
    {
        (*Q).front = (*Q).rear = p;
    }
    else
    {
        (*Q).rear->next = p; 
        (*Q).rear = p;
    }
   
    return OK;
} 

status dequeue(struct linked_queue *Q, q_elemtype *elem)
{
    struct QNode *p;

    if (queue_empty(*Q))
    {
        return ERROR;
    }
    else
    {
        p = (*Q).front;
        (*elem) = p->data;
        (*Q).front = p->next;

        if (!p->next)
        {
            (*Q).rear = NULL;
        }

        free(p);

        return OK;
    }
}

int get_first_adjvex(struct ALGraphy G, int vex_no)
{
    if (G.HeadNode[vex_no].firstarc)
    {
        return G.HeadNode[vex_no].firstarc->adjvex_no; 
    }

    return -1;
}

int get_next_adjvex(struct ALGraphy G, int vex_no, int w)
{
    struct ArcNode *p;

    p = G.HeadNode[vex_no].firstarc;

    while (p && p->adjvex_no != w)
    {
        p = p->nextarc;
    }

    if (p && p->nextarc) 
    {
        return p->nextarc->adjvex_no; 
    }
    else
    {
        return -1;
    }
}

void visit(struct ALGraphy G, int vex_no)
{
    printf("visit %s\n", G.HeadNode[vex_no].data);
}

void DFS(struct ALGraphy G, int vex_no)
{
    int i;

    visited[vex_no] = TRUE;
    visit(G, vex_no);

    for (i = get_first_adjvex(G, vex_no); i != -1; i = get_next_adjvex(G, vex_no, i))
    {
        if (!visited[i])
        {
            DFS(G, i);
        }
    } 
}

void DFS_traverse(struct ALGraphy G)
{
    int i;

    for (i = 0; i < G.vexnum; i++)
    {
        visited[i] = FALSE;
    }

    i = 0;

    /* !不要误解这个for循环,这个只是针对非连通图而设置,对于连通图,只须DFS(G,0)即可 */
    //for (i = 0; i < G.vexnum; i++)
    //{
    //    if (!visited[i])
    //    {
            DFS(G, i);
    //    }
    //}
}

void BFS_traverse(struct ALGraphy G)
{
    int i;
    q_elemtype vex_no = 0;
    struct linked_queue Q;

    for (i = 0; i < G.vexnum; i++)
    {
        visited[i] = FALSE;
    }

    init_queue(&Q);

    /* !这里没有考虑非连通图的情况,反而便于读者理解,理解了后就很容易去理解非连通图的处理了 */
    visited[vex_no] = TRUE;
    visit(G, vex_no);
    enqueue(&Q, vex_no);

    while (!queue_empty(Q))
    {
        dequeue(&Q, &vex_no);

        for (i = get_first_adjvex(G, vex_no); i != -1; i = get_next_adjvex(G, vex_no, i))
        {
            if (!visited[i])
            {
                visited[i] = TRUE;
                visit(G, i);
                enqueue(&Q, i);
            }
        }
    }


}

void find_ingree(struct ALGraphy G, int ingree[])
{
    struct ArcNode *p;
    int i;
    int k;

    for (i = 0; i < G.vexnum; i++)
    {
        for (p = G.HeadNode[i].firstarc; p; p = p->nextarc)
        {
            k = p->adjvex_no; 
            ingree[k]++;
        }
    }
}

/*------------------------------------------------------------------------ *                                                                    
 * 图的拓扑排序                                                            *
 * 用栈S来表示零入度栈,处理ve[i], 返回拓扑逆序栈T给函数critical_path使用,*
 * count用来判断AOV或AOE是否有环,如果有环,那环所包括的节点入度           *
 * 不可能变为0,因此不可能进栈S,count就不会自加了                         * 
 *------------------------------------------------------------------------ */ 
status TP_sort(struct ALGraphy G, struct stack *T)
{
    s_elemtype e;
    struct ArcNode *p;
    struct stack S;
    int count = 0;
    int ingree[MAX_VEX_NUM] = {0};
    int i;
    int k;

    find_ingree(G, ingree);

    init_stack(&S);

    for (i = 0; i < G.vexnum; i++)
    {
        if (!ingree[i])
        {
            push_stack(&S, i);
        }
    }

    init_stack(T);

    for (i = 0; i < G.vexnum; i++)
    {
        ve[i] = 0;
    }

    while (!stack_empty(S))
    {
        pop_stack(&S, &e); 
        push_stack(T, e);

        count++;

        for (p = G.HeadNode[e].firstarc; p; p = p->nextarc)
        {
            k = p->adjvex_no;

            if (!--ingree[k])
            {
                push_stack(&S, k);
            }

            /* 把从起始点到k点的路径最大值赋给ve[k]*/
            if (ve[e] + p->arcinfo[k] > ve[k])
            {
                ve[k] = ve[e] + p->arcinfo[k];
            }
        }
    }

    if (count < G.vexnum)
    {
        printf("===== count = %d, vexnum = %d ==== \n", count, G.vexnum);
        return ERROR;
    }
    else
    {
        return OK;
    }
}

/* 求取关键路径 */
status critical_path(struct ALGraphy G)
{
    struct stack T;
    struct ArcNode *p;
    int e;
    int i;
    int k;
    int ee;
    int el;

    if (!TP_sort(G, &T))
    {
        printf("There is a circle in the graphy\n");
        return ERROR;
    }

    for (i = 0; i < G.vexnum; i++)
    {
        vl[i] = ve[G.vexnum - 1]; 
    }

    while (!stack_empty(T))
    {
        pop_stack(&T, &e);

        for (p = G.HeadNode[e].firstarc; p; p = p->nextarc)
        {
            k = p->adjvex_no;     
            if (vl[e] > (vl[k] - p->arcinfo[k]))
            {
                vl[e] = vl[k] - p->arcinfo[k];
            }
        }
    }

    for (i = 0; i < G.vexnum; i++)
    {
       for (p = G.HeadNode[i].firstarc; p; p = p->nextarc)   
       {
           k = p->adjvex_no;
           ee = ve[i];
           el = vl[k] - p->arcinfo[k];

           if (ee == el) /* 又把=号当成==,调试半天,哎! */
           {
               printf("arc(%d->%d) is critical activity, ee = %d, el =%d\n", i, k, ee, el);
           }
       }
    }
}

status create_graphy(struct ALGraphy *G)
{
    int i;
    int v;
    struct ArcNode *pArcNode;
    char name[3] = {0};

    printf("please input vexnum:");
    scanf("%d", &(*G).vexnum);
    printf("please input graphy kind:(0(DG),1(DN),2(UDG),3(UDN):");
    scanf("%d", &(*G).kind);

    (*G).arcnum = 0;

    (*G).HeadNode = (struct VNode*)malloc(sizeof(struct VNode) * (*G).vexnum);
    if (!(*G).HeadNode)
    {
        printf("%s: malloc failed\n", __FUNCTION__);
        return ERROR;
    }

    for (i = 0; i < (*G).vexnum; i++)
    {
        sprintf(name, "v%d", i);
        strcpy((*G).HeadNode[i].data, name); 
        printf("data:%s\n",(*G).HeadNode[i].data); 

        (*G).HeadNode[i].firstarc = NULL;

        printf("please input v%d's last adjvex(or input -1 to exit the loop):", i);
        scanf("%d", &v);

        while (v != -1)
        {
            pArcNode = (struct ArcNode*)malloc(sizeof(struct ArcNode));
            if (!pArcNode)
            {
                printf("%s: malloc failed\n", __FUNCTION__);
                return ERROR;
            }

            printf("please input arcinfo(v%d->v%d):", i, v);
            scanf("%d", &pArcNode->arcinfo[v]);

            (*G).arcnum++;

            pArcNode->adjvex_no = v;
            pArcNode->nextarc = (*G).HeadNode[i].firstarc; 
            (*G).HeadNode[i].firstarc = pArcNode;

            printf("please input v%d's another front adjvex(or input -1 to exit the loop):", i);
            scanf("%d", &v);
        }
    }

    return OK;
}

void print_graphy(struct ALGraphy G)
{
    int i;

    printf("vexnum:%3d\n", G.vexnum);
    printf("arcnum:%3d\n", G.arcnum);
    printf("kind:  %3d\n", G.kind);

    for (i = 0; i < G.vexnum; i++) //for循环老喜欢加;号阿,影响程序调试,罪过!
    {
        //printf("Head data:%s\n", G.HeadNode[i].data);
    }

    //其余信息读者根据需要自己添加把,TODO
}

int main(void)
{
    struct ALGraphy  G;

    (void)create_graphy(&G);

    print_graphy(G);

    printf("Depth First Search:\n");
    DFS_traverse(G);

    printf("Breadth First Search:\n");
    BFS_traverse(G);

    printf("Critical Path:\n");
    critical_path(G);

    return 0;
}


 

 

 

你可能感兴趣的:(拓扑排序和关键路径算法实现)