【发布时间】:2014-01-20 15:32:27
【问题描述】:
我正在尝试在 C 中找到一种 BFS 算法,但我找不到真正有效的算法。我有一个二叉堆(树实现),我想做的是使用 BFS 算法来找到在我的树中插入新元素的正确位置。
P.S 我不知道要插入的元素的确切数量(如果有帮助的话)。
【问题讨论】:
标签: c algorithm binary-tree breadth-first-search
我正在尝试在 C 中找到一种 BFS 算法,但我找不到真正有效的算法。我有一个二叉堆(树实现),我想做的是使用 BFS 算法来找到在我的树中插入新元素的正确位置。
P.S 我不知道要插入的元素的确切数量(如果有帮助的话)。
【问题讨论】:
标签: c algorithm binary-tree breadth-first-search
插入基于数组的二进制堆的过程是:
在数组实现中,添加到堆的末尾是微不足道的。
在基于树的实现中,您确定节点的路径,然后从根向下遍历该路径,一边进行筛选。您必须知道堆中已经有多少项,并且在开始时树是正确平衡的。
比如说,堆中有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);
}
我已经对其进行了简化,它只显示整数节点号,而不是进行实际的堆插入。您可以轻松地修改代码,而不是输出路径,而是为您提供从根到插入点的路径中的实际节点。
根据您的实现,您可以遍历该路径,将节点插入适当的位置,然后将其冒泡。或者,您可以遍历从根到叶的路径,在此过程中筛选新项目。
【讨论】:
插入二进制堆不需要使用 BFS。
【讨论】:
从书中出现的程序中提取的通用实现怎么样:
《编程挑战:编程竞赛培训手册》作者 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");
}
【讨论】:
使用这个功能
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++]);
}
}
递归可能会解决您的问题
【讨论】: