【发布时间】:2018-09-09 14:46:45
【问题描述】:
我编写了一个从数组构造二叉搜索树的 C 程序。它经过以下步骤:
1:使用qsort()对数组进行排序。
2:使用递归函数treeify()将排序好的数组元素放入二叉树中:
2a:取数组的中间元素(将其长度除以 2)并将其作为树结构(此子树的根节点)的 content 字段。
2b:函数然后将剩余元素的左半部分和右半部分复制到较小的数组中,并分别为这些数组中的每一个调用自身。
2c:通过根节点返回树。
3:递归遍历树并以缩进格式打印其内容。
基本上,我使用分而治之的范式从已经排序的数组构建树。令人惊讶的是(因为这是我第一次设计 D&C 算法)这部分进行得相当顺利。
我真正遇到麻烦的地方是第 3 步。有时它有效,当它有效时,所有元素的顺序都正确,所以这部分显然有效。但是在我运行程序的 90% 的情况下,当它到达第一个叶节点时会出现段错误。
这是完整的程序文本。我已经更改了打印功能,以便它打印节点的地址(用于调试目的)。原来是显示数值的……
#include <stdio.h>
#include <stdlib.h>
struct tree {
int content;
struct tree *left;
struct tree *right;
};
struct tree *treeify( int *, size_t );
void printtree( struct tree *, int );
int comp( int *, int * );
int main( int argc, char **argv ){
int array[] = { 5, 6, 7, 2, 3, 4, 9, 1, 8, 0 };
/* Sort array */
qsort( (void *) array, 10, sizeof( int ), (int (*)(const void *, const void *)) &comp );
for( int i = 0; i < 10; i++ ){
printf( "%d ", array[i] );
}
printf( "\n" );
/* Treeify array */
struct tree *rootnode = treeify( array, 10 );
/* Print tree */
printtree( rootnode, 0 );
return 0;
}
// Place sorted array elements in a tree
// Function is called for each subtree
struct tree *treeify( int *array, size_t size ){
struct tree *root = (struct tree *) malloc( sizeof( struct tree ) );
size_t middle = size/2;
int leftsize = middle, rightsize = size-middle-1;
int left[leftsize], right[rightsize];
for( int i = 0; i < leftsize; i++ ) left[i] = array[i];
for( int i = 0; i < rightsize; i++ ) right[i] = array[i+middle+1];
root->content = array[middle];
if( leftsize > 0 ) root->left = treeify( left, leftsize );
if( rightsize > 0 ) root->right = treeify( right, rightsize );
return root;
}
// Print tree contents in indented format
void printtree( struct tree *node, int level ){
for( int i = 0; i < level; i++ ) printf( " " );
printf( "%x\n", &(node->content) );
if( node->left ) printtree( node->left, level+1 );
if( node->right ) printtree( node->right, level+1 );
}
// Comparison function for qsort
int comp( int *xp, int *yp ){
int x = *xp, y = *yp;
if( x < y ) return -1;
if( x > y ) return 1;
return 0;
}
我已经通过在遍历树时打印节点的地址来隔离问题。这是成功运行的输出:
0 1 2 3 4 5 6 7 8 9
cbe00000
cbe00020
cbe00040
cbe00060
cbe00080
cbe000a0
cbe000c0
cbe000e0
cbe00100
cbe00120
还有一次不成功的运行:
f04032b0
f04032d0
f04032f0
f0403310
0
Segmentation fault: 11
请注意,成功的运行如何仅通过树的三个级别,然后返回并返回。不成功的运行经过四个级别,到达一个空指针。
具体来说,当程序到达这一行时:
if( node->left ) printtree( node->left, level+1 );
尽管node->left 评估为零(如输出的第五行所示),但它仍采用分支。
这是我一生无法理解的。该条件显然被评估为假(我已经验证过),但程序仍在使用该分支,就好像它被评估为真(并且仅在大多数情况下,而不是所有情况下)。
这在我之前从未发生过。我需要一个比我更了解 C 的人来为我阐明这一点。
我能想到的唯一可能:
一些古怪的编译器优化
我在某处犯了一个愚蠢的单字符错误
我的 CPU 部分烧坏了
【问题讨论】:
-
两种行为是指一种称为未定义行为的行为。尝试运行valgrind下的代码,检查是否有无效读写。
-
分配新的
tree时,不设置left = right = NULL。 -
是的,解决方案是简单地将
left和right初始化为NULL,您的代码中没有单个NULL。 -
&comp前面的演员表表明您应该更改comp函数的原型以符合要求。
标签: c arrays segmentation-fault binary-tree binary-search-tree