关于二叉树的算法题一般都是使用递归来实现,所以要想做好二叉树的算法题,要先学会递归算法的使用。
一、如何创建一个二叉树
1.声明一个树节点结构体
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
2.创建节点
TreeNode *node1 = TreeNode(1);
TreeNode *node2 = TreeNode(2);
TreeNode *node3 = TreeNode(3);
TreeNode *node4 = TreeNode(4);
TreeNode *node5 = TreeNode(5);
TreeNode *node6 = TreeNode(6);
TreeNode *node7 = TreeNode(7);
3.连接节点
node1->left = node2;
node1->right = node3;
node2->left = node4;
node2->right = node5;
node3->left = node6;
node3->right = node7;
//和链表一样,知道第一个节点,就可以搜索所有的节点,所以我们可以用根部节点来代表整个二叉树
//即TreeNode* node1代表了整棵二叉树
这样一来,我们就创建了一个简单的二叉树了。
二、二叉树的分类
1.满二叉树
除了最后一层,其他层都包含左右节点。
2.完全二叉树
树的1~n层是一个满二叉树,最后一层的节点全部靠左。(node5不能缺)
3.二叉搜索树
左树内所有的节点小于根节点,右数内所有的节点大于根节点。
注意:node5>node2,但是node5<node1。
4.平衡二叉树
平衡指的是左右平衡,左树右树高度差不超过1;左树右数都是一棵平衡树。
下面这棵树左边高度为2,右边为0,不是一棵平衡二叉树。
三、二叉树的遍历
我们拿这棵树来举例子。
1.深度优先遍历(DFS)
前序遍历(中左右)
void preOrder(TreeNode* root) {
if (root == nullptr) {
return;
}
std::cout << root->val << " "; // 访问根节点
preOrder(root->left); // 遍历左子树
preOrder(root->right); // 遍历右子树
}
//输出node1、node2、node4、node5、node3、node6、node7
中序遍历(左中右)
void inOrder(TreeNode* root) {
if (root == nullptr) {
return;
}
inOrder(root->left); // 遍历左子树
std::cout << root->val << " "; // 访问根节点
inOrder(root->right); // 遍历右子树
}
//输出node4、node2、node5、node1、node6、node3、node7
后续遍历(左右中)
void postOrder(TreeNode* root) {
if (root == nullptr) {
return;
}
postOrder(root->left); // 遍历左子树
postOrder(root->right); // 遍历右子树
std::cout << root->val << " "; // 访问根节点
}
//输出node4、node5、node2、node6、node7、node3、node1
2.广度优先遍历(BFS)
层序遍历
void levelOrder(TreeNode* root) {
if (root == nullptr) {
return;
}
std::queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front();
q.pop();
std::cout << node->val << " ";
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
//输出node1、node2、node3、node4、node5、node6、node7
//这段代码的意思是:第一轮,取树头、把左树压入队列、把右树压入队列
//第二轮,取左树的树头、把左树的左树压入队列、把左树的右树压入队列;
//然后取右树的树头、把右树的左树压入队列、把右树的右树压入队列;
//第三轮。。。。