解析二叉树相关面试题

一、BTree.h

#ifndef __BTree_h__
#define __BTree_h__

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <Windows.h>

typedef int BTDataType;

typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* _left; //左孩子
	struct BinaryTreeNode* _right; //右孩子
	BTDataType _data; //节点数据
}BTNode;

BTNode* BuyBTNode(BTDataType x);
BTNode* CreateBTree(BTDataType* a, size_t* pIndex, BTDataType invalid);

void BTreePrevOrder(BTNode* root);
void BTreeInOrder(BTNode* root);
void BTreePostOrder(BTNode* root);
void BTreeLevelOrder(BTNode* root);

size_t BTreeSize(BTNode* root);
size_t BTreeLeafSize(BTNode* root);
size_t BTreeKLevelSize(BTNode* root, size_t k);
size_t BTreeDepth(BTNode* root);
BTNode* BTreeFind(BTNode* root, BTDataType x);

int IsCompleteBTree(BTNode* root);
int IsCompleteBTree1(BTNode* root);
 
void BTreePrevOrderNonR(BTNode* root);
void BTreeInOrderNonR(BTNode* root);
void BTreePostOrderNonR(BTNode* root);

#endif __BTree_h__

二、Queue.h

#ifndef __Queue_h__
#define __Queue_h__

#include "BTree.h"

typedef BTNode* QDataType;

typedef struct QueueNode
{
	QDataType _data;
	struct QueueNode* _next;
}QueueNode;

typedef struct Queue
{
	QueueNode* _head; //队头指针
	QueueNode* _tail; //队尾指针
}Queue;

//初始化
void QueueInit(Queue* q)
{
	assert(q);
	q->_head = q->_tail = (QueueNode*)malloc(sizeof(QueueNode));
	assert(q->_head&&q->_tail);
	q->_head->_next = NULL;
}

//销毁
void QueueDestroy(Queue* q)
{
	assert(q);
	while (q->_head)
	{
		q->_tail = q->_head->_next;
		free(q->_head);
		q->_head = q->_tail;
	}
}

//入队
void QueuePush(Queue* q, QDataType x)
{
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	assert(newnode);
	newnode->_data = x;
	newnode->_next = NULL;
	q->_tail->_next = newnode;
	q->_tail = newnode;
}

//出队
void QueuePop(Queue* q)
{
	if (q->_head == q->_tail)
	{
		return;
	}
	QueueNode* next = q->_head->_next;
	q->_head->_next = next->_next;
	if (q->_tail == next)
	{
		q->_tail = q->_head;
	}
	free(next);
}

//获取队头元素
QDataType QueueFront(Queue* q)
{
	if (q->_head == q->_tail)
	{
		return NULL;
	}
	else
	{
		return q->_head->_next->_data;
	}
}

//判空
int QueueEmpty(Queue* q)
{
	if (q->_head == q->_tail)
	{
		return 1;
	}
	return 0;
}

#endif __Queue_h__

三、stack.h

#ifndef __stack_h__
#define __stack_h__

#include "BTree.h"

#define Initsize 5 //初始存储空间
#define Increment 2 //每次增量

typedef BTNode* SDataType;

typedef struct Stack
{
	SDataType* _array;
	size_t _size; //有效数据个数 
	size_t _capacity; //容量 
}Stack;

//初始化
void StackInit(Stack* s)
{
	assert(s);
	s->_size = 0;
	s->_capacity = Initsize;
	s->_array = (SDataType*)malloc(Initsize*sizeof(SDataType));
	if (s->_array == NULL)
	{
		perror("StackInit");
		return;
	}
	memset(s->_array, 0, s->_capacity * sizeof(SDataType));
}

//扩容
void CheckCapacity(Stack* s)
{
	assert(s);
	if (s->_size >= s->_capacity)
	{
		SDataType* ptr = (SDataType*)realloc(s->_array, (s->_capacity + Increment)*sizeof(SDataType));
		if (ptr == NULL)
		{
			perror("CheckCapacity");
		}
		else
		{
			s->_array = ptr;
			s->_capacity += Increment;
		}
	}
}

//入栈
void StackPush(Stack* s, SDataType x)
{
	assert(s);
	CheckCapacity(s);
	s->_array[s->_size] = x;
	s->_size++;
}

//出栈
void StackPop(Stack* s)
{
	assert(s);
	if (s->_size == 0)
	{
		return;
	}
	else
	{
		s->_size--;
	}
}

//获取栈顶元素
SDataType StackTop(Stack* s)
{
	assert(s);
	if (s->_size == 0)
	{
		return NULL;
	}
	return s->_array[(s->_size) - 1];
}

