Print binary tree

本文介绍了一个使用队列实现的二叉树数据结构及其可视化方法。通过递归创建平衡二叉树,并采用先序遍历填充节点信息到队列中,最终实现对二叉树结构的打印。文章详细展示了如何计算节点之间的距离、确定每个节点的位置,以及如何逐层打印二叉树。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include 
#include 

#define ARRAY_SIZE (63)
#define NODE_DISTANCE (4)
#define PRINT_OFFSET (2)

typedef enum _CHILD_DIRECTION
{
	LEFT_CHILD = 1,
	RIGHT_CHILD,
	NOT_CHILD,
}CHILD_DIRECTION;

typedef struct _Node {
	int value;
	struct _Node *left;
	struct _Node *right;
}Node;

typedef struct _NodeInfo {
	struct _Node *node;
	struct _NodeInfo *parent;
	int height;
	int offset;
	int distance_between_nodes;
	CHILD_DIRECTION direction;
}NodeInfo;

static int queue_head_idx = 0, queue_tail_idx = 0;
static NodeInfo node_queue[ARRAY_SIZE+1];

static void queue_reset()
{
	queue_head_idx = queue_tail_idx = 0;
}

static int queue_empty()
{
	return queue_head_idx == queue_tail_idx;
}

static int queue_full()
{
	return ((queue_head_idx+1)%(ARRAY_SIZE+1)) == queue_tail_idx;
}

static void queue_insert(NodeInfo node_info)
{
	if (queue_full() == 0)
	{
		node_queue[queue_head_idx] = node_info;
		queue_head_idx++;
		queue_head_idx = queue_head_idx%(ARRAY_SIZE+1);
	}
}

static NodeInfo queue_offer()
{
	NodeInfo ret_node_info = {0};
	if (queue_empty() == 0)
	{
		ret_node_info = node_queue[queue_tail_idx];
		queue_tail_idx++;
		queue_tail_idx = queue_tail_idx%(ARRAY_SIZE+1);
	}
	return ret_node_info;
}

static Node * create_sub_tree(int *src, int start, int end)
{
	Node *node;
	int mid;
	
	if (start > end) return NULL;

	mid = (start + end)/2;

	node = malloc(sizeof(Node));
	if (node)
	{
		node->value = src[mid];
		node->left = create_sub_tree(src, start, mid -1);
		node->right= create_sub_tree(src, mid+1, end);
	}

	return node;
}

static void create_binary_tree(Node** root, int *src, int size)
{
	printf("create_binary_tree begin\n");

	if (root == NULL) return;
 
	*root = create_sub_tree(src, 0, size-1);
	printf("create_binary_tree end\n");
}

static void print_node(int height, NodeInfo *node_info_ordered, int size)
{
	int i, j, node_idx = 0, last_node_level = height;
	NodeInfo *node_info;
	NodeInfo *parent_node;
	int target_offset, current_offset;
	int current_line_width, node_num_in_current_line;
	
	current_offset = 0;
	target_offset = node_info_ordered[node_idx].distance_between_nodes/2 + PRINT_OFFSET;
	node_info_ordered[node_idx].offset = target_offset;
	node_num_in_current_line = 1;

	while(current_offset < target_offset) {
		printf(" ");
		current_offset++;
	}
	
	while (node_idx < size)
	{
		node_info = &node_info_ordered[node_idx];
		
		if(node_info->height != last_node_level)
		{
			printf("\n");

			parent_node = node_info->parent;
			current_line_width = parent_node->distance_between_nodes/2;
			
			current_offset = 0;
			target_offset = parent_node->offset - (current_line_width/2);
			while(current_offset < target_offset) {
				printf(" ");
				current_offset++;
			}

			for(i=0; iheight;
			node_num_in_current_line *= 2;

			current_offset = 0;
		}
		
		parent_node = node_info->parent;
		if(parent_node != NULL)
		{
			if (node_info->direction == LEFT_CHILD)
			{
				node_info->offset = parent_node->offset - (parent_node->distance_between_nodes/4);
			}
			else
			{
				node_info->offset = parent_node->offset + (parent_node->distance_between_nodes/4);
			}
		}

		target_offset = node_info->offset;
		while(current_offset < target_offset) {
			printf(" ");
			current_offset++;
		}
		current_offset += printf("%d", node_info->node->value);

		node_idx++;
	}

	printf("\n");
}



static int preordering_traverse(int height, Node* root, NodeInfo *node_info_ordered)
{
	NodeInfo node_info = {0};
	Node* node;
	int idx = 0, h;
	int i=1, distance_between_nodes = NODE_DISTANCE;
	while(ileft)
		{
			node_info.node = node->left;
			node_info.height = h-1;
			node_info.parent = &node_info_ordered[idx-1];
			node_info.distance_between_nodes = node_info.parent->distance_between_nodes/2;
			node_info.direction = LEFT_CHILD;
			queue_insert(node_info);
		}

		if (node->right)
		{
			node_info.node = node->right;
			node_info.height = h-1;
			node_info.parent = &node_info_ordered[idx-1];;
			node_info.distance_between_nodes = node_info.parent->distance_between_nodes/2;
			node_info.direction = RIGHT_CHILD;
			queue_insert(node_info);
		}
	}
	return idx;
}

