[英]Level Order Binary Tree Traversal Implementation with Queue
我正在尝试实现一个levelOrder函数,它接受树的指针并逐级打印树的数据。 这是C How to Program一书中的一个问题,完整的问题如下:
(Level Order Binary Tree Traversal) 图 12.19 的程序说明了遍历二叉树的三种递归方法——中序遍历、前序遍历和后序遍历。 本练习展示了二叉树的层序遍历,其中节点值从根节点级别开始逐级打印。 每个级别上的节点从左到右打印。 层序遍历不是递归算法。 它使用队列数据结构来控制节点的输出。 算法如下:
在队列中插入根节点
当队列中还有节点时,
获取队列中的下一个节点
打印节点的值
如果指向节点左子节点的指针不为NULL,则将左子节点插入队列
如果指向节点右子节点的指针不为NULL
在队列中插入右子节点。编写函数 levelOrder 来执行二叉树的层序遍历。 该函数应将指向二叉树根节点的指针作为参数。 修改图 12.19 的程序以使用该功能。 将此函数的输出与其他遍历算法的输出进行比较,看看它是否正常工作。 [注意:您还需要在此程序中修改和合并图 12.13 的队列处理功能。]
我的尝试如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct treeNode{
struct treeNode* left;
int data;
struct treeNode* right;
};
struct queueNode{
struct treeNode* tree;
struct queueNode* next;
};
/* prototype */
void insert(struct treeNode**, int); // tree creator
void levelOrder(struct treeNode**);
void inOrder(struct treeNode*);
void enqueue(struct queueNode**, struct queueNode**, struct treeNode*);
struct treeNode* dequeue(struct queueNode**, struct queueNode**);
int main(){
struct treeNode* root = NULL;
levelOrder(&root);
}
void insert(struct treeNode** root, int val){
if(!(*root)){ // when root is empty
*root = (struct treeNode*)malloc(sizeof(struct treeNode));
if(*root){ // if allocation is achieved
(*root) -> data = val;
(*root) -> right = NULL;
(*root) -> left = NULL;
} else { // if allocation is not succesfull
printf("%s\n", "[ERROR] Not enough memory space for allocation!");
}
} else { // if root is not empty
if(val > (*root) -> data)
insert(&(*root) -> right, val);
else if(val < (*root) -> data)
insert(&(*root) -> left, val);
}
}
void enqueue(struct queueNode** head, struct queueNode** tail, struct treeNode* tree){
struct queueNode* newNode = (struct queueNode*)malloc(sizeof(struct queueNode));
if( newNode ){
newNode -> tree = tree;
newNode -> next = NULL;
if(!(*head)){
*head = newNode;
//printf("head->tree->data:%d --> ", (*head)->tree->data);
printf("%d --> ", (*head)->tree->data);
}
else{
(*tail) -> next = newNode;
//printf("tail->tree->data:%d --> ", (*tail)->tree->data);
printf("%d --> ", (*tail)->tree->data);
}
(*tail) = newNode;
} else {
printf("%s\n", "[ERROR] Not enough memory space for allocation!");
}
}
struct treeNode* dequeue(struct queueNode** head, struct queueNode** tail){
struct treeNode* val = (*head)->tree;
struct queueNode* temp = *head;
*head = (*head) -> next;
if(!(*head))
*tail = NULL;
return val;
}
void levelOrder(struct treeNode** root){
struct treeNode* output = NULL;
struct queueNode* head = NULL, *tail = NULL;
size_t i;
srand(time(NULL));
for(i = 0; i < 9; ++i){
insert(root, 1 + rand()%16);
}
puts("in order");
inOrder(*root);
puts("NULL");
puts("After in order");
enqueue(&head, &tail, *root);
while(head){
if(head->tree->left)
enqueue(&head, &tail, head->tree->left);
if(head->tree->right)
enqueue(&head, &tail, head->tree->right);
head = head->next;
}
/*for(i=0;i<9;++i){
output = dequeue(&head, &tail);
printf("%d",output->data);
}*/
}
void inOrder(struct treeNode* tree){ // used to be sure if my implementation works correct
if(tree != NULL){
inOrder(tree->left);
printf("%-2d-->", tree->data);
inOrder(tree->right);
}
}
当我使用出队功能时,它无法正常工作。 我无法使用出队功能获取队列中的所有树。 但是,如果我在 enqueue 中打印值,如所见,它会打印所有添加的值,除了一个(我不知道是哪个),但会打印第一个值两次。 (你能运行代码吗?我想把输出放在这里,但 stackoverflow 认为它是一个代码块,我无法编辑它,所以它没有让我添加它。)
一些问题:
在enqueue
,在else
块中,在移动之前打印tail
的值:这可能会误导输出的阅读器,因为该值不是附加到队列的值。 我认为这是为了调试,但最后你不应该在这里打印。
在主循环中,您不应该像那样移动head
参考。 而是在循环开始时使用dequeue
,并捕获您已经声明的output
变量中的节点,并立即打印相应的值。 这将使队列保持在不超过必要长度的大小。
while(head){ output = dequeue(&head, &tail); // extract printf("%d --> ", output->data); // print here instead of in enqueue if(output->left) // use output enqueue(&head, &tail, output->left); if(output->right) enqueue(&head, &tail, output->right); // Don't move head here } puts("\\n");
在dequeue
您应该在return
之前释放从队列中删除的队列节点:
free(temp);
其他一些注意事项:
levelOrder
不应该真正负责构建树。 在您的主驱动程序代码中执行此操作,或者——如果您真的想要——在单独的函数中执行此操作。 然后将levelOrder
的第二个参数levelOrder
struct treeNode *
而不是struct treeNode **
。
对于调试,您的inOrder
实现将值打印在单独的行上并带有对应于递归深度的缩进,您可以为此传递一个额外的int depth
参数。 这样你就可以对实际的树结构有一些直观的了解。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.