拓扑排序(极其详细)

0x00思路

1.前置知识:临接矩阵+图的创建+链表相关知识实现栈

2.算入度函数

3.用头插实现栈

4.再用以个void的功能函数

0x01各个函数实现

对图的一些处理

图结构体声明

typedef struct Graph {
    char* vexs;
    int** arcs;
    int vexNum;
    int arcNum;
}Graph;

图的初始化

Graph* initGraph(int vexNum) {
    Graph* G = (Graph*)malloc(sizeof(Graph));
    G -> vexs = (char*)malloc(sizeof(char) * vexNum);
    G -> arcs = (int**)malloc(sizeof(int*) * vexNum);
    for (int i = 0 ; i < vexNum; i++) {
        G -> arcs[i] = (int*)malloc(sizeof(int) * vexNum);
    }
    G -> vexNum = vexNum;
    G -> arcNum = 0;
    return G;
}

图的创建

void createGraph(Graph* G, char* vexs, int* arcs) {
    for (int i = 0 ; i < G -> vexNum; i++) {
        G -> vexs[i] = vexs[i];
        for (int j = 0; j < G -> vexNum; j++) {
            G -> arcs[i][j] = *(arcs + i * G -> vexNum + j);
            if (G -> arcs[i][j] != 0)
                G -> arcNum ++;
        }
    }
    G -> arcNum /= 2;
}

(为了检查是否创建成功,拓扑本身不需要)图的dfs遍历

void DFS(Graph* G, int* visited, int index) {
    printf("%c\t", G -> vexs[index]);
    visited[index] = 1;
    for (int i = 0; i < G ->vexNum; i++) {
        if (G -> arcs[index][i] == 1 && !visited[i]) {
            DFS(G, visited, i);
        }
    }
}

栈的实现

节点结构体声明

typedef struct Node {
    int data;
    struct Node* next;
}Node;

栈初始化

Node* initStack() {
    Node* stack = (Node*)malloc(sizeof(Node));
    stack -> data = 0;
    stack -> next = NULL;
    return stack;
}

查空函数

int isEmpty(Node* stack) {
    if (stack -> next == NULL) {
        return 1;
    }
    else {
        return 0;
    }
}

入栈出栈函数

void push(Node* stack, int data) {
    Node* node = (Node*)malloc(sizeof(Node));
    node -> data = data;
    node -> next = stack -> next;
    stack -> next = node;
    stack -> data ++;
}
​
int pop(Node* stack) {
    if (!isEmpty(stack)) {
        Node* node = stack -> next;
        stack -> next = node -> next;
        return node -> data;
    }
    else {
        return -1;
    }
}

功能函数的实现

入度计算

int* findInDegrees(Graph* G) {
    int* inDegrees = (int*)malloc(sizeof(int) * G -> vexNum);
    for (int i = 0; i < G -> vexNum; i++) {
        inDegrees[i] = 0;
    }
    for (int i = 0 ; i < G -> vexNum; i++) {
        for (int j = 0; j < G -> vexNum; j++) {
            if (G -> arcs[i][j])
                inDegrees[j] = inDegrees[j] + 1;
        }
    }
    return inDegrees;
}

拓扑功能函数

void topologicalSort(Graph* G) {
    int index = 0;
    int* top = (int*)malloc(sizeof(int) * G -> vexNum);
    int* inDegrees = findInDegrees(G);
    Node* stack = initStack();
    for (int i = 0 ; i < G -> vexNum; i++) {
        if (inDegrees[i] == 0) {
            push(stack, i);
        }
    }
    while (!isEmpty(stack)) {
        int vex = pop(stack);
        top[index++] = vex;
        for (int i = 0 ; i < G -> vexNum; i++) {
            if (G -> arcs[vex][i]) {
                inDegrees[i] = inDegrees[i] - 1;
                if (inDegrees[i] == 0) 
                    push(stack, i);
            }
        }
    }
    for (int i = 0; i < index; i++) {
        printf("%c ", G -> vexs[top[i]]);
    }
    printf("\n");
}

main