//判空
int StackEmpty(Stack* s)
{
	assert(s);
	if (s->_size)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

#endif __stack_h__

四、BTree.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "BTree.h"
#include "Queue.h"
#include "stack.h"

//创建节点
BTNode* BuyBTNode(BTDataType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	assert(node);
	node->_data = x;
	node->_left = NULL;
	node->_right = NULL;
	return node;
}

//创建二叉树
BTNode* CreateBTree(BTDataType* a, size_t* pIndex, BTDataType invalid) //
{
	BTNode* root = NULL;
	if (a[*pIndex] != invalid)
	{
		root = BuyBTNode(a[*pIndex]);
		(*pIndex)++;
		root->_left = CreateBTree(a, pIndex, invalid); //左递归
		(*pIndex)++;
		root->_right = CreateBTree(a, pIndex, invalid); //右递归
	}
	return root;
}

//先序遍历
void BTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->_data); //访问根
	BTreePrevOrder(root->_left); //左递归
	BTreePrevOrder(root->_right); //右递归
}

//中序遍历
void BTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BTreeInOrder(root->_left); //左递归
	printf("%d ", root->_data); //访问根
	BTreeInOrder(root->_right); //右递归
}

//后序遍历
void BTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BTreePostOrder(root->_left); //左递归
	BTreePostOrder(root->_right); //右递归
	printf("%d ", root->_data); //访问根
}

//层序遍历
void BTreeLevelOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		QDataType first = QueueFront(&q);
		QueuePop(&q);
		printf("%d ", first->_data);
		if (first->_left)
		{
			QueuePush(&q, first->_left);
		}
		if (first->_right)
		{
			QueuePush(&q, first->_right);
		}
	}
}

//总节点数
//子问题:每棵树的节点数=该树的根节点(1)+左子树的节点数+右子树的节点数
size_t BTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 + BTreeSize(root->_left) + BTreeSize(root->_right);
}

//叶子节点数
//子问题:每棵树的叶子节点数=左子树的叶子节点数+右子树的叶子节点数
size_t BTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	else if (root->_left == NULL&&root->_right == NULL)
	{
		return 1;
	}
	return BTreeLeafSize(root->_left) + BTreeLeafSize(root->_right);
}

//第K层节点数
//子问题:每棵树的第K层节点数=左子树的第k-1层节点数+右子树的第k-1层节点数
size_t BTreeKLevelSize(BTNode* root, size_t k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BTreeKLevelSize(root->_left, k - 1) + BTreeKLevelSize(root->_right, k - 1);
}

//深度
//子问题:每棵树的深度=左子树深度和右子树深度两者较大值+1
size_t BTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	size_t LeftDepth = BTreeDepth(root->_left);
	size_t RightDepth = BTreeDepth(root->_right);
	return LeftDepth > RightDepth ? (LeftDepth + 1) : (RightDepth + 1);
}

//查找
BTNode* BTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->_data == x)
	{
		return root;
	}
	BTNode* ret = BTreeFind(root->_left, x);
	if (ret)
	{
		return ret;
	}
	return BTreeFind(root->_right, x);
}

//判断完全二叉树 
int IsCompleteBTree(BTNode* root)
{
	if (root == NULL)
	{
		return 1;
	}
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q)) //找到队列里的第一个NULL
	{
		QDataType first = QueueFront(&q);
		if (first == NULL)
		{
			break;
		}
		QueuePop(&q);
		QueuePush(&q, first->_left);
		QueuePush(&q, first->_right);
	}
	while (!QueueEmpty(&q)) //从第一个NULL后,判断是否有非NULL值出现
	{
		QDataType first = QueueFront(&q);
		if (first) //若出现非NULL值,则为非完全二叉树
		{
			return 0;
		}
		QueuePop(&q);
	}
	return 1; //直到队列为空也没有出现非NULL值,则为完全二叉树
}

//判断完全二叉树,flag的方式判断 
int IsCompleteBTree1(BTNode* root)
{
	if (root == NULL)
	{
		return 1;
	}
	int flag = 0;
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		QDataType first = QueueFront(&q);
		QueuePop(&q);
		if (first->_left==NULL) //左子树
		{
			flag = 1;
		}
		else
		{
			if (flag == 1)
			{
				return 0;
			}
			QueuePush(&q, first->_left);
		}
		if (first->_right == NULL) //右子树
		{
			flag = 1;
		}
		else
		{
			if (flag == 1)
			{
				return 0;
			}
			QueuePush(&q, first->_right);
		}
	}
	return 1;
}

//非递归先序遍历
void BTreePrevOrderNonR(BTNode* root)
{
	Stack s;
	StackInit(&s);
	BTNode* cur = root;
	while (cur || StackEmpty(&s) != 0) 
		//如果cur非NULL,则说明当前节点未遍历;如果栈s不为空,则说明右子树未遍历;只有当两个都为0时,才说明整个树遍历完
	{
		while (cur)
		{
			printf("%d ", cur->_data);
			StackPush(&s, cur);
			cur = cur->_left;
		}
		BTNode* top = StackTop(&s);
		StackPop(&s);
		cur = top->_right;
	}
}

