【WIP_S9】图论算法

创建: 2018/06/01

 

图的概念

 

 

 有向边

 有向图

 无向边

 无向图

 点的次数: 点连接的边的数量

 闭路: 起点和重点一样

 连接图: 任意两点之间都可到达

 无闭路有向图: 没有闭路的有向图

 森林: 互素的树的集合

 生成树: 含有图里所有点的树

 生成树林: 所有生成树的并集

   
   
图论算法的应用  
 

 ● 电路的元件关系

 ● 交通网

 ● 电脑网络(本地网络, 互联网, web等)

 ● 数据库(实体关系图(ER图))

   
图的数据结构  
 邻接矩阵

 适用于数据多的

//------------------------------------------------
//                       邻接矩阵
//------------------------------------------------
struct Graph {
    int v;
    int e;
    int **adj;
};

// 创建图
struct Graph *adjMatrixOfGraph() {
    int i, u, v;
    struct Graph *G = (struct Graph *)malloc(sizeof(struct Graph));
    if (G == NULL) {
        printf("memory error\n");
        return NULL;
    }
    printf("Number of Verticees: ");
    scanf("%d", &G->v);
    printf("Number of Edges: ");
    scanf("%d", &G->e);
    G->adj = (int **)malloc(sizeof(int *) * G->v);
    if (G->adj == NULL) {
        printf("Memory Error\n");
        return NULL;
    }
    for (i = 0; i < G->v; i++) {
        G->adj[i] = (int *)malloc(sizeof(int) * G->v);
        if (G->adj[i] == NULL) {
            printf("Memory Error\n");
            return NULL;
        }
    }
    printf("v: %d, e: %d\n", G->v, G->e);
    for (u=0; u<G->v; u++) { // 初始化点
        for (v=0; v<G->v; v++) {
            if (u==v) {
                G->adj[u][v] = 1;
            } else {
                G->adj[u][v] = 0; // 以0初始化矩阵
            }
        }
    }

    for (i=0; i<G->e; i++) { // 初始化边
        printf("Reading Edge: ");
        scanf("%d %d", &u, &v);
        G->adj[u][v] = G->adj[v][u] = 1;
    }
    return G;
}

 

 邻接链表 

 适用于数据小的

//------------------------------------------------
//                       邻接链表
//------------------------------------------------
struct S9ListNode {
    int vertexNumber;
    struct S9ListNode *next;
};

struct ListGraph {
    int v;
    int e;
    struct S9ListNode *adj;
};

struct ListGraph *adjListOfGraph() { // 无向图
    int i, x, y;
    struct S9ListNode *temp;
    struct ListGraph *G = (struct ListGraph *)malloc(sizeof(struct ListGraph));
    if (G == NULL) {
        printf("Memory Error\n");
        return NULL;
    }
    printf("Number of Vertices: ");
    scanf("%d", &G->v);
    printf("Number of Edges: ");
    scanf("%d", &G->e);
    G->adj = (struct S9ListNode *)malloc(sizeof(struct S9ListNode)*G->v);
    if (G->adj == NULL) {
        printf("Memory Error\n");
        return NULL;
    }
    for (i=0; i<G->v; i++) { // 先初始化所有链表
        G->adj[i] = *(struct S9ListNode *)malloc(sizeof(struct S9ListNode));
        G->adj[i].vertexNumber = i;
        G->adj[i].next = &G->adj[i];
    }
    
    for (i=0; i<G->e; i++) {
        printf("Reading Edge: ");
        scanf("%d %d", &x, &y);
        struct S9ListNode *node;
        temp = (struct S9ListNode *)malloc(sizeof(struct S9ListNode));
        // 把y添加到x的链表上
        temp->vertexNumber = y;
        temp->next = &G->adj[x];
        node = &G->adj[x];
        while (node != NULL && node->next != &G->adj[x]) {
            node = node->next;
        }
        node->next = temp;
        // 把x添加到y的链表山
        temp = (struct S9ListNode *)malloc(sizeof(struct S9ListNode));
        temp->vertexNumber = x;
        temp->next = &G->adj[y];
        node = &G->adj[y];
        while (node != NULL && node->next != &G->adj[y]) {
            node = node->next;
        }
        node->next = temp;
    }
    return G;
}

 

   
图的遍历

 DFS

 深度优先搜索

 Depth First Search

