2017-8-22二叉樹


title: 2017-8-22二叉樹
tags: ACM,數據結構,
grammar_cjkRuby: true

二叉樹(Binary tree)
二叉樹是每個節點最多隻有兩個分支(不存在分枝度大於2的節點)的結構。通常分支被成爲左子樹和右子樹或者左孩子和右孩子。二叉樹分支具有左右結構,不能顛倒。
二叉樹常用的性質:

  1. 二叉樹第i層最多有2i-1個節點;(可以推出樹的層數是從第1層開始的)
  2. 深度爲k的二叉樹最多共有2k+1-1個節點(定義根節點所在深度k0 = 0);
  3. 深度爲k有n個節點的二叉樹,當且僅當其中的每一個節點,都有可以和同樣深度的滿二叉樹,序號從1到n的節點一一對應的時候被稱爲“完全二叉樹”;
  4. 對任何一顆非空的二叉樹,如果其葉子節點(終端節點)的個數爲n0,度數爲2的節點個數爲n2,則其葉子節點的個數爲n0 = n2 + 1;

二叉樹中常用的方法及講解

  1. 二叉樹的創建
  2. 二叉樹的刪除
  3. 求樹的節點個數
  4. 求樹的葉子節點個數
  5. 求樹的深度
  6. 求二叉樹第k層節點個數
  7. 求二叉樹第k層的葉子節點個數
  8. 二叉樹前序、中序、後序、層次序遍歷
  9. 二叉樹根據前序和中序、中序和後序確定並重建二叉樹
  10. 二叉樹轉置

首先對節點的結構進行定義(以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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章