数据结构7:基本的二叉树遍历及题目

一般我们在学习数据结构的时候都会实现它最基本的增删查改方式,但是二叉树这个数据结构不太一般,增删查改没有什么意义,由于二叉树的相关遍历涉及到递归,我们先不学习创建二叉树,而是从遍历开始

简单的创建一个二叉树并不难,创建几个节点然后当作二叉树连起来即可:

typedef  int   BTDataType;


typedef struct BTNode
{
	BTDataType data;
	struct BTNode* left;
	struct BTNode* right;
}BT;


BT* CreatTree()
{
	BT* n1 = (BT*)malloc(sizeof(BT));
	assert(n1);
	BT* n2 = (BT*)malloc(sizeof(BT));
	assert(n2);
	BT* n3 = (BT*)malloc(sizeof(BT));
	assert(n3);
	BT* n4 = (BT*)malloc(sizeof(BT));
	assert(n4);
	BT* n5 = (BT*)malloc(sizeof(BT));
	assert(n5);
	BT* n6 = (BT*)malloc(sizeof(BT));
	assert(n6);

	n1->left = n2;
	n1->right = n4;
	n2->left = n3;
	n2->right = NULL;
	n3->left = NULL;
	n3->right = NULL;
	n4->left = n5;
	n4->right = n6;
	n5->left = NULL;
	n5->right = NULL;
	n6->left = NULL;
	n6->right = NULL;


	n1->data = 1;
	n2->data = 2;
	n3->data = 3;
	n4->data = 4;
	n5->data = 5;
	n6->data = 6;

	return n1;
}

 逻辑结构如下图:

 

二叉树的遍历:

前序遍历:

void preOrder(BT* root)
{

	if (root == NULL)
	{
		printf("NULL ");
		return;
	}


	printf("%d ", root->data);
	preOrder(root->left);
	preOrder(root->right);
}

中序遍历:

void MidOrder(BT* root)
{

	if (root == NULL)
	{
		printf("NULL ");
		return;
	}


	preOrder(root->left);
	printf("%d ", root->data);

	preOrder(root->right);
}

后序遍历:

//后序遍历
void leftOrder(BT* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}


	preOrder(root->left);
	preOrder(root->right);
	printf("%d ", root->data);

}

二叉树功能实现:

 二叉树节点个数:

int TreeSize(BT* root)
{
	if (root == NULL)
		return 0;

	return TreeSize(root->left) + TreeSize(root->right) + 1;
}

二叉树叶子节点个数:

int BinaryTreeLeafSize(BT* root)
{
	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;

	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

二叉树高度:

int BinaryTreeLeafHeight(BT* root)
{
	if (root == NULL)
		return 0;

	int left = BinaryTreeLeafHeight(root->left) + 1;
	int right = BinaryTreeLeafHeight(root->right) + 1;

	if (left > right)
		return left;
	else
		return right;

}

二叉树第k层节点个数:

int BinaryTreeLevelKSize(BT* root, int k)
{
	assert(k > 0);
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;

	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);


}

 二叉树查找值为x的节点:

BT* BinaryTreeFind(BT* root, BTDataType x)
{
	if (root == NULL)
		return NULL;

	if (root->data == x)
		return root;

	BT* leftret = BinaryTreeFind(root->left, x);

	if (leftret)
		return leftret;

	BT* rightret  = BinaryTreeFind(root->right, x);

	if (rightret)
		return rightret;
	return NULL;

}

 一些有关二叉树的题目

相信不少的读者在第一次接触到二叉树的时候对递归的把握并不深刻,在这里,其实递归的本质就是抛去了我们平常写代码注重全局的思想,改成了注重每次递归的时候应该做的事情,我个人没法详细表述的很好,在这里推荐一篇文章:三道题套路解决递归问题 | lyl's blog

单值二叉树:

链接:力扣

 


        if(root== NULL)
        return true;


        if(root->left && root->val != root -> left ->val )
        return false;
        if(root->right && root->val != root ->right -> val)
        return false;

        bool lefret = isUnivalTree(root ->left);
        bool rightret = isUnivalTree(root ->right);


        return lefret && rightret;

 同遍历整个二叉树查找某个值的逻辑相同。

