个人认为图的算法看起来非常简洁,但是实现起来需要基础很扎实。因为经常会涉及多种简单的数据结构,怎样把他们恰当的串联起来,不会报那种,空指针了,类型不匹配,实体类型不符合了等等。
在做无向图邻接链表广度优先搜索的时候,写的很冒火,想去找别的博主的代码借鉴一下,发现大部分,真的是大部分,都是有问题的,有些甚至都运行不出来。于是硬着头皮自己写了。
第一步是分析:
无向图里面用到的数据结构一个是链表,这里用到了两次。一个链表用于存放每个元素的与之相连的元素,用了一个邻接链表。还要考虑所有元素怎么连成一张图,前面的链表可以得到的散开的这种形式x1------x2,要把所有元素集合起来就能变成一张图,我又用了一个链表给他所有元素存起来。那么大的链表里面就有所有元素,以及每个元素的相连元素。也就是说访问这个链表就能得到这张图的结构。
还用到了一个队列,主要是需要用到先进先出的性质,为了使数据的相互联系更加紧密,在声明队列结构体的时候,我用到的是链表的指针。
剩下的就是从一个源节点开始不断的入队出队了,这个思想并不复杂。
要注意的就是指针了,怎么处理空的情况,在写链表的时候要特别注意,这是这个代码最重要的部分,其他的都是在调用他,如果写出问题了后面的访问肯定是有问题的。
(下面代码是根据算法导论来写 的,要是没看过的书的话可能不知道白色灰色黑色等是在干嘛…其实就是在标明一种状态,简单说一下就是初始化都是白色,访问到他了(也就是让他入队列了),他就变成灰色,当把它的相连的子结点都访问完了(也就是他出队列了),就标记成黑色)
#include "stdafx.h"
#include <stdio.h>
#include<stdlib.h>
#define N 5 //the total number of points
#define MAX 0x3f3f3f3f
typedef enum Color { W, G, B }Corlor; //white gray black
typedef struct point_ *point;
typedef struct link_ *link;
typedef struct link_ {
link rear; //尾指针
point node; //数据域
link next; //指针域
link front; //头指针
}l;
typedef struct point_ //define points' property
{
int key;
int distance;
Color c;
link Adj; //other points connected to the point
point parent; //parent is a precessor
point next; //this is for queue
}p;
typedef struct queue_ //队列
{
link head;
link tail;
}*queue, q;
link INI_LINK(link L)
{
L = (link)malloc(sizeof(l));
L->rear = NULL;
L->node = NULL;
L->next = NULL;
L->front = NULL;
return L;
}
link INSERT_LINK(link L, point dot)
{
link new_p = (link)malloc(sizeof(l));
new_p=INI_LINK(new_p);
new_p->node = dot;
new_p->next = NULL;
if (L->front == NULL)
{
L->front = L->rear = new_p;
}
else
{
L->rear->next = new_p;
L->rear = new_p;
if (L->front->next == NULL)
L->front->next = L->rear;
}
return L;
}
queue INI_QUEUE(queue que)
{
que = (queue)malloc(sizeof(q));
que->head = NULL;
que->tail = NULL;
return que;
}
void ENQUEUE(queue que, point x)
{
link new_p = (link)malloc(sizeof(l));
new_p = INI_LINK(new_p);
new_p->node = x;
new_p->next = NULL;
if (que->head == NULL)
{
que->head = que->tail = new_p;
}
else
{
que->tail->next = new_p;
que->tail = new_p;
if (que->head->next == NULL)
que->head->next = que->tail;
}
}
void DEQUEUE(queue que)
{
if (que->head == NULL)
{
return;
}
if (que->head == que->tail)
{
que->head = que->head->next = NULL;
que->tail = que->tail->next = NULL;
}
else
{
que->head = que->head->next;
}
}
//以上是构造基本的数据结构 链表和队列,为图的操作打下基础
point INI_POINT(int k) //初始化结点
{
point m = (point)malloc(sizeof(p));
link x = (link)malloc(sizeof(l));
x->node = NULL;
x->front = NULL;
x->rear = NULL;
x->next = NULL;
m->Adj = x;
m->parent = NULL;
m->c = W;
m->key = k;
m->distance = MAX;
m->next = NULL;
return m;
}
point INI_SOURCE_POINT(point source)
{
source->c = G;
source->distance = 0;
return source;
}
/以上是初始化结点
void CONNECTION(point x1, point x2) //连接两个结点
{
x1->Adj = INSERT_LINK(x1->Adj, x2);
x2->Adj = INSERT_LINK(x2->Adj, x1);
}
void BFS(link All_Point, point s)
{
queue Q=(queue)malloc(sizeof(q));
Q=INI_QUEUE(Q);
ENQUEUE(Q, s);
while (Q->tail != NULL)
{
link u = Q->head;
printf("(%d, %d) ", u->node->key, u->node->distance);
DEQUEUE(Q);
while (u->node->Adj->front != NULL)
{
link v = u->node->Adj->front;
if (v->node->c == W)
{
v->node->c = G;
v->node->distance = u->node->distance + 1;
v->node->parent = u->node;
// printf("v= %d, v parent shi =%d v distance is %d\n", v->node->key, v->node->parent->key, v->node->distance);
ENQUEUE(Q, v->node);
}
u->node->Adj->front = u->node->Adj->front->next;
}
u->node->c = B;
}
}
int main()
{
link All_Point=(link)malloc(sizeof(l)); //这个链表里面存着所有的结点
point p1, p2, p3, p4, p5;
All_Point=INI_LINK(All_Point);
p1 = INI_POINT(12);
p2 = INI_POINT(18);
p3 = INI_POINT(22);
p4 = INI_POINT(31);
p5 = INI_POINT(44);
p1 = INI_SOURCE_POINT(p1); //p1 is a source point
CONNECTION(p1, p2);
CONNECTION(p1, p3);
CONNECTION(p3, p4);
CONNECTION(p3, p5);
INSERT_LINK(All_Point, p1);
INSERT_LINK(All_Point, p2);
INSERT_LINK(All_Point, p3);
INSERT_LINK(All_Point, p4);
INSERT_LINK(All_Point, p5);
printf("the result is:\n");
BFS(All_Point, p1);
return 0;
}
我连接的是这样一个图,结果显示的是结点和对应的距离
18--------------------12(源节点)
|
|
|
|
22 -----------------31
|
|
|
44