我的BFS的C代码给出了不正确的(绝对无意义)输出

时间:2018-04-28 11:37:34

标签: c algorithm graph-algorithm

这里实现的BFS算法在Cormen中提到。但是,由于某些原因,此代码会产生无效输出,即使对于普通图形也是如此。创建邻接列表的所有工作都可以正常工作。

以下是整个代码:

#include<stdio.h>
#include<limits.h>
#include<stdlib.h>
#define size 5

struct node *nodelist = NULL;

struct node
{
    int nodeid;
    int parentid;
    int sourcedist;
    char *color;
};

struct graph *adjlist = NULL;

struct graph
{
    struct listnode *list;
    int count;
};

struct listnode
{
    int nodeid;
    struct listnode *next;
};

struct listnode *createnode(int id)
{
    struct listnode *newnode = (struct listnode *)malloc(sizeof(struct listnode));
    (*newnode).nodeid = id;
    (*newnode).next = NULL;
    return newnode;
}

int addtoadjlist(int u, int v)
{
    struct listnode *newnode = createnode(v);
    if((*(adjlist + u)).list == NULL)
    {
        (*(adjlist + u)).list  = newnode;
        (*(adjlist + u)).count++;
    }
    else
    {
        (*newnode).next = (*(adjlist + u)).list;
        (*(adjlist + u)).list = newnode;
        (*(adjlist + u)).count++;
    }
}

int disp(int totalnodes)
{
    int degreesum = 0, i;
    struct listnode *currentnode = NULL;
    for(i = 0; i < totalnodes; i++)
    {
        currentnode = (*(adjlist + i)).list;
        printf("\n node %d -> ",i);
        while(currentnode != NULL)
        {
            printf("%d -> ",(*currentnode).nodeid);
            currentnode = (*currentnode).next;
        }
        printf("NULL | Degree: %d",(*(adjlist + i)).count);
        degreesum += (*(adjlist + i)).count;
    }
    return degreesum/2;
}

int dispnodeinfo(int totalnodes)
{
    int i;
    for(i = 0; i < totalnodes; i++)
    {
        printf("\n node %d: parent %d| distance from source %d| color %c",(*(nodelist + i)).nodeid,(*(nodelist + i)).sourcedist,(*(nodelist + i)).color);   
    }
}

int *BFSQf;
int *BFSQr;

int ENQ(int x)
{
    if(BFSQr == NULL)
    {
        BFSQr = BFSQf;
        *BFSQf = x;
    }
    else
    {
        BFSQr++;
        *BFSQr = x;
    }
    return 0;
}

int DEQ()
{
    int temp;
    if(BFSQr == NULL)
        return -1;
    else if(BFSQr == BFSQf)
    {
        BFSQr = NULL;
        return *BFSQf;
    }
    else
    {
        temp = *BFSQr;
        BFSQr--;
        return temp;
    }
}

int bfs(int s)
{
    (*(nodelist + s)).color = "G";
    (*(nodelist + s)).sourcedist = 0;
    BFSQr = NULL;               //Empty the Queue;
    ENQ(s);
    while(BFSQr != NULL)
    {
        int u = DEQ();
        struct listnode *currentnode = (*(adjlist + u)).list;
        while(currentnode != NULL)
        {
            int nodeid = (*currentnode).nodeid;
            if((*(nodelist + nodeid)).color == "W")
            {
                (*(nodelist + nodeid)).color = "G";
                (*(nodelist + nodeid)).sourcedist = (*(nodelist + u)).sourcedist + 1;
                (*(nodelist + nodeid)).parentid = u;
                ENQ(nodeid);
            }
            currentnode = (*currentnode).next;
        }
        (*(nodelist + u)).color = "B";
    }
}

int main(void)
{
    int totalnodes, choice = 0, u, v, i, s;

    printf("\n Enter the number of nodes in the graph: ");
    scanf("%d",&totalnodes);

    nodelist = (struct node *)malloc(totalnodes*sizeof(struct node));
    for(i = 0; i < totalnodes; i++)
    {
        (*(nodelist + i)).nodeid = i;
        (*(nodelist + i)).parentid = INT_MIN;
        (*(nodelist + i)).sourcedist = INT_MAX;
        (*(nodelist + i)).color = "W";
    }

    adjlist = (struct garph *)malloc(totalnodes*sizeof(struct graph));
    for(i = 0; i < totalnodes; i++)
    {
        (*(adjlist + i)).list = NULL;
        (*(adjlist + i)).count = 0;
    }

    while(choice != 3)
    {
        printf("\n\n 1.) Add Edges. \n 2.) Display \n 3.) Exit. \n Enter your choice: ");
        scanf("%d",&choice);

        switch(choice)
        {
            case 1:
                    printf("\n Enter source and destination vertices for the edge (starting 0): ");
                    scanf("%d %d",&u,&v);
                    addtoadjlist(u,v);
                    //addtoadjlist(v,u);
                    break;
            case 2:
                    disp(totalnodes);
                    //printf("\n Total edges = %d ",disp(totalnodes));     only for non directed graphs.
                    break;
            case 3:
                    break;
            default:
                    printf("\n Invalid input.");
        }
    }

    BFSQf = (int *)malloc(totalnodes*sizeof(int));
    BFSQr = NULL;               // Queue Empty.

    printf("\n Enter source node to apply BFS: ");
    scanf("%d",&s);
    bfs(s);
    dispnodeinfo(totalnodes);

    return 0;
}