#define TREE_MAX(a,b) (((a)>(b))?(a):(b))
static int calc_tree_height(Node* root)
{
	if(root != NULL)
		return TREE_MAX(1+calc_tree_height(root->left), 1+calc_tree_height(root->right));
	else
		return 0;
}

static void print_tree(Node* root)
{
	int height, offset, size;
	Node *node = root;
	NodeInfo node_queue_ordered[ARRAY_SIZE+1];
	
	height = calc_tree_height(root);

	printf("print_tree height = %d\n", height);

	size = preordering_traverse(height, root, node_queue_ordered);

	print_node(height, node_queue_ordered, size);

	queue_reset();
}

int main()
{
	int a[ARRAY_SIZE] = {3,5,5,1,2,6,8,4,7,9, \
		3,5,5,1,2,6,8,4,7,9, \
		3,5,5,1,3,5,5,1,2,6, \
		8,4,7,9,3,5,5,1,2,6, \
		3,5,5,1,3,5,5,1,2,6, \
		8,4,7,9,3,5,5,1,8,4, \
		7,9,3};
	Node* root;

	printf("print binary tree begin\n");

	create_binary_tree(&root, a, ARRAY_SIZE);

	print_tree(root);
	
	printf("print binary tree end\n");

	return 0;
}
### 顺序存储二叉树的前序、中序和后序遍历非递归算法 #### 背景说明 顺序存储二叉树通常采用数组形式实现,其中父节点 `i` 的左子节点位于索引位置 `2*i+1`,右子节点位于索引位置 `2*i+2`。基于此特性,可以利用栈模拟递归过程完成前序、中序和后序遍历。 以下是具体的非递归实现代码: --- #### 前序遍历(Preorder Traversal) 前序遍历遵循 **根 -> 左 -> 右** 的顺序。通过栈保存未访问过的节点,并优先访问其左子节点。 ```c #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 typedef struct { int data[MAX_SIZE]; int top; } Stack; void initStack(Stack *s) { s->top = -1; } int isEmpty(Stack *s) { return s->top == -1; } void push(Stack *s, int value) { if (s->top >= MAX_SIZE - 1) { printf("Stack Overflow\n"); exit(1); } s->data[++(s->top)] = value; } int pop(Stack *s) { if (isEmpty(s)) { printf("Stack Underflow\n"); exit(1); } return s->data[(s->top)--]; } // Preorder traversal of a binary tree stored in an array void preorder(int *tree, int size) { if (!tree || size <= 0) return; Stack stack; initStack(&stack); int i = 0; // Start from the root node at index 0 while (i < size || !isEmpty(&stack)) { while (i < size && tree[i] != -1) { // Traverse to the leftmost child printf("%d ", tree[i]); push(&stack, i); // Push current index onto the stack i = 2 * i + 1; // Move to the left child } if (!isEmpty(&stack)) { i = pop(&stack); // Backtrack one level up i = 2 * i + 2; // Move to the right child } } } ``` --- #### 中序遍历(Inorder Traversal) 中序遍历遵循 **左 -> 根 -> 右** 的顺序。同样借助栈保存路径上的节点,在回溯过程中依次访问这些节点。 ```c // Inorder traversal of a binary tree stored in an array void inorder(int *tree, int size) { if (!tree || size <= 0) return; Stack stack; initStack(&stack); int i = 0; // Start from the root node at index 0 while (i < size || !isEmpty(&stack)) { while (i < size && tree[i] != -1) { // Traverse to the leftmost child push(&stack, i); // Push current index onto the stack i = 2 * i + 1; // Move to the left child } if (!isEmpty(&stack)) { i = pop(&stack); // Visit the parent node after all its left children are visited printf("%d ", tree[i]); i = 2 * i + 2; // Move to the right child } } } ``` --- #### 后序遍历(Postorder Traversal) 后序遍历遵循 **左 -> 右 -> 根** 的顺序。为了简化逻辑,引入额外标记变量记录当前状态。 ```c // Postorder traversal of a binary tree stored in an array using two stacks void postorder(int *tree, int size) { if (!tree || size <= 0) return; Stack stack1, stack2; initStack(&stack1); initStack(&stack2); push(&stack1, 0); // Start with the root node while (!isEmpty(&stack1)) { int i = pop(&stack1); // Pop and move it to another stack push(&stack2, i); if (2 * i + 1 < size && tree[2 * i + 1] != -1) { push(&stack1, 2 * i + 1); // Push left child first } if (2 * i + 2 < size && tree[2 * i + 2] != -1) { push(&stack1, 2 * i + 2); // Then push right child } } while (!isEmpty(&stack2)) { int i = pop(&stack2); printf("%d ", tree[i]); // Print nodes in reverse order } } ``` --- ### 总结 以上实现了顺序存储二叉树的前序、中序和后序遍历非递归版本[^1][^2][^3]。每种遍历方式的核心在于如何合理使用栈来控制访问次序以及处理左右子节点的关系。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值