二叉樹(3)

二叉樹的子樹
在二叉樹中以任何一個節點爲頭部的整棵樹稱作二叉樹的子樹。
這裏寫圖片描述
這裏寫圖片描述

平衡二叉樹(AVL樹)
1.空樹是平衡二叉樹
2.如果一棵樹不爲空,並且其中所有的子樹都滿足各自的左子樹與右子樹的高度都不超過1。
這裏寫圖片描述
給定一顆二叉樹的頭節點head,判斷一棵樹是否是平衡二叉樹。

#include<iostream>
#include<string>
#include<stack>
#include<queue>
using namespace std;

class BinaryTreeNode  
{
public:
    char data;  
    BinaryTreeNode *Left;  
    BinaryTreeNode *Right;  
}; 

//創建二叉樹,順序依次爲中間節點->左子樹->右子樹

void createBiTree(BinaryTreeNode* &T)   //這裏加上&意思是傳遞的參數爲指針的引用,括號裏面等價於 BiTreeNode* &T
 {                                 //這樣的意義在於在函數執行過後,傳遞進來的指針會發生改變(引用的作用),不可以去掉&
     char c;
     cin >> c;
     if('#' == c)               //當遇到#時,令樹的根節點爲NULL,從而結束該分支的遞歸
         T = NULL;
     else
     {
         T = new BinaryTreeNode;
         T->data=c;
         createBiTree(T->Left);
         createBiTree(T->Right);
     }
 }

int treeDepth(BinaryTreeNode* root){
    if(root==NULL){
        return 0;
    }
    if(root->Left==NULL){
        return treeDepth(root->Right)+1;
    }
    if(root->Right==NULL){
        return treeDepth(root->Left)+1;
    }
    return treeDepth(root->Right)>treeDepth(root->Left)?treeDepth(root->Right)+1:treeDepth(root->Left)+1;
}

bool isAVLtree(BinaryTreeNode* root){
    if(root==NULL)
        return true;
    if(abs(treeDepth(root->Right)-treeDepth(root->Left))>1)
      return false; 
    return isAVLtree(root->Left)&&isAVLtree(root->Right); 
}

int main(){
    BinaryTreeNode* T;               //聲明一個指向二叉樹根節點的指針               
    createBiTree(T);               //abd###ce##fg###
    cout<<"二叉樹創建完成!"<<endl; 
    cout<<"二叉樹深度:"<<endl; 
    cout<<treeDepth(T)<<endl;
    cout<<endl;
    if(isAVLtree(T)==true){
       cout<<"true"<<endl;
    }
    else
       cout<<"false"<<endl;

    return 0;
}

思路爲二叉樹的後序遍歷。(?)

搜索二叉樹
搜索二叉樹的特徵:
每顆子樹的頭節點的值都比各自左子樹上的所有節點值要大,也都比各自右子樹上的所有節點值要小。
搜索二叉樹按照中序遍歷得到的序列,一定是從小到大排列的。
紅黑樹、平衡搜索二叉樹(AVL樹)等,其實都是搜索二叉樹的不同實現。

給定一顆二叉樹的頭節點head,判斷一棵樹是否是搜索二叉樹。
1.改寫二叉樹的中序遍歷
2.遍歷到每個節點的值時,如果一直比上一個遍歷的節點值要大,則是搜索二叉樹,否則,不是搜索二叉樹。
3.爲了方便同時得到當前節點,和上一個遍歷的節點,二叉樹中序遍歷非遞歸的實現比較合適。

#include<iostream>
#include<string>
#include<stack>
#include<queue>
using namespace std;


class BinaryTreeNode  
{
public:
    char data;  
    BinaryTreeNode *Left;  
    BinaryTreeNode *Right;  
}; 

//創建二叉樹,順序依次爲中間節點->左子樹->右子樹

void createBiTree(BinaryTreeNode* &T)   //這裏加上&意思是傳遞的參數爲指針的引用,括號裏面等價於 BiTreeNode* &T
 {                                 //這樣的意義在於在函數執行過後,傳遞進來的指針會發生改變(引用的作用),不可以去掉&
     char c;
     cin >> c;
     if('#' == c)               //當遇到#時,令樹的根節點爲NULL,從而結束該分支的遞歸
         T = NULL;
     else
     {
         T = new BinaryTreeNode;
         T->data=c;
         createBiTree(T->Left);
         createBiTree(T->Right);
     }
 }

bool sousuomidorder(BinaryTreeNode* &T){
    stack<BinaryTreeNode*> s;
    char last=0;
    BinaryTreeNode* cur=T;
    while(cur!=NULL||!s.empty()){
        while(cur!=NULL){
            s.push(cur);
            cur=cur->Left;
         }
        BinaryTreeNode* node=s.top();
        s.pop();
        char now=node->data;
        if(now<last){
            return false;   
        }
        last=node->data;
        cout<<node->data;
        cur=node->Right;
    }
    return true;
 }

int main(){
    BinaryTreeNode* T;               //聲明一個指向二叉樹根節點的指針               
    createBiTree(T);               //abd###ce##fg###
    cout<<"二叉樹創建完成!"<<endl; 

    cout<<"判斷是否是搜索二叉樹:"<<endl;

    if(sousuomidorder(T)==true){
       cout<<"true"<<endl;
    }
    else
       cout<<"false"<<endl;
    return 0;
}

