[英]Using BFS to compute distance between a source and a vertex
I am trying to use adjacency list to compute the distance from a source vertex to the other vertices. 我正在尝试使用邻接表来计算从源顶点到其他顶点的距离。 I am using a queue to accomplish this however I get the distance of each vertex besides the source as -1, but I am not sure why this is happening
我正在使用一个队列来完成此操作,但是我得到除源之外每个顶点的距离为-1,但是我不确定为什么会这样
#include <stdio.h>
#include <stdlib.h>
#include "input_error.h"
#define VertexToSearch 1
typedef struct edge {
int vertexIndex;
struct edge *edgePtr;
} edge;
typedef struct vertex {
int vertexKey;
struct edge *edgePtr;
int visited;
int distance;
} vertex;
typedef struct queue {
struct vertex v;
struct queue* next;
}queue;
int vertexCount = 0;
struct vertex graph[];
void load_file(char*);
void insertEdge(int, int, struct vertex[]);
void InsertVertex(int, struct vertex[]);
void printGraph();
void bfs();
void print_distances();
queue* enqueue(queue*,vertex );
vertex dequeue(queue*);
enum error program_error;
int count;
int main(int argc, char** argv) {
load_file(argv[1]);
printGraph();
bfs();
print_distances();
return 0;
}
void load_file(char* filename) {
int vertex1;
int vertex2;
FILE* file = fopen(filename, "r");
if (file == NULL) {
printf("%s did not open\n", filename);
program_error = FILE_FAILED_TO_OPEN;
exit(program_error);
}
fscanf(file, "%d", &count);
graph[count];
for (int i = 0; i < count; i++) {
InsertVertex(i + 1, graph);
}
for (int i = 0; i < count; i++) {
fscanf(file, "\n(%d,%d)", &vertex1, &vertex2);
insertEdge(vertex1, vertex2, graph);
}
fclose(file);
}
void InsertVertex(int vertexKey, struct vertex graph[]) {
graph[vertexCount].vertexKey = vertexKey;
graph[vertexCount].edgePtr = NULL;
graph[vertexCount].visited = 0;
graph[vertexCount].distance = -1;
vertexCount++;
}
void insertEdge(int vertex1, int vertex2, struct vertex graph[]) {
struct edge *e, *e1, *e2;
e = graph[vertex1 - 1].edgePtr;
while (e && e->edgePtr) {
e = e->edgePtr;
}
e1 = (struct edge *) malloc(sizeof (*e1));
e1->vertexIndex = vertex2;
e1->edgePtr = NULL;
if (e)
e->edgePtr = e1;
else
graph[vertex1 - 1].edgePtr = e1;
e = graph[vertex2 - 1].edgePtr;
while (e && e->edgePtr) {
e = e->edgePtr;
}
e2 = (struct edge *) malloc(sizeof (*e2));
e2->vertexIndex = vertex1;
e2->edgePtr = NULL;
if (e)
e->edgePtr = e2;
else
graph[vertex2 - 1].edgePtr = e2;
}
void printGraph() {
int i;
struct edge *e;
for (i = 0; i < vertexCount; i++) {
printf("%d(%d)", i + 1, graph[i].vertexKey);
e = graph[i].edgePtr;
while (e) {
printf("->%d", e->vertexIndex);
e = e->edgePtr;
}
printf("\n");
}
}
void bfs() {
graph[0].distance = 0;
queue* q = NULL;
q = enqueue(q,graph[0]);
while(q->next != NULL){
vertex u = dequeue(q);
while(u.edgePtr != NULL){
if(graph[u.edgePtr->vertexIndex -1 ].distance == -1){
graph[u.edgePtr->vertexIndex -1 ].distance = u.distance + 1;
enqueue(q, graph[u.edgePtr->vertexIndex -1 ]);
}
u.edgePtr = u.edgePtr->edgePtr;
}
}
}
void print_distances() {
for (int i = 0; i < count; i++) {
printf("%d %d\n", i + 1, graph[i].distance);
}
}
queue* enqueue(queue* q,vertex v) {
queue* new = malloc(sizeof (queue));
new->next = NULL;
new->v = v;
if (q == NULL) {
q = malloc(sizeof(queue));
q = new;
} else {
while (q->next != NULL) {
q = q->next;
}
//add new node at the end
q->next = new;
}
return q;
}
vertex dequeue(queue* q) {
vertex v;
queue* tempPtr;
tempPtr = q; //makes temp the address of the node to be deleted
v = tempPtr->v;
q = q->next; //sets the new head as the address of the next node
return v;
}
I have figured it out, basically my queue implementation was horrible and dequeue was not clearing out the queue, also this while(q->next != NULL)
was incorrect it should be while(q != NULL)
Below is the correct implementation of this program 我已经弄清楚了,基本上我的队列实现很糟糕并且出队没有清除队列,这
while(q->next != NULL)
是不正确的, while(q != NULL)
下面是正确的实现该程序的
#include <stdio.h>
#include <stdlib.h>
#include "input_error.h"
#define VertexToSearch 1
typedef struct edge {
int vertexIndex;
struct edge *edgePtr;
} edge;
typedef struct vertex {
int vertexKey;
struct edge *edgePtr;
int visited;
int distance;
} vertex;
typedef struct queue {
struct vertex v;
struct queue* next;
}queue;
int vertexCount = 0;
struct vertex graph[];
queue* q = NULL;
void load_file(char*);
void insertEdge(int, int, struct vertex[]);
void InsertVertex(int, struct vertex[]);
void printGraph();
void bfs();
void print_distances();
void enqueue(vertex);
vertex dequeue();
enum error program_error;
int count;
int main(int argc, char** argv) {
load_file(argv[1]);
printGraph();
bfs();
print_distances();
return 0;
}
void load_file(char* filename) {
int vertex1;
int vertex2;
FILE* file = fopen(filename, "r");
if (file == NULL) {
printf("%s did not open\n", filename);
program_error = FILE_FAILED_TO_OPEN;
exit(program_error);
}
fscanf(file, "%d", &count);
graph[count];
for (int i = 0; i < count; i++) {
InsertVertex(i + 1, graph);
}
for (int i = 0; i < count; i++) {
fscanf(file, "\n(%d,%d)", &vertex1, &vertex2);
insertEdge(vertex1, vertex2, graph);
}
fclose(file);
}
void InsertVertex(int vertexKey, struct vertex graph[]) {
graph[vertexCount].vertexKey = vertexKey;
graph[vertexCount].edgePtr = NULL;
graph[vertexCount].visited = 0;
graph[vertexCount].distance = -1;
vertexCount++;
}
void insertEdge(int vertex1, int vertex2, struct vertex graph[]) {
struct edge *e, *e1, *e2;
e = graph[vertex1 - 1].edgePtr;
while (e && e->edgePtr) {
e = e->edgePtr;
}
e1 = (struct edge *) malloc(sizeof (*e1));
e1->vertexIndex = vertex2;
e1->edgePtr = NULL;
if (e)
e->edgePtr = e1;
else
graph[vertex1 - 1].edgePtr = e1;
e = graph[vertex2 - 1].edgePtr;
while (e && e->edgePtr) {
e = e->edgePtr;
}
e2 = (struct edge *) malloc(sizeof (*e2));
e2->vertexIndex = vertex1;
e2->edgePtr = NULL;
if (e)
e->edgePtr = e2;
else
graph[vertex2 - 1].edgePtr = e2;
}
void printGraph() {
int i;
struct edge *e;
for (i = 0; i < vertexCount; i++) {
printf("%d(%d)", i + 1, graph[i].vertexKey);
e = graph[i].edgePtr;
while (e) {
printf("->%d", e->vertexIndex);
e = e->edgePtr;
}
printf("\n");
}
}
void bfs() {
graph[0].distance = 0;
enqueue(graph[0]);
while(q != NULL){
vertex u = dequeue();
while(u.edgePtr != NULL){
if(graph[u.edgePtr->vertexIndex - 1].distance == -1){
graph[u.edgePtr->vertexIndex - 1].distance = u.distance + 1;
enqueue(graph[u.edgePtr->vertexIndex - 1]);
}
u.edgePtr = u.edgePtr->edgePtr;
}
}
}
void print_distances() {
for (int i = 0; i < count; i++) {
printf("%d %d\n", i + 1, graph[i].distance);
}
}
void enqueue(vertex v) {
queue* new = malloc(sizeof (queue));
new->next = NULL;
new->v = v;
if (q == NULL) {
q = malloc(sizeof(queue));
q = new;
} else {
while (q->next != NULL) {
q = q->next;
}
//add new node at the end
q->next = new;
}
}
vertex dequeue() {
vertex v;
queue* tempPtr;
tempPtr = q; //makes temp the address of the node to be deleted
v = tempPtr->v;
q = q->next; //sets the new head as the address of the next node
return v;
}
In insertVertex(...)
, you call graph[vertexCount].distance = -1;
在
insertVertex(...)
,您调用graph[vertexCount].distance = -1;
. 。
It is very likely that your code isn't changing distance properly. 您的代码很可能没有正确更改距离。 From what I can see, you set
u.edgePtr->vertexIndex
to the index of the second vertex connected - 1 (in insertEdge(...)
). 从我所看到的,您将
u.edgePtr->vertexIndex
设置为连接的第二个顶点的索引-1 (在insertEdge(...)
)。 This means you're probably converting from human-readable indexes (1, 2, ... n) into machine-readable indexes (0, 1, ... n-1) 这意味着您可能正在将人类可读的索引(1、2,... n)转换为机器可读的索引(0、1,... n-1)
In bfs()
you shouldn't need to do this a second time! 在
bfs()
您不需要第二次! I couldn't find any reason to set graph[u.edgePtr->vertexIndex - 1].distance
, but I could be mistaken. 我找不到设置
graph[u.edgePtr->vertexIndex - 1].distance
任何理由,但我可能会误解。 I've redone your while loop. 我已重做您的while循环。 Try putting this in
bfs()
: 尝试将其放在
bfs()
:
while(u.edgePtr != NULL){
if(graph[u.edgePtr->vertexIndex].distance == -1){
graph[u.edgePtr->vertexIndex].distance = u.distance + 1;
enqueue(q, graph[u.edgePtr->vertexIndex]);
}
I'm not sure why none of your distances are changing, because your code should still be affecting the distances at index-1
just fine. 我不确定为什么您的距离都没有变化,因为您的代码仍然应该影响
index-1
处的距离。 Try the fix above and let me know if that was enough to catch the bug or if there might be another one. 尝试上面的修复,让我知道这是否足以捕获该错误,或者是否还有另一个错误。
You have the general idea. 您有大致的想法。 Here are some ways to simplify the code
以下是一些简化代码的方法
Here's the simplified code. 这是简化的代码。 I leave it as an exercise for the reader to optimize the code for speed and/or remove the queue limit, as desired.
我把它留给读者作为练习,以根据需要优化代码的速度和/或删除队列限制。
#include <stdio.h>
#include <stdint.h>
struct Vertex
{
int id;
int distance;
};
struct Queue
{
uint8_t head;
uint8_t tail;
void *data[256];
};
int main( void )
{
int edge[][2] = { {2,3}, {1,4}, {1,3}, {3,4}, {4,5}, {0,0} };
struct Vertex vertex[] = { {1,0}, {2,-1}, {3,-1}, {4,-1}, {5,-1}, {0,0} };
struct Queue q = { 0, 0 };
q.data[q.head++] = &vertex[0];
while ( q.tail != q.head )
{
struct Vertex *src = q.data[q.tail++];
for ( int i = 0; edge[i][0] > 0; i++ )
for ( int j = 0; j < 2; j++ )
if ( edge[i][j] == src->id )
{
int destID = edge[i][(j+1)%2];
struct Vertex *dest;
for ( dest = vertex; dest->id > 0; dest++ )
if ( dest->id == destID )
break;
if ( dest->distance < 0 )
{
dest->distance = src->distance + 1;
q.data[q.head++] = dest;
}
}
}
for ( int i = 0; vertex[i].id > 0; i++ )
printf( "Vertex %d is at distance %d\n", vertex[i].id, vertex[i].distance );
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.