//非递归中序遍历
void BTreeInOrderNonR(BTNode* root)
{
	Stack s;
	StackInit(&s);
	BTNode* cur = root;
	while (cur || StackEmpty(&s) != 0)
	{
		while (cur)
		{
			StackPush(&s, cur);
			cur = cur->_left;
		}
		BTNode* top = StackTop(&s);
		printf("%d ", top->_data);
		StackPop(&s);
		cur = top->_right;
	}
}

//非递归后序遍历
void BTreePostOrderNonR(BTNode* root)
{
	Stack s;
	StackInit(&s);
	BTNode* cur = root;
	BTNode* last = NULL; //last记录上一次访问节点,作为右子树访问标记
	while (cur || StackEmpty(&s) != 0)
	{
		while (cur)
		{
			StackPush(&s, cur);
			cur = cur->_left;
		}
		BTNode* top = StackTop(&s);
		if (top->_right == last || top->_right == NULL) //如果top->_right == last,说明右子树上次已访问过
		{
			printf("%d ", top->_data);
			last = top; //更新last
			StackPop(&s);
		}
		else
		{
			cur = top->_right;
		}
	}
}

五、test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "BTree.h"

int main()
{
	//int a[] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6, '#', '#', '#' };
	int a[] = { 1, 2, 3, '#', '#', '#', 5, 6, '#', '#', '#' };
	size_t index = 0;

	BTNode* tree = CreateBTree(a, &index, '#');
	printf("先序遍历:");
	BTreePrevOrder(tree);
	printf("\n");

	printf("非递归先序遍历:");
	BTreePrevOrderNonR(tree);
	printf("\n");

	printf("中序遍历:");
	BTreeInOrder(tree);
	printf("\n"); 

	printf("非递归中序遍历:");
	BTreeInOrder(tree);
	printf("\n");

	printf("后序遍历:");
	BTreePostOrder(tree);
	printf("\n");

	printf("非递归后序遍历:");
	BTreePostOrder(tree);
	printf("\n");

	printf("层序遍历:");
	BTreeLevelOrder(tree);
	printf("\n");

	printf("总节点数:%d\n", BTreeSize(tree));
	printf("叶子节点数:%d\n", BTreeLeafSize(tree));
	printf("第%d层节点数:%d\n", 2, BTreeKLevelSize(tree, 2));
	printf("深度:%d\n", BTreeDepth(tree));
	printf("是否为完全二叉树?%d\n", IsCompleteBTree(tree));
	printf("是否为完全二叉树?%d\n", IsCompleteBTree1(tree));

	if (BTreeFind(tree, 4))
	{
		printf("找到了\n");
	}
	else
	{
		printf("未找到\n");
	}

	system("pause");
	return 0;
}

执行结果

(1)int a[] = { 1, 2, 3, ‘#’, ‘#’, 4, ‘#’, ‘#’, 5, 6, ‘#’, ‘#’, ‘#’ };
这里写图片描述

(2)int a[] = { 1, 2, 3, ‘#’, ‘#’, ‘#’, 5, 6, ‘#’, ‘#’, ‘#’ };
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python二叉树面试题有很多种,以下是其中几个常见的面试题: 1. 二叉树的最大深度:这个问题要求计算给定二叉树的最大深度。可以使用递归的方法来解决,递归函数的定义是返回当前节点的深度,递归终止条件是节点为空时返回0,递归过程中比较左右子树的深度并返回较大值加1。时间复杂度为O(n),空间复杂度为O(n)。 2. 二叉树的前序遍历:这个问题要求按照前序遍历的顺序输出二叉树的节点值。可以使用递归或迭代的方法来解决。递归方法的思路是先输出当前节点的值,然后递归遍历左子树,最后递归遍历右子树。迭代方法可以使用栈来辅助实现,把根节点压入栈中,然后循环弹出栈顶节点,输出其值,并将其右子节点和左子节点依次压入栈中。时间复杂度为O(n),空间复杂度为O(n)。 3. 二叉树的层序遍历:这个问题要求按照层序遍历的顺序输出二叉树的节点值。可以使用队列来辅助实现。首先将根节点入队,然后循环直到队列为空,每次从队列中取出一个节点,输出其值,并将其左右子节点依次入队。时间复杂度为O(n),空间复杂度为O(n)。 以上是几个常见的Python二叉树面试题的解法,根据具体的问题要求和输入条件选择合适的解法即可。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【编程之路】面试必刷TOP101:二叉树系列(23-30,Python实现)](https://blog.csdn.net/be_racle/article/details/125531755)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [【面试题8】二叉树的下一个节点](https://download.csdn.net/download/weixin_38589168/14035034)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值