int main() {
    Graph* G = initGraph(6);
    int* visited = (int*)malloc(sizeof(int) * G -> vexNum);
    for (int i = 0; i < G -> vexNum; i++)
        visited[i] = 0;
    int arcs[6][6] = {
        0,1,1,1,0,0,
        0,0,0,0,0,0,
        0,1,0,0,1,0,
        0,0,0,0,1,0,
        0,0,0,0,0,0,
        0,0,0,1,1,0
    };
    createGraph(G, "123456", (int*)arcs);
    DFS(G, visited, 0);
    printf("\n");
    topologicalSort(G);
    return 0;
}

0x02几个有意思的问题

1.为什么要用栈

ans:1.减少时间复杂度,把入度为0的直接先压栈 2.在while遍历时,不断if入度为0压栈,不为0入度-1,执行一次出栈一个 3.ps相同入度,先入后出

2.为什么要定义top数组

ans:因为你push,pop进去的是下标,这个下标是数字,但是你的图的data不一定是数字,所以需要一个"哈希"数组进行对应,index也是在这里用来给哈系数组下标自增的, 也就是"人形自走数组产生器"哈哈哈哈哈

3.idnex干啥用

ans:如上

4.初始化的艺术

ans:我更倾向于把需要用的东西在main函数准备好,然后哪个函数需要啥,传参传啥,

luciffer更喜欢在需要用到这个东西的函数里面初始化并获取,如创建队列,我认为本质问题还是自己逻辑

不够清楚,我的"客制化盲写代码也会附上"

5.关于任意给个例子测试

ans:图的入度很讲究的,我认为有一定的规律可循(有向拓扑图),不能随便给个入度去跑

0x03Code

规范版

#include <stdio.h>
#include <stdlib.h>
​
typedef struct Graph {
    char* vexs;
    int** arcs;
    int vexNum;
    int arcNum;
}Graph;
​
typedef struct Node {
    int data;
    struct Node* next;
}Node;
​
Node* initStack() {
    Node* stack = (Node*)malloc(sizeof(Node));
    stack -> data = 0;
    stack -> next = NULL;
    return stack;
}
​
int isEmpty(Node* stack) {
    if (stack -> next == NULL) {
        return 1;
    }
    else {
        return 0;
    }
}
​
void push(Node* stack, int data) {
    Node* node = (Node*)malloc(sizeof(Node));
    node -> data = data;
    node -> next = stack -> next;
    stack -> next = node;
    stack -> data ++;
}
​
int pop(Node* stack) {
    if (!isEmpty(stack)) {
        Node* node = stack -> next;
        stack -> next = node -> next;
        return node -> data;
    }
    else {
        return -1;
    }
}
​
int* findInDegrees(Graph* G) {
    int* inDegrees = (int*)malloc(sizeof(int) * G -> vexNum);
    for (int i = 0; i < G -> vexNum; i++) {
        inDegrees[i] = 0;
    }
    for (int i = 0 ; i < G -> vexNum; i++) {
        for (int j = 0; j < G -> vexNum; j++) {
            if (G -> arcs[i][j])
                inDegrees[j] = inDegrees[j] + 1;
        }
    }
    return inDegrees;
}
​
void topologicalSort(Graph* G) {
    int index = 0;
    int* top = (int*)malloc(sizeof(int) * G -> vexNum);
    int* inDegrees = findInDegrees(G);
    Node* stack = initStack();
    for (int i = 0 ; i < G -> vexNum; i++) {
        if (inDegrees[i] == 0) {
            push(stack, i);
        }
    }
    while (!isEmpty(stack)) {
        int vex = pop(stack);
        top[index++] = vex;
        for (int i = 0 ; i < G -> vexNum; i++) {
            if (G -> arcs[vex][i]) {
                inDegrees[i] = inDegrees[i] - 1;
                if (inDegrees[i] == 0) 
                    push(stack, i);
            }
        }
    }
    for (int i = 0; i < index; i++) {
        printf("%c ", G -> vexs[top[i]]);
    }
    printf("\n");
}
​
Graph* initGraph(int vexNum) {
    Graph* G = (Graph*)malloc(sizeof(Graph));
    G -> vexs = (char*)malloc(sizeof(char) * vexNum);
    G -> arcs = (int**)malloc(sizeof(int*) * vexNum);
    for (int i = 0 ; i < vexNum; i++) {
        G -> arcs[i] = (int*)malloc(sizeof(int) * vexNum);
    }
    G -> vexNum = vexNum;
    G -> arcNum = 0;
    return G;
}
​
void createGraph(Graph* G, char* vexs, int* arcs) {
    for (int i = 0 ; i < G -> vexNum; i++) {
        G -> vexs[i] = vexs[i];
        for (int j = 0; j < G -> vexNum; j++) {
            G -> arcs[i][j] = *(arcs + i * G -> vexNum + j);
            if (G -> arcs[i][j] != 0)
                G -> arcNum ++;
        }
    }
    G -> arcNum /= 2;
}
​
void DFS(Graph* G, int* visited, int index) {
    printf("%c\t", G -> vexs[index]);
    visited[index] = 1;
    for (int i = 0; i < G ->vexNum; i++) {
        if (G -> arcs[index][i] == 1 && !visited[i]) {
            DFS(G, visited, i);
        }
    }
}
​
int main() {
    Graph* G = initGraph(6);
    int* visited = (int*)malloc(sizeof(int) * G -> vexNum);
    for (int i = 0; i < G -> vexNum; i++)
        visited[i] = 0;
    int arcs[6][6] = {
        0,1,1,1,0,0,
        0,0,0,0,0,0,
        0,1,0,0,1,0,
        0,0,0,0,1,0,
        0,0,0,0,0,0,
        0,0,0,1,1,0
    };
    createGraph(G, "123456", (int*)arcs);
    DFS(G, visited, 0);
    printf("\n");
    topologicalSort(G);
    return 0;
}

