1. 二叉树的定义
二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个节点最多只能有两棵子树,且有左右之分。二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个节点。
2. 二叉树的性质
- 在二叉树的第i层上最多有2 i-1 个节点 。(i>=1)
- 二叉树中如果深度为k,那么最多有2k-1个节点。(k>=1)
- .n0=n2+1 n0表示度数为0的节点 n2表示度数为2的节点。
- 完全二叉树中,具有n个节点的完全二叉树的深度为[log2n]+1,其中[log2n]+1是向下取整。
-
若对含 n 个结点的完全二叉树从上到下且从左至右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点:
(1) 若 i=1,则该结点是二叉树的根,无双亲, 否则,编号为 [i/2] 的结点为其双亲结点;
(2) 若 2i>n,则该结点无左孩子, 否则,编号为 2i 的结点为其左孩子结点;
(3) 若 2i+1>n,则该结点无右孩子结点, 否则,编号为2i+1 的结点为其右孩子结点。
3. 二叉树的遍历
3.1 前序遍历
1.首先访问根节点。
2.其次前序访问左子树。
3.最后前序访问右子树。
3.2 中序遍历
1.先中序遍历左子树。
2.然后是根结点。
3.然后中序遍历右子树。
3.3 后序遍历
1.后序遍历左子树。
2.后序遍历右子树。
3.然后访问根节点。
3.4 层次遍历
逐层从左到右访问二叉树结点。
4. 特殊二叉树
4.1 满二叉树
1.一棵树深度为k,2^k-1个节点的树是满二叉树。
2.所有内部节点都有两个子节点,最底一层是叶子节点。
3.如果一颗树深度为h,最大层数为k,且深度与最大层数相同,即k=h。
4.第k层的结点数是:2^(k-1)。
5.总结点数是:2^k-1 (2的k次方减一)。
6.总节点数一定是奇数。
7.树高:h=log2(n+1)。
4.2 完全二叉树
1.若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h 层所有的结点都连续集中在最左边,这就是完全二叉树。
2.深度为k的完全二叉树,至少有2(k-1)个节点,至多有2k-1个节点。
3.树高h=log2n+1。
4.满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树。
4.3 二叉搜索树
1.左子树上所有结点的值均小于等于它的根结点的值,右子树上所有结点的值均大于等于它的根结点的值。
2.优点:查找速度快,二叉查找树比普通树查找更快。
3.缺点:出现平衡问题。
4.4 平衡二叉树
1.平衡二叉树全称平衡二叉搜索树,也叫AVL树,是一种自平衡的树,从上面二叉搜索树升级过来的,重点是改进了平衡问题。
2.AVL树也规定了左结点小于根节点,右结点大于根节点。并且还规定了左子树和右子树的高度差不得超过1,这样保证了它不会成为线性的链表。
5. 二叉树建立及遍历代码设计
代码由自己设计,前中后序遍历代码代码分为递归和非递归两个版本,代码如下:
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
using namespace std;
struct Node {
char data;
Node *lchild, *rchild;
Node() = default;
explicit Node(char data) : data(data) {
lchild = nullptr;
rchild = nullptr;
}
Node(char data, Node *left, Node *right) : data(data), lchild(left), rchild(right) {}
};
using BiTree = Node *;
// 创建二叉树(递归,通过前序遍历创建)
void create(BiTree &node) {
char ch;
cin >> ch;
if (ch == '#') node = nullptr;// '#' => null character
else {
node = new Node;
node->data = ch;
create(node->lchild); //递归
create(node->rchild);
}
}
// 递归:实现前序遍历 DLR
void preTraversal(BiTree root) {
if (root == nullptr) return;
cout << root->data << " ";
preTraversal(root->lchild);
preTraversal(root->rchild);
}
// 递归:实现中序遍历 LDR
void inTraversal(BiTree root) {
if (root == nullptr) return;
inTraversal(root->lchild);
cout << root->data << " ";
inTraversal(root->rchild);
}
// 递归:实现后序遍历 LRD
void postTraversal(BiTree root) {
if (root == nullptr) return;
postTraversal(root->lchild);
postTraversal(root->rchild);
cout << root->data << " ";
}
//非递归:实现二叉树的中序遍历
void InOrderTranversal(BiTree root) {
BiTree cur = root;
stack<BiTree> cs;
while (cur || !cs.empty()) {
if (cur != nullptr) {
cs.push(cur);
cur = cur->lchild;
} else {
cur = cs.top();
cs.pop();
cout << cur->data << " ";
cur = cur->rchild;
}
}
}
// 非递归:实现二叉树的前序遍历
void PreOrderTranversal(BiTree root) {
vector<char> result;
stack<BiTree> st;
if (root == nullptr) return;
st.push(root);
while (!st.empty()) {
auto node = st.top();
st.pop();
result.push_back(node->data);
if (node->rchild != nullptr)
st.push(node->rchild);
if (node->lchild != nullptr)
st.push(node->lchild);
}
for (auto res: result) cout << res << " ";
}
// 非递归:实现二叉树的后序遍历
void PostOrderTranversal(BiTree root) {
vector<char> result;
stack<BiTree> st;
if (root == nullptr) return;
st.push(root);
while (!st.empty()) {
auto node = st.top();
st.pop();
result.push_back(node->data);
if (node->lchild != nullptr)
st.push(node->lchild);
if (node->rchild != nullptr)
st.push(node->rchild);
}
reverse(result.begin(), result.end());
for (auto res: result) cout << res << " ";
}
// 层序遍历
void LevelorderTraversal(BiTree root) {
if (root == nullptr) return;
queue<BiTree> que;
que.push(root);
while (!que.empty()) {
auto node = que.front();
que.pop();
cout << node->data << " ";;
if (node->lchild != nullptr) que.push(node->lchild);
if (node->rchild != nullptr) que.push(node->rchild);
}
}
int main() {
BiTree T;
cout << "Please enter the data of the node, # stands for empty : "; //ABC#D##EF###GHI###J##
create(T);
cout << "Created successfully!" << endl;
cout << " ===========Preorder traversal Test=========== " << endl;
preTraversal(T);
cout << endl;
cout << " ===========Inorder traversal Test=========== " << endl;
inTraversal(T);
cout << endl;
cout << " ===========Postorder traversal Test=========== " << endl;
postTraversal(T);
cout << endl;
cout << " ************Preorder traversal Test************ " << endl;
PreOrderTranversal(T);
cout << endl;
cout << " ************Inorder traversal Test************ " << endl;
InOrderTranversal(T);
cout << endl;
cout << " ************Postorder traversal Test************ " << endl;
PostOrderTranversal(T);
cout << endl;
cout << " ************Leverlorder traversal Test************ " << endl;
LevelorderTraversal(T);
cout << endl;
return 0;
}
运行结果如下:
Please enter the data of the node, # stands for empty :ABC#D##EF###GHI###J##
Created successfully!
===========Preorder traversal Test===========
A B C D E F G H I J
===========Inorder traversal Test===========
C D B F E A I H G J
===========Postorder traversal Test===========
D C F E B I H J G A
************Preorder traversal Test************
A B C D E F G H I J
************Inorder traversal Test************
C D B F E A I H G J
************Postorder traversal Test************
D C F E B I H J G A
************Leverlorder traversal Test************
A B G C E H J D F I