1、BFS
- 广度优先搜索,多在树、图等集合类型的检索操作中使用的一种搜索方法,其中基本上都使用队列这种数据库来保存搜索过程中的数据
- 因为队列的先进先出的特性,从队头获取数据,搜索到的数据放入到队尾
- 默认先往队列中放入一个元素,然后根据该元素和其他相关元素之间的关系找到其他元素,并放入到队列中
2、LCR 043. 完全二叉树插入器
题目信息:
- https://leetcode.cn/problems/NaqhDT/description/
完全二叉树是每一层(除最后一层外)都是完全填充(即,节点数达到最大,第 n 层有 2n-1 个节点)的,并且所有的节点都尽可能地集中在左侧。
设计一个用完全二叉树初始化的数据结构 CBTInserter,它支持以下几种操作:
CBTInserter(TreeNode root) 使用根节点为 root 的给定树初始化该数据结构;
CBTInserter.insert(int v) 向树中插入一个新节点,节点类型为 TreeNode,值为 v 。使树保持完全二叉树的状态,并返回插入的新节点的父节点的值;
CBTInserter.get_root() 将返回树的根节点。示例 1:
输入:inputs = ["CBTInserter","insert","get_root"], inputs = [[[1]],[2],[]]
输出:[null,1,[1,2]]示例 2:
输入:inputs = ["CBTInserter","insert","insert","get_root"], inputs = [[[1,2,3,4,5,6]],[7],[8],[]]
输出:[null,3,4,[1,2,3,4,5,6,7,8]]提示:
最初给定的树是完全二叉树,且包含 1 到 1000 个节点。
每个测试用例最多调用 CBTInserter.insert 操作 10000 次。
给定节点或插入节点的每个值都在 0 到 5000 之间。
节点对象:
* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };
解题思路:
- 1、审题:创建一个二叉树插入器的类,内部包含的二叉树是完全二叉树形式,并暴露两个方法插入insert,和获取树的根节点
- 要求在插入树节点内部的二叉树还是完全二叉树的形式
- 2、解题:
- 根据完全二叉树的特性,树的每层结点都应该是满的,最后一层可以不填充满,但是树节点位置是从左到右排列的。
- 在调用插入insert方法时,层序遍历树的结点,找到左右子节点不满的结点,并新插入对应缺失的结点
- 层序遍历使用队列保存元素
- 优化,如果每次调用插入方法,都需要从根节点开始层序遍历的话时间复杂度就高了,可以使用队列保存待插入节点的父节点
代码实现:
class CBTInserter
{
public:CBTInserter(TreeNode *root){m_root = root;}int insert(int v){TreeNode *newNode = new TreeNode(v);if (m_root == nullptr){m_root = newNode;return v;}TreeNode *node = m_root;queue.push(node);while (!queue.empty()){TreeNode *tempNode = queue.front();if (tempNode->left == nullptr) {tempNode->left = newNode;return tempNode->val;}if (tempNode->right == nullptr){tempNode->right = newNode;return tempNode->val;}else{queue.push(tempNode->left);queue.push(tempNode->right);queue.pop();}}return 0;}TreeNode *get_root(){return m_root;}private:std::queue<TreeNode *> queue;TreeNode *m_root;
};
解法2:
- 在构造函数的时候对树进行层序遍历,找到需要补充左右子节点的结点位置
- 在调用insert方法的时候,从队列中直接获取队列的头结点,然后插入左或右子节点,如果当前结点的左右子节点都满了,则进行入队和出队操作
- 采用这种实现方式不用每次调用insert方法的时候,都需要进行层序遍历
代码实现2:
class CBTInserter
{
public:CBTInserter(TreeNode *root){m_root = root;queue.push(root);while (!queue.empty()){TreeNode *node = queue.front();if (node->left != nullptr && node->right != nullptr){queue.pop();queue.push(node->left);queue.push(node->right);}else{break;}}}int insert(int v){TreeNode *newNode = new TreeNode(v);if (queue.empty()){queue.push(newNode);m_root = newNode;return v;}TreeNode *node = queue.front();if (node->left == nullptr){node->left = newNode;}else{node->right = newNode;queue.pop();queue.push(node->left);queue.push(node->right);}return node->val;}TreeNode *get_root(){return m_root;}private:std::queue<TreeNode *> queue;TreeNode *m_root;
};
3、总结:
- 完全二叉树的定义
- 要往完全二叉树中插入新节点,需要先找到待插入节点的父节点
- 使用层序遍历+队列方式遍历树,在遍历过程中找到目标节点
- 优化解法,不用每次插入节点时,都要走一遍完整的树层序遍历