//------------------------------------------------
//                深度优先搜索  DFS
//------------------------------------------------
int visited[128]; // 实际只需要点的数量的长度
// 状态: 1: 已访问     0: 未访问
// 邻接矩阵的DFS
void depthFirstSearch(struct Graph *g, int u) {
    int v;
    visited[u] = 1;
    printf("%d visited\n", u); // 访问中的处理
    for (v = 0; v <g->v; v++) {
        // 对点u连接的未访问的节点进行访问
        if (visited[v] == 0 && g->adj[u][v] != 0) { // 节点并未访问且u和v连接
            depthFirstSearch(g, v); // 从v出发
        }
    }
}

void depthFirstSearchTraversal(struct Graph *g) {
    int i;
    for (i = 0; i < g->v; i++) { // 初始化访问表
        visited[i] = 0;
    }
    // 有不通的子连接图时需要
    for (i = 0; i < g->v; i++) {
        if (visited[i] == 0) {
            depthFirstSearch(g, i); // 一次呼出直接遍历完i可到的所有点
        }
    }
}

// 邻接链表的DFS
void depthFirstSearch_List(struct ListGraph *g, int u) {
    struct S9ListNode *temp = g->adj[u].next;
    visited[u] = 1;
    printf("%d visited\n", u); // 访问中的处理
    while (temp != &g->adj[u]) {
        if (visited[temp->vertexNumber] == 0) {
            depthFirstSearch_List(g, temp->vertexNumber);
        }
        temp = temp->next;
    }
    
}

void depthFirstSearchTraversal_List(struct ListGraph *g) {
    int i;
    for (i = 0; i < g->v; i++) { // 初始化访问表
        visited[i] = 0;
    }
    // 有不通的子连接图时需要
    for (i = 0; i < g->v; i++) {
        if (visited[i] == 0) {
            depthFirstSearch_List(g, i); // 一次呼出直接遍历完i可到的所有点
        }
    }
}

 

 BFS

 宽度优先搜索

 Breadth First Search 

 

//------------------------------------------------
//                宽度优先搜索  BFS
//------------------------------------------------
struct S9QueueNode {
    int data;
    struct S9QueueNode *next;
};
struct S9Queue {
    struct S9QueueNode *front;
};

struct S9Queue *S9CreateQueue() {
    struct S9Queue *q = (struct S9Queue *)malloc(sizeof(struct S9Queue));
    if (q == NULL) {
        return NULL;
    }
    q->front = NULL;
    return q;
}