我的"客制化"版本(阉割

#include <stdio.h>
#include <stdlib.h>
typedef struct Node{
    int data;
    struct Node *next;
}Node;
int isempty(Node *D){
    if(D -> next == NULL) return 1;
    if(D -> next != NULL) return 0;
}
Node* init(){
    Node *D = (Node*)malloc(sizeof(Node));
    D -> next = NULL;
    D -> data = 0;
    return D;
}
void push(Node *D,int data){
    Node *node = (Node*)malloc(sizeof(Node));
    node -> next = D -> next;
    D -> next = node;
    node -> data = data;
    D -> data = D -> data + 1;
}
int pop(Node *D){
    int i = D -> next -> data;
    D -> next = D -> next -> next;
    return i;   
}
int* findIndegree(int* ljjz){
    int *indegree = (int*)malloc(sizeof(int)*4);
    for(int i = 0;i < 4;i++){
        for(int j = 0;j < 4;j++){
            if(*(ljjz+i*4+j)!=0){
                (*(ljjz+i*4+j))--;
                (*(indegree+j))++;
            }
        }
    }
    return indegree;
}
void topology(int *indegree,Node *stack,char *zifu){
    int index = 0;
    int *ans = (int*)malloc(sizeof(int)*4);
    for(int i =0;i < 4;i++){
        if(indegree[i]==0) push(stack,i);
        else{
            indegree[i]--;
        }
    }
    while(!isempty(stack)){
        int i = pop(stack);
        ans[index++] = i ;
        for(int i = 0;i < 4; i++){
            if(indegree[i]!=0){
                indegree[i]--;
                if(indegree[i]==0){
                    push(stack,i);
                }
            }
        }
    }
    for(int i = 0; i < index; i++){
        printf("%c ",zifu[ans[i]] );
    }
    printf("\n");
}
int main(){
    char *zifu = "ABCD";
    int ljjz[4][4] = {
        0,1,1,0,
        0,0,0,1,
        0,1,0,1,
        0,0,0,0
    };
    Node* stack = init();
    int *indegree = findIndegree(ljjz);
    topology(indegree,stack,zifu);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LiujiaHuan13

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值