文章目录
- 二叉树的简要概述
- 二叉树的常用操作
- 已知前序和中序遍历结果,重构二叉树
- 判断是否是子树
- 实现对BST树的镜像翻转
- 非递归实现找中序遍历的倒数第K个结点
- 递归实现找中序遍历的倒数第K个结点
- 找公共祖先结点
- 判断二叉树是不是BST树
- 非递归实现在BST树查找指定的元素值val是否存在
- 递归实现在BST树查找指定的元素值val是否存在
- 非递归实现BST树的插入操作
- 递归实现BST树的插入操作
- 非递归实现BST树的删除操作
- 递归实现BST树的删除操作
- 递归实现返回BST树所有结点的个数
- 递归实现返回BST树的层数
- 判断当前二叉树是不是BST树
- 找满足区间[first,last]之间的元素
- (非递归)实现BST树的遍历
- (递归)实现BST树的遍历
- 递归实现层序遍历
二叉树的简要概述
二叉树的定义
定于:二叉树是有限元素的集合,该集合或者为空、或者由一个称为根的元素以及两个不相交的、被称为左子树和右子树的二叉树组成。
在二叉树中,一个元素也称作一个结点。当集合为空时,称该二叉树为空二叉树
二叉树是有序的,即若将其左、右子树颠倒,就成为另一棵不同的树。
树中某个结点只有一棵树时要区分它是左子树还是右子树(这是二叉树和数之间的基本区别点)
二叉树具有五种基本形态
- 空二叉树
- 只有一个根
- 只有左孩子
- 只有右孩子
- 有两个孩子的二叉树
满二叉树
- 如果所有分支结点都存在左子树和右子树
- 并且所有叶子结点都在同一层上
完全二叉树
一颗深度为k的有n个结点的二叉树,如果其中任何结点的的编号i(1≤i≤n)与满二叉树中的编号为i的结点位置完全相同,则这棵二叉树称为完全二叉树。
完全二叉树的特点:
- 叶子结点只能出现在最下层和次下层
- 最下层的叶子结点连续出现在树的左部。
满二叉树必定是完全二叉树,而完全二叉树未必是满二叉树。
二叉树的主要性质
- 一棵非空二叉树的第i层最多有 2 i − 1 2^{i-1} 2i−1 个结点(i≥1).
- 一棵深度为K的二叉树中,最多有 2 k − 1 2^k-1 2k−1个结点
- 对于一颗非空的二叉树,如果叶子结点为n0,度数为2的结点数为n2,则有
n0=n2+1
- 具有n个结点的完全二叉树的深度k为 l o g 2 n log _2 n log2n+1
- 对于具有n个结点的完全二叉树,如果按照从上到下、从左到右的编号体系对二叉树种的结点进行从1开始顺序编号,则对于任意的序号为i的结点,有:
- 如果i>1,则序号为i的结点的父亲结点的序号为 ⌊ i / 2 ⌋ \lfloor i/2 \rfloor ⌊i/2⌋;如果i=1,则序号为i的结点是根结点,无父亲结点
- 如果2i≤n,则序号为i的结点的左孩子结点的序号为2i,如果2*i>n,则序号为i的结点无左孩子。
- 如果2i+1≤n,则序号为i的结点的右孩子结点的序号为2i+1;如果2*i+1>n,则序号为i的结点无右孩子。
- 若结点i序号为奇数且不等于1,则它的左兄弟序号为i-1
- 若结点i的序号为偶数且不等于n,则他的右兄弟序号为i+1
- 结点i所在层数(层次)为
⌊
l
o
g
2
i
⌋
\lfloor log_2 i\rfloor
⌊log2i⌋+1
如果对二叉树的根节点从0开始编号,则i结点的父亲编号 ⌊ i / 2 ⌋ \lfloor i/2 \rfloor ⌊i/2⌋,左孩子的编号为2i+1,右孩子的编号为2(i+1)
二叉树的数据结构
template<typename T>
class BSTree
{
public:
private:
// 定义BST树结点的类型
struct BSTNode
{
BSTNode(T data = T())
:_data(data)
, _left(nullptr)
, _right(nullptr)
{}
T _data;
BSTNode *_left;
BSTNode *_right;
};
BSTNode *_root; // 指向树的根节点
}
二叉树的常用操作
已知前序和中序遍历结果,重构二叉树
// 已知一棵BST树的前序遍历结果pre数组,和中序遍历结果in数组,重建二叉树
void rebuildBSTree(int pre[], int len1, int in[], int len2)
{
this->_root = rebuildBSTree(pre, 0, len1-1, in, 0, len2-1);
}
BSTNode* rebuildBSTree(int pre[], int i, int j, int in[], int m, int n)
{
if (i > j || m > n)
{
return nullptr;
}
BSTNode *root = new BSTNode(pre[i]);
for (int k = m; k <= n; ++k)
{
if (in[k]==pre[i]) // 中序遍历找到根节点了
{
root->_left = rebuildBSTree(pre, i+1, i+(k-m), in, m, k-1);
root->_right = rebuildBSTree(pre, i+(k - m)+1, j, in, k+1, n);
break;
}
}
return root;
}
判断是否是子树
// 判断参数tree是否是当前BST树的一颗子树,是返回true,否则返回false
bool isChildTree(const BSTree<T> &tree)
{
if (_root == nullptr)
return false;
BSTNode *cur = _root;
while (cur != nullptr)
{
if (tree._root->_data > cur->_data)
{
cur = cur->_right;
}
else if (tree._root->_data < cur->_data)
{
cur = cur->_left;
}
else
{
break;
}
}
if (cur == nullptr)
return false;
return isChildTree(cur, tree._root);
}
// 从father节点开始判断,是否全包含child的节点
bool isChildTree(BSTNode *father, BSTNode *child)
{
if (father == nullptr && child == nullptr)
{
return true;
}
if (father == nullptr)
{
return false;
}
if (child == nullptr)
{
return true;
}
if (father->_data != child->_data)
{
return false;
}
return isChildTree(father->_left, child->_left)
&& isChildTree(father->_right, child->_right);
}
实现对BST树的镜像翻转
void mirror()
{
mirror(_root);
}
void mirror(BSTNode *node)
{
if (node == nullptr)
return;
BSTNode *ptmp = node->_left;
node->_left = node->_right;
node->_right = ptmp;
mirror(node->_left);
mirror(node->_right);
}
非递归实现找中序遍历的倒数第K个结点
int getLastKValue(int k)
{
static int n = number(_root) - k;
if (_root == nullptr)
return -1;
stack<BSTNode*> s;
BSTNode *cur = _root;
while (!s.empty() || cur != nullptr)
{
if (cur != nullptr)
{
s.push(cur);
cur = cur->_left;
}
else
{
BSTNode *top = s.top();
s.pop();
while ((n--) == 0)
{
return top->_data;
}
cur = top->_right;
}
}
}
递归实现找中序遍历的倒数第K个结点
// 获取中序遍历倒数第k个节点的值
int getLastKValue(int k) // LVR RVL
{
int i = 0;
BSTNode *p = getLastKValue(_root, k, i);
if (p != nullptr)
{
return p->_data;
}
else
{
throw "no last k value, k is invalid!";
}
}
// LVR RVL 以node为根节点,找反向中序遍历的第K个节点
BSTNode* getLastKValue(BSTNode *node, int k, int &i)
{
if (node == nullptr)
{
return nullptr;
}
BSTNode *p1 = getLastKValue(node->_right, k, i); // R
if (p1 != nullptr)
{
return p1;
}
i++;
if (k == i)
{
return node; // V
}
return getLastKValue(node->_left, k, i); // L
}
找公共祖先结点
// 获取两个节点的最近公共祖先节点
int getLCA(int val1, int val2)
{
BSTNode *p = getLCA(_root, val1, val2);
if (p != nullptr)
{
return p->_data;
}
else
{
throw "no LCA node!";
}
}
// 以node为根节点,开始寻找val1和val2的LCA
BSTNode* getLCA(BSTNode *node, int val1, int val2)
{
if (node == nullptr)
{
return nullptr;
}
if (val1 < node->_data && val2 < node->_data)
{
return getLCA(node->_left, val1, val2);
}
else if (val1 > node->_data && val2 > node->_data)
{
return getLCA(node->_right, val1, val2);
}
else
{
return node;
}
}
判断二叉树是不是BST树
// 判断当前二叉树是不是一颗BST树
bool isBSTree()
{
BSTNode *pre = nullptr;
return isBSTree(_root, pre);
}
// 以node为根节点,判断当前二叉树是不是BST树
bool isBSTree(BSTNode *node, BSTNode *&pre)
{
if (node == nullptr)
{
return true;
}
if (!isBSTree(node->_left, pre))
{
return false;
}
if (pre != nullptr)
{
if (node->_data <= pre->_data)
{
return false;
}
}
pre = node;
return isBSTree(node->_right, pre);
}
非递归实现在BST树查找指定的元素值val是否存在
bool query(const T &val)
{
BSTNode *cur = _root;
if (cur == nullptr)
{
return false;
}
while (cur != nullptr)
{
if (val == cur->_data)
{
return true;
}
else if (val < cur->_data)
{
cur = cur->_left;
}
else
{
cur = cur->_right;
}
}
return false;
}
递归实现在BST树查找指定的元素值val是否存在
BSTNode * query(const T& val)
{
return query(_root, val);
}
BSTNode * query(BSTNode *node, int val)
{
if (node == nullptr)
{
return nullptr;
}
BSTNode *cur = node;
if (cur->_data == val)
{
return cur;
}
else if (cur->_data < val)
{
return query(cur->_right, val);
}
else
{
return query(cur->_left, val);
}
}
非递归实现BST树的插入操作
void noninsert(const T &val)
{
if (_root == nullptr)
{
_root = new BSTNode(val);
return;
}
BSTNode *pre = nullptr;
BSTNode *cur = _root;
while (cur != nullptr)
{
pre = cur;
if (val < cur->_data)
{
cur = cur->_left;
}
else if (val > cur->_data)
{
cur = cur->_right;
}
else
{
return;
}
}
if (val < pre->_data)
{
pre->_left = new BSTNode(val);
}
else
{
pre->_right = new BSTNode(val);
}
}
递归实现BST树的插入操作
//递归实现BST树的插入操作
void insert(const T &val)
{
_root = insert(_root, val);
}
BSTNode * insert(BSTNode *node, const T &val)
{
if (node == nullptr)
{
node = new BSTNode(val);
return node;
}
if (val < node->_data)
{
node->_left = insert(node->_left, val);
}
else if (val > node->_data)
{
node->_right = insert(node->_right, val);
}
return node;
}
非递归实现BST树的删除操作
BST树的删除操作,分为3种情况:
- 删除的结点没有孩子
- 删除的结点只有一个孩子
- 删除的结点有两个孩子
主要思路是:用前驱结点或者后继结点替换当前待删除的结点
前驱结点:当前结点左子树中元素最大的值所在的结点
后继结点:当前结点右子树中元素最小的值所在的结点
步骤:
- 从根节点(_root)开始寻找值为val的结点,用一个指针(cur)指向它
- 先判断是否满足情况3
- 如果满足,需要找cur的前驱结点,用前驱结点的值把cur结点的值给覆盖掉,直接删前驱结点
- 删除情况1和情况2
void nonremove(const T &val)
{
// 1. 从_root开始寻找值为val的节点,cur指向它
BSTNode *pre = nullptr;
BSTNode *cur = _root;
while (cur != nullptr)
{
if (val < cur->_data)
{
pre = cur;
cur = cur->_left;
}
else if (val > cur->_data)
{
pre = cur;
cur = cur->_right;
}
else
{
break;
}
}
if (cur == nullptr)
return;
// 2. 先判断是否满足情况3,如果满足,需要找cur的前驱节点,用前驱把cur节点的值给覆盖掉,直接删前驱
if (cur->_left != nullptr && cur->_right != nullptr)
{
BSTNode *old = cur;
pre = cur;
cur = cur->_left;
while (cur->_right != nullptr)
{
pre = cur;
cur = cur->_right;
}
old->_data = cur->_data;
}
// 3. 删除情况1和情况2 直接删除cur指针指向的节点就可以了
BSTNode *child = cur->_left;
if (child == nullptr)
{
child = cur->_right;
}
if (pre == nullptr) // 只有一个根节点是要被删除的结点
{
_root = child;
}
else
{
// 要把删除节点的孩子赋给cur父节点相应的地址域里面
if (cur == pre->_left)
{
pre->_left = child;
}
else
{
pre->_right = child;
}
}
delete cur;
}
递归实现BST树的删除操作
BSTNode* remove(BSTNode *node, const T &val)
{
if (node == nullptr)
return nullptr;
if (node->_data > val)
{
node->_left = remove(node->_left, val);
}
else if (node->_data < val)
{
node->_right = remove(node->_right, val);
}
else
{
if (node->_left != nullptr && node->_right != nullptr)
{
BSTNode *pre = node->_left;
while (pre->_right != nullptr)
{
pre = pre->_right;
}
node->_data = pre->_data;
// 直接删除前驱
node->_left = remove(node->_left, pre->_data);
}
else
{
if (node->_left != nullptr)
{
BSTNode *left = node->_left;
delete node;
return left;
}
else if (node->_right != nullptr)
{
BSTNode *right = node->_right;
delete node;
return right;
}
else
{
delete node;
return nullptr;
}
}
}
return node;
}
递归实现返回BST树所有结点的个数
int number(BSTNode *node)
{
if (node == nullptr)
return 0;
return 1 + number(node->_left) + number(node->_right);
}
递归实现返回BST树的层数
// 返回以node为根节点的树的层数/高度
int level(BSTNode *node)
{
if (node == nullptr)
{
return 0;
}
else
{
int left = level(node->_left);
int right = level(node->_right);
return left > right ? left + 1 : right + 1;
}
}
判断当前二叉树是不是BST树
// 判断当前二叉树是不是一颗BST树
bool isBSTree()
{
BSTNode *pre = nullptr;
return isBSTree(_root, pre);
}
// 以node为根节点,判断当前二叉树是不是BST树
bool isBSTree(BSTNode *node, BSTNode *&pre)
{
if (node == nullptr)
{
return true;
}
if (!isBSTree(node->_left, pre))
{
return false;
}
if (pre != nullptr)
{
if (node->_data < pre->_data)
{
return false;
}
}
pre = node;
return isBSTree(node->_right, pre);
}
找满足区间[first,last]之间的元素
// 以node为根节点,中序遍历BST树,找满足区间[first,last]之间的元素
void findAreaData(BSTNode *node, int first, int last, vector<int> &vec)
{
if (node == nullptr)
return;
findAreaData(node->_left, first, last, vec);
if (node->_data > last)
{
return;
}
if (first <= node->_data && last >= node->_data)
{
vec.push_back(node->_data);
}
findAreaData(node->_right, first, last, vec);
}
(非递归)实现BST树的遍历
非递归实现层序遍历
- 如果_root为空,直接返回
- 根节点入队(_root -> queue)
- 循环环判断队列是否为空
- 不为空取出队头元素,分别判断左右孩子是否为nullptr
- 不为空就要依次入队
- 然后打印队头元素,继续判断下一个队头元素
void nonlevelOrder()
{
if (_root == nullptr)
return;
queue<BSTNode*> que;
que.push(_root);
while (!que.empty())
{
BSTNode *front = que.front();
cout << front->_data << " ";
que.pop();
if (front->_left != nullptr)
{
que.push(front->_left);
}
if (front->_right != nullptr)
{
que.push(front->_right);
}
}
}
非递归实现前序遍历(解法1)
void nonfrontOrder()
{
BSTNode *cur = _root;
if (cur == nullptr)
{
return;
}
stack<BSTNode *> stk;
while (!(cur==nullptr&&stk.empty()))
{
while (cur != nullptr)
{
cout <<cur->_data << endl;//在入栈前访问
stk.push(cur);
cur = cur->_left;//让左孩子一直压栈
}
cur = stk.top();//左孩子处理完了
stk.pop();
cur = cur->_right;//处理右孩子
}
}
非递归实现前序遍历(解法2)
void nonpreOrder()
{
if (_root == nullptr)
return;
stack<BSTNode*> s;
s.push(_root);
while (!s.empty()) // VLR
{
BSTNode *top = s.top();
s.pop();
cout << top->_data << " "; // 打印V元素
if (top->_right != nullptr) // 把右孩子先入栈
{
s.push(top->_right);
}
if (top->_left != nullptr) // 把左孩子后入栈,左孩子就在栈顶
{
s.push(top->_left);
}
}
cout << endl;
}
非递归实现中序遍历
void nonmidOrder()
{
BSTNode *cur = _root;
if (cur == nullptr)
{
return;
}
stack<BSTNode *> stk;
while (!(cur == nullptr&&stk.empty()))
{
while (cur != nullptr)
{
stk.push(cur);
cur = cur->_left;//让左孩子一直压栈
}
cur = stk.top();//左孩子处理完了
stk.pop();
cout << cur->_data << endl;
cur = cur->_right;//处理右孩子
}
}
非递归实现后序遍历(解法1)
void nonbackOrder()
{
BSTNode *cur = _root;
if (cur == nullptr)
{
return;
}
stack<BSTNode *>S1;
stack<BSTNode *> S2;//用来存储最后需要打印的数据
while (cur || !S1.empty())
{
while (cur) //一直向右并将沿途节点访问(压入S2)后压入堆栈S1
{
S2.push(cur);
S1.push(cur);
cur = cur->_right;
}
if (!S1.empty())
{
cur = S1.top(); //节点弹出堆栈
S1.pop();
cur = cur->_left; //转向左子树
}
}
while (!S2.empty()) //访问(打印)S2中元素
{
cur =S2.top();
S2.pop();
printf("%d\n",cur->_data);
}
}
非递归实现后序遍历(解法2)
// 非递归实现BST的后序遍历 LRV
void nonpostOrder()
{
if (_root == nullptr)
return;
stack<BSTNode*> s1; // 辅助用的栈
stack<BSTNode*> s2; // 存储后序遍历节点的栈
s1.push(_root);
while (!s1.empty())
{
BSTNode *top = s1.top();
s1.pop();
if (top->_left != nullptr)
{
s1.push(top->_left);
}
if (top->_right != nullptr)
{
s1.push(top->_right);
}
s2.push(top);
}
while (!s2.empty())
{
cout << s2.top()->_data << " ";
s2.pop();
}
cout << endl;
}
(递归)实现BST树的遍历
递归实现前序遍历
void frontOrder(BSTNode *node)
{
if (node == nullptr)
{
return;
}
cout << node->_data << endl;
frontOrder(node->_left);
frontOrder(node->_right);
}
递归实现中序遍历
void midOrder(BSTNode *node)
{
if (node == nullptr)
{
return;
}
midOrder(node->_left);
cout << node->_data << endl;
midOrder(node->_right);
}
递归实现后序遍历
void backOrder(BSTNode *node)
{
if (node == nullptr)
{
return;
}
backOrder(node->_left);
backOrder(node->_right);
cout << node->_data << endl;
}
递归实现层序遍历
void levelOrder()
{
cout << "递归实现层序遍历:";
int l = level(_root);
for (int i = 0; i < l; ++i)
{
levelOrder(_root, i);
}
cout << endl;
}
// 打印以node为根节点的树的层序遍历
void levelOrder(BSTNode *node, int k) // 2
{
if (node != nullptr)
{
if (k == 0)
{
cout << node->_data << " ";
return;
}
levelOrder(node->_left, k - 1);
levelOrder(node->_right, k - 1);
}
}