今天下午有時間,好奇圖論,所以把算法導論的22章的圖論的基礎給看了一下,最後那個強連通分量我沒看,不知道有什麼用處,等到要用的時候再看吧,一切按照興趣走。晚上花了兩個多小時把廣度優先搜索的部分給實現了一遍,感覺還是比較棒的。整個過程中的數據結構方面,我沒有因爲實現方面的原因而浪費空間,盡力實現了這個廣度優先搜索。
直接上附上代碼,以後直接在代碼上註釋吧,不過多地寫廢話了,一些概念都在書上,但是自己寫的代碼有時候自己卻會忘記。
/*************************************************************************
> File Name: graph.c
> Author: jeff zhu
> Mail: [email protected]
> Created Time: 2016年09月04日 星期日 18時58分08秒
************************************************************************/
#include <stdio.h>
#include <malloc.h>
#include <limits.h>
#define MAXSIZE 100 //圖的最大的頂點數量爲100,
#define WHITE 1 //定義每個頂點的可能的顏色,白色代表沒有探索,灰色代表已經探索,但是其鄰接的定點沒有完全探索,黑的代表其所有鄰接的頂點都探索過。
#define GRAY 2
#define BLACK 3
#define INFINITE INT_MAX //定義一個正無窮
typedef struct gra_ptr_node { //這個地方我定義了一個數據結構,這個數據結構用來實現鏈表(這個鏈表的節點的關鍵字是指針,所以節省了空間,在效率上也沒有損耗)
struct gra_ptr_node *next;
struct graph_node *ptr;
}PTR_NODE;
typedef struct graph_node { //圖的每個頂點,parent用來實現廣度優先搜索樹,nect用來實現來鏈表,key代表編號,d是距離搜索頂點的距離,f是爲了深度優先搜索而準備<span style="white-space:pre"> </span>//的
struct graph_node *parent;
struct graph_node *next;
int key;
int d;
int f;
int color;
}NODE;
typedef struct graph { //圖的數據結構,length代表adj實際的長度
PTR_NODE *adj[MAXSIZE];
int length;
}GRAPH;
typedef struct stack_of_granode { //在BFS中會用到的棧
NODE *arr_temp[MAXSIZE];
int start;
int end;
int length;
int count;
}NODEQUEUE;
NODE *arr_V[MAXSIZE]; //這個數組保存所有的頂點,可以直接在這個數組中找到想要的定點
void BFS (GRAPH *G , NODE *s) ;
void init_graph (GRAPH *G , int len) ;
NODE *create_and_init_node (int key) ;
void insert_to_adj (GRAPH *G , NODE *x , int key) ;
void init_queue (NODEQUEUE *Q , GRAPH *G) ;
void enqueue (NODEQUEUE *Q , NODE *x) ;
NODE *dequeue (NODEQUEUE *Q) ;
void BFS (GRAPH *G , NODE *s) ;
int main () {
int i;
int count = 0;
GRAPH G;
NODE *temp;
NODE *temp1;
PTR_NODE *ptr_temp;
NODEQUEUE Q; //一下兩行代碼放到BFS函數中更好,寫註釋的時候發現的懶得改了
init_queue (&Q , &G);
init_graph (&G , 8); //初始化圖
temp = create_and_init_node (0); //一下代碼都是初始化一個圖,圖的邏輯結構見《算法導論》圖22-3
arr_V[count++] = temp;
insert_to_adj (&G , temp , 1);
temp = create_and_init_node (1);
arr_V[count++] = temp;
insert_to_adj (&G , temp , 0);
insert_to_adj (&G , temp , 2);
temp = create_and_init_node (2);
temp1 = temp;
arr_V[count++] = temp;
insert_to_adj (&G , temp , 1);
insert_to_adj (&G , temp , 3);
temp = create_and_init_node (3);
arr_V[count++] = temp;
insert_to_adj (&G , temp , 2);
insert_to_adj (&G , temp , 4);
insert_to_adj (&G , temp , 5);
temp = create_and_init_node (4);
arr_V[count++] = temp;
insert_to_adj (&G , temp , 3);
insert_to_adj (&G , temp , 5);
insert_to_adj (&G , temp , 6);
insert_to_adj (&G , temp , 7);
temp = create_and_init_node (5);
arr_V[count++] = temp;
insert_to_adj (&G , temp , 3);
insert_to_adj (&G , temp , 4);
insert_to_adj (&G , temp , 6);
temp = create_and_init_node (6);
arr_V[count++] = temp;
insert_to_adj (&G , temp , 5);
insert_to_adj (&G , temp , 4);
insert_to_adj (&G , temp , 7);
temp = create_and_init_node (7);
arr_V[count++] = temp;
insert_to_adj (&G , temp , 6);
insert_to_adj (&G , temp , 4); //圖初始化結束
for (i = 0 ; i < 8 ; i++) {
ptr_temp = G.adj[i];
while (ptr_temp != NULL) {
printf ("%d " , ptr_temp->ptr->key);
ptr_temp = ptr_temp->next;
}
printf ("\n");
} //打印一下結果,看看是否和邏輯圖是一樣的
printf ("\n\n");
BFS (&G , temp1); //執行BFS算法
for (i = 0 ; i < count ; i++) {
printf ("%d " , arr_V[i]->d);
}
printf ("\n");
}
void init_graph (GRAPH *G , int len) { //初始化圖的函數
int i;
G->length = len;
for (i = 0 ; i < len ; i++) {
G->adj[i] = NULL;
}
}
NODE *create_and_init_node (int key) { //創建和初始化圖
NODE *temp = (NODE *) malloc (sizeof (NODE));
temp->key = key;
temp->d = 0;
temp->f = 0;
temp->next = NULL;
temp->parent = NULL;
return temp;
}
void insert_to_adj (GRAPH *G , NODE *x , int key) { //這個函數從圖論的角度來說是將邊加入到一個關於頂點的便於搜索數組。
if (key >= G->length) {
printf ("the key is too big");
return;
}
PTR_NODE *temp;
temp = (PTR_NODE *) malloc (sizeof (PTR_NODE));
temp->next = G->adj[key];
temp->ptr = x;
G->adj[key] = temp;
}
void init_queue (NODEQUEUE *Q , GRAPH *G) { //初始化BFS算法要用到的隊列Q。
Q->start = 0;
Q->end = 0;
Q->length = G->length;
Q->count = 0;
}
void enqueue (NODEQUEUE *Q , NODE *x) { //將節點x加入到隊列Q中。同時,Q->count加1。
if (((Q->end+1) % Q->length) == Q->start)
return;
else {
Q->arr_temp[Q->end] = x;
Q->end++;
if (Q->end == Q->length)
Q->end = 0;
Q->count++;
}
}
NODE *dequeue (NODEQUEUE *Q) { //返回Q->arr[Q->start],同時將這個數組給刪除。同時,Q->count減1。
NODE *temp;
if (Q->start == Q->end)
return;
else {
temp = Q->arr_temp[Q->start];
Q->start++;
if (Q->start == Q->length)
Q->start = 0;
Q->count--;
}
return temp;
}
void BFS (GRAPH *G , NODE *s) { //終於到了廣度優先算法了,這個算法的核心思想就是,先探索和當前節點鄰接的頂點,然後再探索別的定點
int i;
NODEQUEUE Q;
init_queue (&Q , G);
NODE *temp;
PTR_NODE *ptr_temp;
for (i = 0 ; i < G->length ; i++) {
if (arr_V[i] != s) {
arr_V[i]->color = WHITE;
arr_V[i]->d = INFINITE;
arr_V[i]->parent = NULL;
}
}
s->color = GRAY;
s->parent = NULL;
s->d = 0;
enqueue (&Q , s);
while (Q.count != 0) {
temp = dequeue (&Q);
ptr_temp = G->adj[temp->key];
while (ptr_temp != NULL) {
if (ptr_temp->ptr->color == WHITE) {
ptr_temp->ptr->color = GRAY;
ptr_temp->ptr->d = temp->d + 1;
ptr_temp->ptr->parent = temp;
enqueue (&Q , ptr_temp->ptr);
}
ptr_temp = ptr_temp->next;
}
temp->color = BLACK;
}
}