翻转二叉树:

链接:力扣

思路:面对递归类型的题目,不应该直接专注于解决一整颗树上,而是每一步应该做什么,这题的主体每步的逻辑就是置换左右子树,那么我们不需要多想,直接交换左右子树,剩下的交给递归处理,不需要过度的照顾全局。

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {

        if(root == NULL)
        return NULL;

        struct TreeNode* tmp = root->left;
        root -> left = root->right;

        invertTree(root->left);
        invertTree(root->right);

        return root;

    }
};

 相同的树:

链接:力扣

思路:同上的翻转相同,我们只需要关注每一个节点对比的值是否符合要求即可,剩下的交给递归

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p == NULL && q == NULL)
    return true;


    if(p == NULL || q == NULL)
    return false;


    if(p->val != q->val)
    return false;


    bool leftret = isSameTree(p->left,q->left);
    bool rightret = isSameTree(p->right,q->right);


    return leftret && rightret ;


}

 

层序遍历:

由于递归的栈帧消耗还是比较大的,所以用非递归的方法来遍历二叉树还是非常有必要的,借助队列的先进先出的特性可以很好的实现非递归遍历。

思路:二叉树无非就是跟和左子树右子树的问题,逻辑上来说,在我们在到达一个节点的时候接下来就是得到它的值或者是左子树右子树,那么我们就只需要先将根节点入队列,再将根的左子树右子树入队列,把根出队列后,再把其左右子树视作新根,再拆开成为左右子树,以达到层序遍历的效果。

