【问题标题】:BFS algorithm in C [closed]C中的BFS算法[关闭]
【发布时间】:2014-01-20 15:32:27
【问题描述】:

我正在尝试在 C 中找到一种 BFS 算法,但我找不到真正有效的算法。我有一个二叉堆(树实现),我想做的是使用 BFS 算法来找到在我的树中插入新元素的正确位置。

P.S 我不知道要插入的元素的确切数量(如果有帮助的话)。

【问题讨论】:

标签: c algorithm binary-tree breadth-first-search


【解决方案1】:

插入基于数组的二进制堆的过程是:

  1. 将新项目添加到堆的末尾
  2. 冒泡

在数组实现中,添加到堆的末尾是微不足道的。

在基于树的实现中,您确定节点的路径,然后从根向下遍历该路径,一边进行筛选。您必须知道堆中已经有多少项,并且在开始时树是正确平衡的。

比如说,堆中有4个节点:

    0
  1   2
3

您添加的下一个节点将进入位置 4 - 节点 1 的右子节点。因此您的工作是确定位置 4 的位置。更准确地说,您必须确定哪个节点是位置 4 的父节点。

如果根节点为0,那么任何节点的父节点都是节点(i-1)/2。所以节点4的父节点是节点1,节点1的父节点是节点0。

您可以编写一个递归函数,给定一个节点号,它将遍历树以找到到父节点的路径。在退出递归的过程中,您实际上最终会在树中筛选节点而不是将其冒泡,但复杂度是相同的:O(log n)。

请注意,这不会进行广度优先搜索。 BFS 将是一种极其低效的做事方式。

其他信息

“偶数”或“奇数”情况不需要特殊处理。这一切都隐含在树结构中。考虑这种方法,它会为您提供从根到树中插入点的路径:

(我的示例是用 C# 编写的,只是因为这就是我这些天使用的。你应该能够轻松转换为 C。)

private void HeapInsert(int node)
{
    if (node == 0)
        return;
    int parent = (node - 1)/2;
    HeapInsert(parent);
    Console.WriteLine("From node {0}, take {1} child to node {2}", parent, (node%2) == 0 ? "right" : "left", node);
}

我已经对其进行了简化,它只显示整数节点号,而不是进行实际的堆插入。您可以轻松地修改代码,而不是输出路径,而是为您提供从根到插入点的路径中的实际节点。

根据您的实现,您可以遍历该路径,将节点插入适当的位置,然后将其冒泡。或者,您可以遍历从根到叶的路径,在此过程中筛选新项目。

【讨论】:

  • 我使用这篇帖子的最后一个答案stackoverflow.com/questions/500057/… 来解决我的问题。它适用于“完整二进制堆”和“偶数”情况,但对于“奇数”情况,该算法似乎不起作用。节点 findParentOfLastNode(Node root ,Node lastNode){ if(root == null) return root; if( root.left == lastNode || root.right == lastNode ) 返回根;节点 n1=findParentOfLastNode(root.left,lastNode);节点 n2=findParentOfLastNode(root.left,lastNode);返回 n1 != null ? n1:n2; } 有什么建议吗?
  • @matrix:是的。我的建议是不要那样做。当您可以使用 O(log n) 算法直接访问节点时,没有理由产生 BFS 的 O(n) 成本。
  • 那么我该如何处理“奇怪”的情况。在完整的情况下,我将新节点添加到左孩子的左孩子的左孩子。在“偶数”情况下,我使用“lastnode”指针来查找我要插入的节点的父节点。最后一个案例呢。例如,一棵树有 5 个元素,我想在其中插入第 6 个元素。
  • @matrix:查看我的更新回复。我没有时间为您编写完整的堆实现,因此您必须按照我的提示进行操作。或不。如果您确定并决心使用广度优先搜索,那么这个答案不适合您。
  • 经过几个小时我终于让它工作了:P 我想知道是否也有任何类似的删除递归算法。 ^^(其实我对“DownReHeapify”算法很感兴趣)
【解决方案2】:

插入二进制堆不需要使用 BFS。

【讨论】:

  • 要学习二进制堆和/或 BFS,“算法简介”是一个好的开始。
  • 我知道如何将元素插入到用数组实现的二进制堆中,但是对于树实现(结构),我认为我需要 BFS。
  • 如果使用 BFS 插入元素,插入元素时会得到 O(n)。我建议你使用指针模拟基于数组的堆中的操作,插入时会得到 O(logn)。这个想法是使用指针和倒置堆调整操作。
【解决方案3】:

从书中出现的程序中提取的通用实现怎么样:

《编程挑战:编程竞赛培训手册》作者 Steven Skiena 和 Miguel Revilla,Springer-Verlag,纽约,2003 年。

#define TRUE    1
#define FALSE   0
#define MAXV        100     /* maximum number of vertices */
#define MAXDEGREE   50      /* maximum outdegree of a vertex */

typedef struct {
    int edges[MAXV+1][MAXDEGREE];   /* adjacency info */
    int degree[MAXV+1];     /* outdegree of each vertex */
    int nvertices;          /* number of vertices in the graph */
    int nedges;         /* number of edges in the graph */
} graph;
#define QUEUESIZE       1000

typedef struct {
        int q[QUEUESIZE+1];     /* body of queue */
        int first;                      /* position of first element */
        int last;                       /* position of last element */
        int count;                      /* number of queue elements */
} queue;

typedef int bool;


    bool processed[MAXV];   /* which vertices have been processed */
    bool discovered[MAXV];  /* which vertices have been found */
    int parent[MAXV];   /* discovery relation */

    bool finished = FALSE;  /* if true, cut off search immediately */

    initialize_search(graph *g)
    {
            int i;                          /* counter */

            for (i=1; i<=g->nvertices; i++) {
                    processed[i] = discovered[i] = FALSE;
                    parent[i] = -1;
            }
    }

    bfs(graph *g, int start)
    {
        queue q;            /* queue of vertices to visit */
        int v;              /* current vertex */
        int i;              /* counter */

        init_queue(&q);
        enqueue(&q,start);
        discovered[start] = TRUE;

        while (empty(&q) == FALSE) {
            v = dequeue(&q);
            process_vertex(v);
            processed[v] = TRUE;
            for (i=0; i<g->degree[v]; i++) 
                if (valid_edge(g->edges[v][i]) == TRUE) {
                if (discovered[g->edges[v][i]] == FALSE) {
                    enqueue(&q,g->edges[v][i]);
                    discovered[g->edges[v][i]] = TRUE;
                    parent[g->edges[v][i]] = v;
                }
                if (processed[g->edges[v][i]] == FALSE) 
                    process_edge(v,g->edges[v][i]);
                }
        }
    }


    /*
    bool valid_edge(edge e)
    {
        if (e.residual > 0) return (TRUE);
        else return(FALSE);
    }
    */


    dfs(graph *g, int v)
    {
        int i;              /* counter */
        int y;              /* successor vertex */

        if (finished) return;       /* allow for search termination */

        discovered[v] = TRUE;
        process_vertex(v);

        for (i=0; i<g->degree[v]; i++) {
            y = g->edges[v][i];
            if (valid_edge(g->edges[v][i]) == TRUE) {
                if (discovered[y] == FALSE) {
                    parent[y] = v;
                    dfs(g,y);
                } else 
                    if (processed[y] == FALSE)
                        process_edge(v,y);
            }
            if (finished) return;
        }

        processed[v] = TRUE;
    }


    find_path(int start, int end, int parents[])
    {
        if ((start == end) || (end == -1))
            printf("\n%d",start);
        else {
            find_path(start,parents[end],parents);
            printf(" %d",end);
        }
    }

/*The testing part*/
process_vertex(int v)
{
    printf("processed vertex %d\n",v);
}

process_edge(int x, int y)
{
        printf("processed edge (%d,%d)\n",x,y);
}


bool valid_edge(int e)
{
        return (TRUE);
}


int main()
{
    graph g;
    int i;

    read_graph(&g,FALSE);
    print_graph(&g);
    initialize_search(&g);
    bfs(&g,1);
    for (i=1; i<=g.nvertices; i++)
        printf(" %d",parent[i]);
    printf("\n");

    for (i=1; i<=g.nvertices; i++) 
        find_path(1,i,parent);
    printf("\n");
        return 0;
}

这是图表部分:

initialize_graph(graph *g)
{
    int i;              /* counter */

    g -> nvertices = 0;
    g -> nedges = 0;

    for (i=1; i<=MAXV; i++) g->degree[i] = 0;
}

read_graph(graph *g, bool directed)
{
    int i;              /* counter */
    int m;              /* number of edges */
    int x, y;           /* vertices in edge (x,y) */

    initialize_graph(g);

    scanf("%d %d",&(g->nvertices),&m);

    for (i=1; i<=m; i++) {
        scanf("%d %d",&x,&y);
        insert_edge(g,x,y,directed);
    }
}

insert_edge(graph *g, int x, int y, bool directed)
{
    if (g->degree[x] > MAXDEGREE)
        printf("Warning: insertion(%d,%d) exceeds max degree\n",x,y);

    g->edges[x][g->degree[x]] = y;
    g->degree[x] ++;

    if (directed == FALSE)
        insert_edge(g,y,x,TRUE);
    else
        g->nedges ++;
}


delete_edge(graph *g, int x, int y, bool directed)
{
    int i;              /* counter */

    for (i=0; i<g->degree[x]; i++) 
        if (g->edges[x][i] == y) {
            g->degree[x] --;
            g->edges[x][i] = g->edges[x][g->degree[x]];

            if (directed == FALSE)
                delete_edge(g,y,x,TRUE);

            return;
        }

    printf("Warning: deletion(%d,%d) not found in g.\n",x,y);
}

print_graph(graph *g)
{
    int i,j;            /* counters */

    for (i=1; i<=g->nvertices; i++) {
        printf("%d: ",i);
        for (j=0; j<g->degree[i]; j++)
            printf(" %d",g->edges[i][j]);
        printf("\n");
    }
}

这里是队列

init_queue(queue *q)
{
        q->first = 0;
        q->last = QUEUESIZE-1;
        q->count = 0;
}

enqueue(queue *q, int x)
{
        if (q->count >= QUEUESIZE)
        printf("Warning: queue overflow enqueue x=%d\n",x);
        else {
                q->last = (q->last+1) % QUEUESIZE;
                q->q[ q->last ] = x;    
                q->count = q->count + 1;
        }
}

int dequeue(queue *q)
{
        int x;

        if (q->count <= 0) printf("Warning: empty queue dequeue.\n");
        else {
                x = q->q[ q->first ];
                q->first = (q->first+1) % QUEUESIZE;
                q->count = q->count - 1;
        }

        return(x);
}

int empty(queue *q)
{
        if (q->count <= 0) return (TRUE);
        else return (FALSE);
}

print_queue(queue *q)
{
        int i,j;

        i=q->first; 

        while (i != q->last) {
                printf("%c ",q->q[i]);
                i = (i+1) % QUEUESIZE;
        }

        printf("%2d ",q->q[i]);
        printf("\n");
}

【讨论】:

    【解决方案4】:

    使用这个功能

    void bfs(int v)
    {
        for(i=1;i<=n;i++)
        if(a[v][i] && !visited[i])
        q[++r]=i;
        if(f<=r)
        {
                   visited[q[f]]=1;
                   bfs(q[f++]);
        }
    }
    

    递归可能会解决您的问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-19
      • 2010-10-19
      • 1970-01-01
      • 1970-01-01
      • 2014-11-19
      • 1970-01-01
      相关资源
      最近更新 更多