输入:6 1 0 1 1 0 3 1 1 4 1 4 3 1 3 1 1 2 4 1 2 5 1 5 5 2 3 3

我得到的邻接清单是:

 node 0 -> 3 -> 1 -> NULL | Degree: 2
 node 1 -> 4 -> NULL | Degree: 1
 node 2 -> 5 -> 4 -> NULL | Degree: 2
 node 3 -> 1 -> NULL | Degree: 1
 node 4 -> 3 -> NULL | Degree: 1
 node 5 -> 5 -> NULL | Degree: 1

这是正确的。但产生的结果是:

 node 0: parent 2147483647| distance from source 984096070| color 
 node 1: parent 1| distance from source 984096072| color 
 node 2: parent 2147483647| distance from source 984096070| color 
 node 3: parent 0| distance from source 984096072| color 
 node 4: parent 2| distance from source 984096072| color 
 node 5: parent 2147483647| distance from source 984096070| color

仅正确分配了节点ID其余都是虚假值。我在main()中的初始赋值后立即调用了displaynodeinfo(),如下所示:

   int main(void)
   {
     ....

    nodelist = (struct node *)malloc(totalnodes*sizeof(struct node));
    for(i = 0; i < totalnodes; i++)
    {
        (*(nodelist + i)).nodeid = i;
        (*(nodelist + i)).parentid = INT_MIN;
        (*(nodelist + i)).sourcedist = INT_MAX;
        (*(nodelist + i)).color = "W";
    }
    displaynodeinfo(totalnodes);
    .....
   }

这里仍然为nodeids分配了虚假的任务。怎么了?请帮忙。

1 个答案:

答案 0 :(得分:1)

您的代码有几个问题。对于初学者,启用所有编译器警告并查看它们。在这种情况下,其中一些实际上是真正的错误。下面是每个警告的快速解释(使用GCC编译时)。

因此,在尝试使用代码调试运行时问题之前,请先验证您是否有无警告代码。

<source>: In function 'dispnodeinfo':
<source>:78:62: warning: format '%d' expects argument of type 'int', but argument 4 has type 'char *' [-Wformat=]
         printf("\n node %d: parent %d| distance from source %d| color %c",(*(nodelist + i)).nodeid,(*(nodelist + i)).sourcedist,(*(nodelist + i)).color);
                                                             ~^                                                                  ~~~~~~~~~~~~~~~~~~~~~~~
                                                             %s

<source>:78:72: warning: format '%c' expects a matching 'int' argument [-Wformat=]
         printf("\n node %d: parent %d| distance from source %d| color %c",(*(nodelist + i)).nodeid,(*(nodelist + i)).sourcedist,(*(nodelist + i)).color);
                                                                       ~^

前两个警告已经暗示为什么你在输出中看到“虚假值”。不仅格式字符串具有不匹配类型,而且您还缺少一个参数。

<source>: In function 'bfs':
<source>:131:45: warning: comparison with string literal results in unspecified behavior [-Waddress]
             if((*(nodelist + nodeid)).color == "W")
                                             ^~

这让您知道将指针与字符串文字进行比较不会达到预期效果。实际上,您应该在结构中使用char,而不是char *;然后在整个代码中使用单个字符文字而不是字符串文字('G'"G")。

<source>: In function 'main':
<source>:160:13: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
     adjlist = (struct garph *)malloc(totalnodes*sizeof(struct graph));
             ^

在这里,编译器会警告您类型名称中的拼写错误(struct garph)。

<source>: In function 'addtoadjlist':
<source>:52:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

<source>: In function 'dispnodeinfo':
<source>:80:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

<source>: In function 'bfs':
<source>:142:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

其余三个警告是关于您声明为返回int而不是void的函数,因为它们不会返回任何内容。