int S9DeQueue(struct S9Queue *queue) {
    if (queue==NULL) {
        return -1;
    }
    if (queue->front == NULL) {
        return -1;
    }
    struct S9QueueNode *temp = queue->front;
    if (queue->front == NULL) {
        return -1;
    }
    int data = temp->data;
    queue->front = queue->front->next;
    free(temp);
    return data;
}
void S9EnQueue(struct S9Queue *queue, int data) {
    if (queue == NULL) {
        queue = (struct S9Queue *)malloc(sizeof(struct S9Queue));
    }
    struct S9QueueNode *newNode = (struct S9QueueNode *)malloc(sizeof(struct S9QueueNode));
    struct S9QueueNode *temp = queue->front;
    newNode->next = NULL;
    newNode->data = data;
    if (temp == NULL) {
        queue->front = newNode;
    } else {
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
}

void S9FreeQueue(struct S9Queue *q) {
    if (q == NULL) {
        return;
    }
    if (q->front != NULL) {
        struct S9QueueNode *temp = q->front, *temp2;
        while (temp != NULL) {
            temp2 = temp;
            temp = temp->next;
            free(temp2);
        }
    }
    free(q);
}

int S9IsEmptyQueue(struct S9Queue *queue) { // true: 1, false: 0
    if (queue == NULL) {
        return 1;
    }
    int result = queue->front == NULL ? 1 : 0;
    return result;
}
void S9ShowQueue(struct S9Queue *q) {
    if (q == NULL) {
        printf("queue is null\n");
        return;
    }
    if (q->front == NULL) {
        printf("queue has no data\n");
        return;
    }
    struct S9QueueNode *temp = q->front;
    int count = 0;
    while (temp) {
        printf("[%d]: %d ", count, temp->data);
        temp = temp->next;
        count++;
    }
    puts("");
}

int visited_bfs[128];
void breadthFirstSearch(struct Graph *g, int u) { // 矩阵
    int count = 0, i;
    struct S9Queue *queue = S9CreateQueue();
    S9EnQueue(queue, u);
    while (!S9IsEmptyQueue(queue)) {
        int u = S9DeQueue(queue);
        printf("顶点[%d]: %d\n", count, u);
        count++;
        visited_bfs[u] = 1;
        for (i=0; i<g->v; i++) {
            if (g->adj[u][i] == 1 && visited_bfs[i] == 0) {
                S9EnQueue(queue, i);
            }
        }
    }
    S9FreeQueue(queue);
}
void breadthFirstSearchTravsal(struct Graph *g) {
    for (int i=0; i<128; i++) {
        visited_bfs[i] = 0;
    }
    for (int i = 0; i<g->v; i++) {
        if (visited_bfs[i] == 0) {
            breadthFirstSearch(g, i);
        }
    }
}

 

   
最短路径算法  
 种类

 ● 不带加权的图

 ● 带加权的图

 ● 有负加权的图

 应用 

 ● 两地间最近的路

 ●  从A到B发送数据最便宜的方法

 不加权的图最短路径

 

//------------------------------------------------
//                  不带加权的图
//------------------------------------------------
int distant[128];
int path[128];
void unweightedShortestPath(struct Graph *g, int s) { // 邻接矩阵版
    struct S9Queue *queue = S9CreateQueue();
    int v, w;
    S9EnQueue(queue, s);
    for (int i = 0; i<g->v; i++) {
        distant[i] = -1;
        path[i] = -1; // 起点为-1
    }
    distant[s] = 0;
    while(!S9IsEmptyQueue(queue)) {
        v = S9DeQueue(queue);
        for (w = 0; w<g->v; w++) {
            if (g->adj[v][w] != 0 && distant[w] == -1) {
                S9EnQueue(queue, w);
                distant[w] = distant[v] + 1;
                path[w] = v;
            }
        }
    }
    S9FreeQueue(queue);
}

 

 

 迪杰斯特拉算法

 加权图最短路径算法

 
//------------------------------------------------
//            不带负加权的图 迪杰斯特拉算法
//------------------------------------------------
void dijkstra(struct Graph *g, int s) {
    struct S9Queue *queue = S9CreateQueue(); // 优先队列
    int v, w;
    S9EnQueue(queue, s);
    for (int i = 0 ; i<g->v; i++) {
        distant[i] = -1; // -1 表示还没处理
    }
    distant[s] = 0; // 自己到自己的距离为0
    while (!S9IsEmptyQueue(queue)) {
//        v = S9DeQueue(queue); // TODO-PRO: fix here [这里要改成以距离为排序的DeleteMin]
        v = S9DeleteMin(queue);
        for (w = 0; w<g->v; w++) {
            if (g->adj[v][w] != 0) { // v -> w 直接相同
                int newDistant = distant[v] + g->adj[v][w]; // 新距离
                printf("distant[v]: %d\n", distant[v]);
                if (distant[w] == -1) {
                    distant[w] = newDistant;
                    S9EnQueue(queue, w);
                    path[w] = v;
                } else if (newDistant < distant[w]) {
                    distant[w] = newDistant;
                    path[w] = v;
                    // 更新w
                    S9EnQueue(queue, w);
                }
            }
        }
    }
}

 

 贝尔曼-福特算法  可以有负加权边
   
posted @ 2018-06-01 22:57  懒虫哥哥  阅读(151)  评论(0编辑  收藏  举报