void BinaryTreeLevelOrder(BTNode* root)// 层序遍历
{
	Queue q;
	QueueInit(&q);
	if (root)//root不为空,放数据
		QueuePush(&q,root);
 
	while (!QueueEmpty(&q))//如果队列不为空,则循环
	{
		BTNode* front = QueueFront(&q);//拿队头数据
		printf("%d ", front->data);
		QueuePop(&q);
		if (front->left)
			QueuePush(&q, front->left);
 
		if (front->right)
			QueuePush(&q, front->right);
	}
 
	QueueDestroy(&q);
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这道题目是关于如何利用二叉链表结构建立一棵二叉树,并能够实现二叉树的先序遍、中序遍和后序遍三种遍算法,能够用队列实现二叉树的层次遍算法,并按层次输出(标出层号),并能统计树叶数、结点数、层高等。 ### 回答2: 二叉树是计算机科学中的一个重要概念,其本质上是一种树状结构,其中每个节点最多具有两个子节点。二叉树在计算机科学领域广泛应用,包括搜索树、表达式树、哈夫曼树等。下面我将就如何利用二叉链表结构来建立一棵二叉树,并递归实现它的先序遍、中序遍和后序遍三种遍算法,用队列实现层次遍算法,并按层次输出,并能统计树叶数、节点数、层高等问题进行详细解答。 1.建立二叉树 建立二叉树可以通过二叉链表结构完成。所谓二叉链表结构,是指每个节点包含三个信息:节点值、左子节点和右子节点。以下是建立一棵二叉树的程序框架: ``` class Node: def __init__(self, val=None, left=None, right=None): self.val = val self.left = left self.right = right class BinaryTree: def __init__(self, val=None): self.root = Node(val) def insert(self, val): if not self.root: self.root = Node(val) else: self._insert(val, self.root) def _insert(self, val, node): if val < node.val: if not node.left: node.left = Node(val) else: self._insert(val, node.left) else: if not node.right: node.right = Node(val) else: self._insert(val, node.right) ``` 2.递归实现遍算法 接下来,我们可以使用递归实现二叉树的先序遍、中序遍和后序遍三种遍算法。 (1)先序遍,即先输出相应节点,再遍左子树和右子树; ``` def preorder(self, node): if node: print(node.val) self.preorder(node.left) self.preorder(node.right) ``` (2)中序遍,即先遍左子树,再输出相应节点和右子树; ``` def inorder(self, node): if node: self.inorder(node.left) print(node.val) self.inorder(node.right) ``` (3)后序遍,即先遍左子树和右子树,再输出相应节点; ``` def postorder(self, node): if node: self.postorder(node.left) self.postorder(node.right) print(node.val) ``` 3.层次遍算法 接下来,我们可以使用队列实现二叉树的层次遍算法,并按层次输出(标出层号)。 ``` def levelorder(self): if not self.root: return [] queue = [self.root] res = [] level = 0 while queue: res.append([]) level_length = len(queue) for i in range(level_length): node = queue.pop(0) res[level].append(node.val) if node.left: queue.append(node.left) if node.right: queue.append(node.right) level += 1 return res ``` 4.统计树叶数、节点数、层高等 最后,我们可以通过递归,统计二叉树的叶数、节点数和深度。其中,深度可以使用递推的方式实现,具体代码如下: ``` def count_leaves(self, node): if not node: return 0 if not node.left and not node.right: return 1 else: return self.count_leaves(node.left) + self.count_leaves(node.right) def count_nodes(self, node): if not node: return 0 return 1 + self.count_nodes(node.left) + self.count_nodes(node.right) def depth(self, node): if not node: return 0 return 1 + max(self.depth(node.left), self.depth(node.right)) ``` 以上就是关于如何利用二叉链表结构建立二叉树,并递归实现遍算法、层次遍算法,以及统计树叶数、节点数、层高等问题的详细解答。 ### 回答3: 二叉树特指每个节点最多只有两个子节点的树结构,节点的左右子节点顺序不同则构成不同的二叉树。二叉链表结构指利用指针来表示节点的数据结构,节点包含一个数据域和两个指向左右子节点的指针。 建立二叉树的方式有多种,其中最基本的是先序遍建立二叉树。即按照“根 - 左子树 - 右子树”的顺序从上至下递归遍,并利用二叉链表结构生成树。先序遍算法如下: 1. 若当前节点存在则输出该节点数据; 2. 若当前节点的左孩子节点非空,则递归遍左子树; 3. 若当前节点的右孩子节点非空,则递归遍右子树。 中序遍算法按照“左子树 - 根 - 右子树”的顺序遍,并利用递归算法实现。 1. 若当前节点的左孩子节点非空,则递归遍左子树; 2. 若当前节点存在则输出该节点数据; 3. 若当前节点的右孩子节点非空,则递归遍右子树。 后序遍算法按照“左子树 - 右子树 - 根”的顺序遍,并利用递归算法实现。 1. 若当前节点的左孩子节点非空,则递归遍左子树; 2. 若当前节点的右孩子节点非空,则递归遍右子树; 3. 若当前节点存在则输出该节点数据。 层次遍算法需要利用队列数据结构实现,具体算法如下: 1. 将根节点入队列; 2. 当队列非空时,弹出队头元素并输出该节点数据; 3. 若该节点的左孩子节点非空,则将其入队列; 4. 若该节点的右孩子节点非空,则将其入队列; 5. 重复2至4步直到队列为空。 统计树叶数、节点数和层高算法利用递归实现,统计的代码实现如下: //统计树叶数 int countLeaf(Tnode* root) { if (root == NULL) return 0; //空树则叶数为0 else if (root->left == NULL && root->right == NULL) return 1; //只有一个节点则叶数为1 else return countLeaf(root->left) + countLeaf(root->right); //递归计算左子树和右子树叶数之和 } //统计节点数 int countNode(Tnode* root) { if (root == NULL) return 0; //空树则节点数为0 else return countNode(root->left) + countNode(root->right) + 1; //递归计算左子树和右子树节点数之和加1 } //求层高 int getHeight(Tnode* root) { if (root == NULL) return 0; //空树则层高为0 else { int leftH = getHeight(root->left); //计算左子树的层高 int rightH = getHeight(root->right); //计算右子树的层高 return (leftH > rightH ? leftH : rightH) + 1; //返回左右子树层高较大值加1 } } 因此,利用上述算法,我们可以通过建立一棵二叉链表结构的二叉树,实现递归实现二叉树的先序遍、中序遍和后序遍三种遍算法,并利用队列实现二叉树的层次遍算法,并按层次输出(标出层号),并可以统计树叶数、节点数、层高等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值