滿二叉樹
滿二叉樹是除了最後一層的節點無任何子節點外,剩下每一層上的節點都有兩個子節點。
層數爲L,節點數爲N,N=2^L-1

完全二叉樹
是指,除了最後一層之外,其他每一層的節點數都是滿的。最後一層如果也滿了,是一顆滿二叉樹,也是完全二叉樹。最後一層如果不滿,缺少的節點也全部的集中在右邊,那也是一顆完全二叉樹。
這裏寫圖片描述

給定一顆二叉樹的頭節點head,判斷一棵樹是否是完全二叉樹。
1、採用按層遍歷二叉樹的方式,從每層的左邊向右邊依次遍歷所有的節點。
2、如果當前的節點有右孩子,但沒有左孩子,直接返回false。
3、如果當前節點並不是左右孩子全有,那之後的節點必須都爲葉節點,否則返回false。
4、遍歷過程中如果不返回false,遍歷結束後返回true即可。

#include<iostream>
#include<string>
#include<stack>
#include<queue>
using namespace std;


class BinaryTreeNode  
{
public:
    char data;  
    BinaryTreeNode *Left;  
    BinaryTreeNode *Right;  
}; 

//創建二叉樹,順序依次爲中間節點->左子樹->右子樹

void createBiTree(BinaryTreeNode* &T)   //這裏加上&意思是傳遞的參數爲指針的引用,括號裏面等價於 BiTreeNode* &T
 {                                 //這樣的意義在於在函數執行過後,傳遞進來的指針會發生改變(引用的作用),不可以去掉&
     char c;
     cin >> c;
     if('#' == c)               //當遇到#時,令樹的根節點爲NULL,從而結束該分支的遞歸
         T = NULL;
     else
     {
         T = new BinaryTreeNode;
         T->data=c;
         createBiTree(T->Left);
         createBiTree(T->Right);
     }
 }

bool wanquanerchashu(BinaryTreeNode* &T){
    queue<BinaryTreeNode*> q1;
    q1.push(T);
    char yeflag=false;
    while(!q1.empty()){
        BinaryTreeNode* cur=q1.front();
        q1.pop();
        cout<<cur->data;
        if(yeflag==true){//判斷後面的各節點是不是都是葉節點
          if(cur->Left!=NULL||cur->Right!=NULL){
              return false;
          }
        }       
        if(cur->Left==NULL&&cur->Right!=NULL){
            return false;
        }
        if(cur->Left==NULL||cur->Right==NULL){
            yeflag=true;//啓動判斷後面的各節點是不是都是葉節點標識
        }
        if(cur->Left!=NULL){
            q1.push(cur->Left);
        }
        if(cur->Right!=NULL){
            q1.push(cur->Right);
        }
    }
    return true;
}

int main(){
    BinaryTreeNode* T;               //聲明一個指向二叉樹根節點的指針               
    createBiTree(T);               //abd###ce##fg###
    cout<<"二叉樹創建完成!"<<endl; 
    cout<<"判斷完全二叉樹:"<<endl;
    if(wanquanerchashu(T)==true){
       cout<<"true"<<endl;
    }
    else
       cout<<"false"<<endl;

    return 0;
}

注意
面試中,二叉樹節點類型僅包括:數據項、左孩子、右孩子。
工程上的二叉樹節點類型,往往多一條指向父節點的指針。
一般默認面試中的二叉樹節點結構不包括指向父節點的指針,除非特別說明。

後繼節點
一個節點的後繼節點是指,這個節點在中序遍歷序列中的下一個節點。

前驅節點
一個節點的前驅節點是指,這個節點在中序遍歷序列中的上一個節點。

案例
現在有一種新的二叉樹節點類型,定義如下。

public class Node{
     public int valuepublic Node left;
     public Node right;
     public Node parent;
     public Node(int data){
            this.value=data;
     }
}

該結構比普通二叉樹節點結構多了一個指向父節點的parent指針。假設有一顆這種類型的節點組成的二叉樹,樹中每個節點的parent指針都正確指向自己的父節點,頭節點的parent指向空。只給定在二叉樹中的某個節點node。該節點不一定是頭節點,可能是樹中任何一個節點,請實現返回後繼節點的函數。

普通方法:
1.不斷向上找到頭節點
2.利用頭結點進行中序遍歷,進而獲得後續節點。

普通方法要遍歷所有節點,如果二叉樹節點爲N,時間複雜度爲O(N),額外空間複雜度爲O(N)。

最優解法:
情況一:如果node有右子樹,那麼後繼節點就是右子樹上最左邊的節點。
情況二:如果node沒有右子樹,那麼先看node是不是node父節點的左孩子,如果是左孩子,那麼此時node的父節點就是node的後繼節點,如果是右孩子,就向上尋找node的後繼節點,假設向上移動的節點記爲s,s的父節點記爲p,如果發現s是p的左孩子,那麼節點p就是node節點的後繼節點,否則就一直向上移動。
情況三:如果一直向上,都移動到空節點了,還是沒有發現node的後繼節點,說明node根本不存在後繼節點,返回空即可。

如果node節點的node後繼節點之間的實際距離爲L,最優解法只用走過L個節點,時間複雜度爲O(L),額外空間複雜度爲O(1),也就是常數級別。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章