title: 2017-8-22二叉樹
tags: ACM,數據結構,
grammar_cjkRuby: true
二叉樹(Binary tree)
二叉樹是每個節點最多隻有兩個分支(不存在分枝度大於2的節點)的結構。通常分支被成爲左子樹和右子樹或者左孩子和右孩子。二叉樹分支具有左右結構,不能顛倒。
二叉樹常用的性質:
- 二叉樹第i層最多有2i-1個節點;(可以推出樹的層數是從第1層開始的)
- 深度爲k的二叉樹最多共有2k+1-1個節點(定義根節點所在深度k0 = 0);
- 深度爲k有n個節點的二叉樹,當且僅當其中的每一個節點,都有可以和同樣深度的滿二叉樹,序號從1到n的節點一一對應的時候被稱爲“完全二叉樹”;
- 對任何一顆非空的二叉樹,如果其葉子節點(終端節點)的個數爲n0,度數爲2的節點個數爲n2,則其葉子節點的個數爲n0 = n2 + 1;
二叉樹中常用的方法及講解
- 二叉樹的創建
- 二叉樹的刪除
- 求樹的節點個數
- 求樹的葉子節點個數
- 求樹的深度
- 求二叉樹第k層節點個數
- 求二叉樹第k層的葉子節點個數
- 二叉樹前序、中序、後序、層次序遍歷
- 二叉樹根據前序和中序、中序和後序確定並重建二叉樹
- 二叉樹轉置
首先對節點的結構進行定義(以int型的value爲例):
struct Node{
int value;
Node* left;
Node *right;
}
要對二叉樹的各種方法進行講解之前勢必要先經歷構建樹的過程:
class BinTree{
private:
Node* root;
Node* create(Node* root);
Node* create(Node* root,int pre[],int pos1,int in[],int pos2,int n);
void deleteall(Node* root);
void preorder(Node* root);
void inorder(Node* root);
void postorder(Node* root);
void levelorder(Node* root);
int getNodeNum(Node* root);
int getDepth(Node* root);
int getNodeNumKthLevel(Node* root,int k);
int getLeafNodeNum(Node* root);
int getKthLeaveLeafNodeNum(Node* root,int k);
void mirror(Node* root);
public:
BinTree();
BinTree(int pre[],int pos1,int in[],int pos2,int n);
~BinTree();
void preorder();
void inorder();
void postorder();
void levelorder();
int getNodeNum();
int getDepth();
int getNodeNumKthLevel(int k);
int getLeafNodeNum();
int getKthLeaveLeafNodeNum(int k);
void mirror();
};
實現:
BinTree::BinTree(){
root = create(root);
}
BinTree::BinTree(int pre[],int pos1,int in[],int pos2,int n){
root = create(root,pre,pos1,in,pos2,n);
}
BinTree::~BinTree(){
deleteall(root);
}
void BinTree::preorder(){
preorder(root);
}
void BinTree::inorder(){
inorder(root);
}
void BinTree::postorder(){
postorder(root);
}
void BinTree::levelorder(){
levelorder(root);
}
int BinTree::getNodeNum(){
return getNodeNum(root);
}
int BinTree::getDepth(){
return getDepth(root);
}
int BinTree::getNodeNumKthLevel(int k){
return getNodeNumKthLevel(root,k);
}
int BinTree::getLeafNodeNum(){
return getLeafNodeNum(root);
}
int BinTree::getKthLeaveLeafNodeNum(int k){
return getKthLeaveLeafNodeNum(root,k);
}
void BinTree::mirror(){
mirror(root);
}
1、二叉樹的創建
遞歸解法:
採用類似於前序遍歷的方式,首先創建根節點,再依次創建左子樹和右子樹
Node* BinTree::create(Node* root){
int data;
if(cin >> data && !data) root = NULL;
else{
root = new Node;
root ->value = data;
root ->left = create(root ->left);
root ->right = create(root ->right);
}
return root;
}
2、二叉樹的刪除
遞歸解法:
採用類似於後序遍歷的方法,在刪除根節點之前首先要保證其左子樹和右子樹已經被刪除
void BinTree::deleteall(Node* root){
if(root == NULL) return;
deleteall(root ->left);
deleteall(root ->right);
delete root;
}
3、求二叉樹的節點個數:
遞歸解法:
(1)如果二叉樹爲空,返回0
(2)如果二叉樹不爲空,二叉樹節點個數 = 根節點 + 左子樹節點個數 + 右子樹節點個數
int BinTree::getNodeNum(Node* root){
if(root == NULL) return 0;
return getNodeNum(root ->left) + getNodeNum(root ->right) + 1;//這裏的+1指的就是根節點
}
4、求樹的葉子節點的個數
遞歸解法:
(1)如果二叉樹爲空,返回0
(2)如果二叉樹不爲空,但是左右子樹都爲空,返回1
(3)如果二叉樹不爲空,且左右子樹不同時爲空,返回左子樹中葉子節點個數和右子樹中葉子節點個數之和
int BinTree::getLeafNodeNum(Node* root){
if(root == NULL) return 0;
if(!root ->left && !root ->right) return 1;
return getLeafNodeNum(root ->leaf) + getLeafNodeNum(root ->right);
}
5、求樹的深度
遞歸解法:
(1)如果二叉樹爲空,返回0
(2)如果二叉樹不爲空,返回 二叉樹的深度 = max(左子樹深度,右子樹深度) + 1;
int BinTree::getDepth(Node* root){
if(root == NULL) return 0;
int leftDepth = getDepth(root ->left);
int rightDepth = getDepth(root ->right)'
return leftDepth > rightDepth ? (leftDepth + 1) :(rightDepth + 1);
}
6、求二叉樹第k層節點個數
二叉樹的高度定義爲二叉樹中層數最大的葉結點的層數。
二叉樹的深度定義爲二叉樹中層數最大的葉結點的層數。
樹的層數是從第1層開始的
遞歸解法:
(1)如果二叉樹爲空或k < 1 返回 0
(2)如果二叉樹不爲空,k == 1 返回 1
(3)如果二叉樹不爲空,k > 1 返回 k - 1 層(上一層)的左子樹的節點個數和右子樹中的節點個數之和
int BinTree::getNodeNumKthLevel(Node* root,int k){
if(k < 1 || root == NULL) return 0;
if(k == 1) return 1;
return getNodeNumKthLevel(root ->left,k-1) + getNodeNumKthLevel(root ->right,k-1);
}
7、求第k層葉子節點個數
求第k層葉子節點個數時我們可以藉助求第k層節點個數並加上對節點是否是葉子節點的判斷
遞歸解法:
(1)如果二叉樹爲空或 k < 1 返回 0
(2)如果二叉樹不爲空,且 k = 1,此時需要對葉子節點進行判斷
如果左右子樹均爲空,返回 1
如果左右子樹不全爲空,返回 0
(3)如果二叉樹不爲空,則返回 k - 1層左右子樹的葉子節點數
int BinTree::getLeafNodeNum(Node* root){
if(root == NULL || k < 1) return 0;
if(k == 1){
if(root ->left == NULL && root ->right == NULL) return 1;
else return 0;
}
return getLeafNodeNum(root ->left, k - 1) + getLeafNodeNum(root ->right, k - 1);
}
8、二叉樹的前序遍歷、中序遍歷、後序遍歷、層次序遍歷
前序遍歷
遞歸解法:
(1)如果二叉樹爲空,返回
(2)如果二叉樹不爲空,訪問根節點之後,遍歷左子樹,遍歷右子樹
以訪問輸出爲例:
void BinTree::preorder(Node* root){
if(root == NULL) return;
cout << root ->value;
preorder(root ->left);
preorder(root ->right);
}
中序遍歷
遞歸解法:
(1)如果二叉樹爲空,返回
(2)如果二叉樹不爲空,先遍歷訪問左子樹,再訪問根節點,最後遍歷訪問右子樹
void BintTree::inorder(Node* root){
if(root == NULL) return;
inorder(root ->leaf);
cout << root ->value;
inorder(root ->right);
}
後序遍歷
遍歷解法:
(1)如果二叉樹爲空,返回
(2)如果二叉樹不爲空,先遍歷訪問左子樹,再遍歷訪問右子樹,最後訪問根節點
void BinTree::postorder(Node* root){
if(root == NULL)
return;
postorder(root ->left);
postorder(root ->right);
cout << root ->value<<" ";
}
層次序遍歷
相當於廣度優先遍歷,使用隊列實現。在每一層進行訪問的同時,將其子節點放入隊列中。
void BinTree::levelorder(Node* root){
if(root == NULL) return;
queue<Node*> q;
q.push(root);
while(!q.empty()){
Node *node = q.front();
q.pop();
cout << node ->value<<" ";
if(node ->left != NULL) q.push(node ->left);
if(node ->right != NULL) q.push(node ->right);
}
}
9、 二叉樹根據前序和中序、中序和後序確定並重建二叉樹
直接輸出後序
假設前序和中序序列保存在數組當中
在前序結果中,第一個數就是二叉樹的根節點,可以根據這個數在中序結果中確認其左子樹和右子樹(在中序遍歷中,在根節點之前被訪問的是根節點的左子樹,在根節點之後被訪問的是根節點的右子樹)
(1)根據前序結果得到當前的根節點
(2)在中序結果中根據當前根節點確定其左子樹和右子樹範圍
(3)遞歸實現將對當前根節點的左子樹和右子樹進行後序遍歷
int pre[] = {1,2,4,7,3,5,8,9,6};
int in[] = {4,7,2,1,8,5,9,3,6};
void printPostOrder(int pre[],int pos1,int in[],int pos2,int n){
if(n == 1){
cout << pre[pos1];
return;
}
if(n == 0) return;
int i = 0;
for( ; pre[pos1] != pre[pos2+i]; i ++);
//首先輸出其左子樹
printPostOrder(pre,pos1+1,in,pos2,i);
printPostOrder(pre,pos1+i+1,in,pos2+i+1,n-i+1);
cout << pre[pos1]<<endl;
}
利用前序和中序結果創建二叉樹
按照創建二叉樹的基本思路,在創建左右子樹之前先創建根節點
Node* BinTree::create(Node* root,int pre[],int pos1,int in[],int pos2,int n){
if (n == 0) root = NULL;
int i = 0;
for( ; pre[pos1] != pre[pos2+i]; i ++);
root = new Node;
root ->value = pre[pos1];
root ->left = create(root ->left,pre,pos1+1,in,pos2,i);
root ->right = create(root ->right,pre,pos1+i+1,in,pos2+i+1,n-i-1);
return root;;
}
10、二叉樹轉置
遞歸解法:
(1)如果二叉樹爲空,返回
(2)如果二叉樹不爲空,將其左右子樹進行遞歸調換
void BiTree::mirror(Node* root){
if(root == NULL) return;
Node *temp = root ->left;
root ->left = root ->right;
root ->right = temp;
mirror(root ->left);
mirror(root ->right);
}