定义
二叉树(Binary Tree)是一种数据结构,它的每个父节点(parent)至多有两个子节点(children),分别被称为左孩子(the left child)和右孩子(the right child).
如上图所示, 该二叉树的大小(size)为9且高度(height)为3,根结点(root)的值为2. 另外,这是一棵不平衡(unbalanced)且未排序(unsorted)的二叉树。
特殊二叉树
- 完美二叉树(perfect binary tree)
二叉树属性
- 在任意二叉树中,度数为2节点的个数等于叶子节点的个数减1
节点的度数等于其子节点的个数。因此,在二叉树中,节点的度数只可能为0,1和2。
当只有1个节点时,度为0。接着,每多出1个节点,同时会派生出1度。派生出的度和派生出的节点数一定相等。即:
节点总数 = 总度数 + 1
假设在一棵二叉树中,度数为2的节点数为X2
,度数为1的节点数为X1
,度数为0的节点数为X0
。结合上式:
X2 + X1 + X0 = 2X2 + X1 + 1
,推出 X2 = X0 - 1
因此,度数为2的节点个数等于叶节点数减1
- 满二叉树定理:非空满二叉树的叶节点数等于其分支节点数加1
证明同上。在满二叉树中,度数为1的节点数为0。
当仅有根节点时:二叉树有2个空子树,1个节点,结论成立。
接着,空子树和节点等量增长,结论成立。
- 满二叉树最少有2h+1个节点,最多有2^(h+1)-1个节点 (仅有根节点的二叉树的高度为0)
- 在完美二叉树中,假设叶子结点的个数为l,高度为h,则l=2^h,总结点个数n=2^(h+1)-1
二叉树算法
二叉树的结点
1 2 3 4 5 6 7
| template <class elemType> struct binaryTreeNode { elemType info; binaryTreeNode<elemType> *left; binaryTreeNode<elemType> *right; };
|
二叉树的高度
1 2 3 4 5 6 7 8
| template <class elemType> int height(binaryTreeNode<elemType> *btn) { if (btn == NULL) return 0; else return 1 + max(height(btn->left), height(btn->right)); }
|
二叉树的复制
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| template <class elemType> void copyTree(binaryTreeNode<elemType>* &copiedTreeRoot, binaryTreeNode<elemType>* otherTreeRoot) { if (otherTreeRoot == NULL) { copiedTreeRoot = NULL; } else { copiedTreeRoot = new binaryTreeNode<elemType>; copiedTreeRoot->info = otherTreeRoot->info; copyTree(copiedTreeRoot->left, otherTreeRoot->left); copyTree(copiedTreeRoot->right, otherTreeRoot->right); } }
|
二叉树的遍历 (traverse)
- 前序遍历:根->左->右
- 中序遍历:左->根->右
- 后序遍历:左->右->根
递归遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| template <class elemType> void preorder(binaryTreeNode<elemType> *btn) { if (btn == NULL) return; cout << btn->info << " "; preorder(btn->left); preorder(btn->right); }
template <class elemType> void inorder(binaryTreeNode<elemType> *btn) { if (btn == NULL) return; inorder(btn->left); cout << btn->info << " "; inorder(btn->right); }
template <class elemType> void postorder(binaryTreeNode<elemType> *btn) { if (btn == NULL) return; postorder(btn->left); postorder(btn->right); cout << btn->info << " "; }
|
迭代遍历
需要额外的一个栈stack结构来辅助实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| template <class elemType> void preorderIteration(binaryTreeNode<elemType> *root) { stack<binaryTreeNode<elemType>*> st; if(root) st.push(root);
while(!st.empty()){ binaryTreeNode<elemType> *cur = st.top(); st.pop();
cout << cur->info << " ";
if(cur->right) st.push(cur->right); if(cur->left) st.push(cur->left); } }
template <class elemType> void inorderIteration(binaryTreeNode<elemType> *root) { stack<binaryTreeNode<elemType>*> st;
binaryTreeNode<elemType> *cur = root;
while(cur || !st.empty()){ if(cur){ st.push(cur); cur = cur->left; } else{ cur = st.top(); st.pop();
cout << cur->info << " ";
cur = cur->right; } } }
template <class elemType> void postorderIteration(binaryTreeNode<elemType> *root) { stack<binaryTreeNode<elemType>*> st; binaryTreeNode<elemType> *pre;
if(root) st.push(root);
while(!st.empty()){ binaryTreeNode<elemType> *cur = st.top();
if((!cur->left && !cur->right) || (pre && (cur->left == pre || cur->right == pre))){ st.pop(); cout << cur->info << " "; pre = cur; } else{ if(cur->right) st.push(cur->right); if(cur->left) st.push(cur->left); } } }
|
层次遍历 (Breadth-First Search)
需要额外的一个队列queue结构来辅助实现。
大致思想为:队列初始化时只有根节点,每个节点出队列时,将它子节点加入队列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| template <class elemType> void BFS(binaryTreeNode<elemType>* btn) { if(btn == nullptr) return; queue<binaryTreeNode<elemType> *> que; que.push(btn); while(!que.empty()){ binaryTreeNode<elemType> *q = que.front(); cout << q->info << " "; que.pop(); if(q->left != nullptr) que.push(q->left); if(q->right != nullptr) que.push(q->right); } }
|
二叉树的算法思路:仅考虑当前结点的任务,将其余部分交给递归或迭代框架。其算法框架大致为:
1 2 3 4 5 6 7 8 9
| template <class elemType> void BTFramework(binaryTreeNode<elemType>* btn, int target) { if (btn->val == target) DoSometing; if (btn->left != nullptr) BTFramework(btn->left, target); if (btn->right != nullptr) BTFramework(btn->right, target); }
|
这个以后再细说。。。
代码下载地址:https://xiaoli777.github.io/codes/BinaryTree.cpp