天天看點

二叉樹的基本操作

這篇文章隻有二叉樹的基本操作,對于AVL、Huffman等不涉及。基本都是計科專業課内的知識點。

#include <bits/stdc++.h>
#define MAX 1010
using namespace std;
/*
    樹的基本操作:
        00)由前序結果建樹 
        01)前序遞歸周遊
        02)前序非遞歸周遊 
        03)中序遞歸周遊 
        04)中序非遞歸周遊 
        05)後序遞歸周遊 
        06)後序非遞歸周遊 
        07)層序周遊
        08)層序周遊,按層輸出
        09)計算葉結點個數
        10)計算每層中葉結點的個數
        11)樹的高度(根結點為 1)
        12)某結點的深度(根結點為 1,找不到傳回 0,如果有多個則傳回距根結點較近的)
        13)某結點的深度(根結點為 1,找不到傳回 0,如果有多個則傳回距根結點較遠的)
        14)某結點的父結點集合(找不到傳回空,此結點存在多個時傳回離根較近的結果,遠近相同時傳回左邊的)
        15)某結點的父結點集合(找不到傳回空,此結點存在多個時傳回離根較遠的結果,遠近相同時傳回左邊的)
        16)某結點的直接父節點(找不到傳回 -1,此結點存在多個時傳回離根較近的結果,遠近相同時傳回左邊的)
        17)某結點的直接父節點(找不到傳回 -1,此結點存在多個時傳回離根較遠的結果,遠近相同時傳回左邊的)
        18)前序和中序建樹
        19)後序和中序建樹
        20)每一棵樹及其子樹做鏡面反轉 
        21)樹的複制 
*/

//二叉樹結點結構 
typedef class Node
{
    public:
        int val;
        Node *left;
        Node *right;
        Node(){ left = right = NULL; }
        Node(int tval){ val = tval; left = right = NULL; }
} *BinTree;

//根據前序周遊的結果建樹,空結點用-1表示 
BinTree createTree_preOrder()
{
    int val;
    cin >> val;
    if(val == -)
        return NULL;            //空結點時退棧 
     BinTree temp = new Node();
     temp->val = val;
     temp->left = createTree_preOrder();    //遞歸建立左子樹 
     temp->right = createTree_preOrder();   //遞歸建立右子樹 
     return temp;
}

//遞歸的前序周遊
void print_preOrder_recursion(BinTree root)
{
    if(root != NULL)
    {
        cout << root->val;
        print_preOrder_recursion(root->left);
        print_preOrder_recursion(root->right);
    }
}

/*
    非遞歸的前序周遊:
        當棧不空或者目前指向的結點不空時,便還沒有通路完: 
            1)目前指向不空的時候:輸出、壓棧、向左下移
            2)目前指向為空的時候:彈棧、向右下移
*/
void print_preOrder_noRecursion(BinTree root)
{
    BinTree arr[MAX];
    int t = ;          //棧頂。模拟棧 
    BinTree pointer = root;
    while(pointer != NULL || t != )
    {
        if(pointer != NULL)
        {
            cout << pointer->val;
            arr[t++] = pointer;
            pointer = pointer->left;
        }else
            pointer = arr[--t]->right;
    }
}

//遞歸的中序周遊
void print_inOrder_recursion(BinTree root)
{
    if(root != NULL)
    {
        print_inOrder_recursion(root->left);
        cout << root->val;
        print_inOrder_recursion(root->right);
    }
}

/*
    非遞歸的中序周遊: 
        當棧不空或者目前指向的結點不空時,便還沒有通路完: 
            1)目前指向不空的時候:壓棧、向左下移
            2)目前指向為空的時候:彈棧、輸出、向右下移
*/
void print_inOrder_noRecursion(BinTree root)
{
    BinTree arr[MAX];
    int t = ;          //棧頂。模拟棧 
    BinTree pointer = root;
    while(pointer != NULL || t != )
    {
        if(pointer != NULL)
        {
            arr[t++] = pointer;
            pointer = pointer->left;
        }else{
            pointer = arr[--t];
            cout << pointer->val;
            pointer = pointer->right; 
        } 
    }
}

//遞歸的後序周遊
void print_posOrder_recursion(BinTree root)
{
    if(root != NULL)
    {
        print_posOrder_recursion(root->left);
        print_posOrder_recursion(root->right);
        cout << root->val;
    }
}

/*
    非遞歸的後序周遊:
        當棧不空或者目前指向的結點不空時,便還沒有通路完: 
            1)循環 壓入結點、向左下移 至目前指向為空 
            2)彈棧
            3)右子樹為空或從右子樹傳回時:輸出、記錄右子樹、目前指向置空 
            4)右子樹不空且不是從右子樹傳回時:壓棧、向右下移
*/
void print_posOrder_noRecursion(BinTree root)
{
    BinTree arr[MAX];
    int t = ;          //棧頂。模拟棧 
    BinTree pointer = root;
    BinTree visit = NULL;
    while(pointer != NULL || t != )
    {
        while(pointer != NULL) 
        {
            arr[t++] = pointer;
            pointer = pointer->left;
        }
        pointer = arr[--t];
        if(pointer->right != NULL && pointer->right != visit)
        {
            arr[t++] = pointer;
            pointer = pointer->right;
        }else{
            cout << pointer->val;
            visit = pointer;
            pointer = NULL;
        }
    }
}

/*
    層序周遊,不分層輸出:
        樹不空時根結點壓入隊列中,當隊列不空時便沒有通路完
        對所有的結點,入隊和出隊都隻進行一次,兩種方式都可以通路,在這選擇出隊時通路: 
            1)出隊列、左子樹不空左子樹入隊、右子樹不空右子樹入隊 
*/
void print_levelOrder_noLayered(BinTree root)
{
    BinTree pointer = root;
    int f = , t = ;   //頭、尾。模拟隊列 
    BinTree arr[MAX];
    if(pointer != NULL)
        arr[t++] = pointer;
    while(t > f)
    {
        pointer = arr[f++];
        cout << pointer->val;
        if(pointer->left != NULL)
            arr[t++] = pointer->left;
        if(pointer->right != NULL)
            arr[t++] = pointer->right;
    }
}

/*
    層序周遊,分層輸出:
        樹不空時根結點壓入隊列中,當父親隊列和孩子隊列都不空時便沒有通路完
        對所有的結點,兩個隊列入隊和出隊都隻進行一次,四種方式都可以通路,在這選擇出父親隊列時通路:
            1)父親隊列不空時:出隊列、輸出、左子樹不空壓入孩子隊列、右子樹不空壓入孩子隊列
            2)父親隊列為空時:孩子隊列的結點都壓入父親隊列、輸出換行
*/
void print_levelOrder_layered(BinTree root)
{
    BinTree father[MAX], child[MAX];
    int ff = , ft = ;     //模拟父親隊列 
    int cf = , ct = ;     //模拟孩子隊列 
    BinTree pointer = root;
    if(pointer != NULL)
        father[ft++] = pointer;
    while(ff < ft || cf < ct)   //父親隊列不空且孩子隊列不空 
    {
        if(ff < ft)     //父親隊列不空時,輸出 
        {
            pointer = father[ff++];
            cout << pointer->val << " ";
            if(pointer->left != NULL)
                child[ct++] = pointer->left;
            if(pointer->right != NULL) 
                child[ct++] = pointer->right;
        }else{
            while(cf < ct)
                father[ft++] = child[cf++];
            cout << endl;
        }
    }
}

/*
    計算葉結點個數:
        任意一種周遊,左子樹為空右子樹為空時計入 
*/
int count_leaves(BinTree root)
{
    if(root == NULL)
        return ;
    if(root->left == NULL && root -> right ==NULL)
        return ;
    int l = count_leaves(root->left);
    int r = count_leaves(root->right);
    return l + r;
}

/*
    計算每層葉結點的個數
        層序周遊計數 
*/
void count_leaves_layered(BinTree root)
{
    BinTree father[MAX], child[MAX];
    int ff = , ft = ;     //模拟父親隊列 
    int cf = , ct = ;     //模拟孩子隊列
    int n = ;              //記錄每層的個數 
    BinTree pointer = root;
    if(pointer != NULL)
        father[ft++] = pointer;
    while(ff < ft || cf < ct)   //父親隊列不空且孩子隊列不空 
    {
        if(ff < ft)
        {
            pointer = father[ff++];
            if(pointer->left == NULL && pointer->right == NULL)
                n++;
            if(pointer->left != NULL)
                child[ct++] = pointer->left;
            if(pointer->right != NULL) 
                child[ct++] = pointer->right;
        }else{
            while(cf < ct)
                father[ft++] = child[cf++];
            cout << n << " ";
            n = ;
        }
    }
    cout << n;
}

/*
    樹的高度:
        目前結點為空結點時傳回 0,否則傳回其左右子樹中較大的高度 
*/
int tree_height(BinTree root)
{
    if(root == NULL)
        return ;
    int l = tree_height(root->left);
    int r = tree_height(root->right);
    return l > r ? l +  : r + ;
}

/*
    某結點的深度(近距離優先):
        遞歸周遊,如果目前結點是所找結點,則傳回 1,否則傳回 0 
        如果目前結點的接受到的孩子結點傳回值(n)不是 0,傳回 n + 1 
*/
int node_depth_near(BinTree root, int val)
{
    if(root == NULL)
        return ; 
    if(root->val == val)
        return ;
    int l = node_depth_near(root->left, val);
    int r = node_depth_near(root->right, val);
    if(l ==  && r == )
        return ;
    else if(l == )
        return r + ;
    else if(r == )
        return l + ;
    return l < r ? l +  : r + ;
}

/*
    某結點的深度(遠距離優先):
        遞歸周遊,如果目前結點是所找結點,則傳回 1,否則傳回 0 
        如果目前結點的接受到的孩子結點傳回值(n)不是 0,傳回 n + 1 
*/
int node_depth_far(BinTree root, int val)
{
    if(root == NULL)
        return ;
    int l = node_depth_far(root->left, val);
    int r = node_depth_far(root->right, val);
    if(l ==  && r == )
    {
        if(root->val == val)
            return ;
        else
            return ;
    }
    else if(l == )
        return r + ;
    else if(r == )
        return l + ;
    return l > r ? l +  : r + ;
} 

/*
    某結點的父節點集合(近距離優先。找不到時傳回空,多個時傳回較近的,遠近相同時傳回左邊的): 
        結點為空時:傳回空
        結點為所求結點時:傳回vector<int> 
        結點不空時:向左向右遞歸
                    退棧時若左右結點都為空,傳回 NULL 
                    退棧時若左右結點都為空,且目前結點不所求系結點傳回vector<int>
                    左子樹空傳回右子樹、右子樹空傳回左子樹 
                    左右結點都不空時傳回size較大的,size一緻時傳回左子樹。 
*/ 
vector<int> *getFathers_near(BinTree root, int val)
{
    if(root == NULL)
        return NULL;
    if(val == root->val)
        return new vector<int>;
    vector<int> * l = getFathers_near(root->left, val);
    vector<int> * r = getFathers_near(root->right, val);
    if(l == NULL && r == NULL)
        return NULL;
    if(l == NULL)
    {
        r->push_back(root->val);
        return r;
    }
    if(r == NULL)
    {
        l->push_back(root->val);
        return l;
    }
    l->push_back(root->val);
    r->push_back(root->val); 
    if(r->size() == l->size())
        return l;
    return r->size() > l->size() ? l : r; 
}

/*
    某結點的父節點集合(遠距離優先。找不到時傳回空,多個時傳回較遠的,遠近相同時傳回左邊的): 
        結點為空時:傳回空
        結點不空時:向左向右遞歸
                    退棧時若左右結點都為空,且目前結點不是所求系結點傳回NULL 
                    退棧時若左右結點都為空,且目前結點不所求系結點傳回vector<int>
                    左子樹為空傳回右子樹、右子樹為空傳回左子樹
                    左右結點都不空時傳回size較大的,size一緻時傳回左子樹。 
*/ 
vector<int> *getFathers_far(BinTree root, int val)
{
    if(root == NULL)
        return NULL;
    vector<int> * l = getFathers_far(root->left, val);
    vector<int> * r = getFathers_far(root->right, val);
    if(l == NULL && r == NULL)
    {
        if(val == root->val)
            return new vector<int>;
        else
            return NULL;
    } 
    if(l == NULL)
    {
        r->push_back(root->val);
        return r;
    }
    if(r == NULL)
    {
        l->push_back(root->val);
        return l;
    }
    l->push_back(root->val);
    r->push_back(root->val); 
    if(r->size() == l->size())
        return l;
    return r->size() > l->size() ? r : l; 
}

/*
    某結點的直接父節點(找不到傳回 -1,此結點存在多個時傳回離根較近的結果,遠近相同時傳回左邊的)
*/ 
int getDirectFather_near(BinTree root, int val)
{
    vector<int> * v = getFathers_near(root, val);
    if(v == NULL)
        return -;
    else
        return v->at();
}

/*
    某結點的直接父節點(找不到傳回 -1,此結點存在多個時傳回離根較遠的結果,遠近相同時傳回左邊的)
*/ 
int getDirectFather_far(BinTree root, int val)
{
    vector<int> * v = getFathers_far(root, val);
    if(v == NULL)
        return -;
    else
        return v->at();
}

/*
    前序和中序建樹(結點數值不能重複): 
        傳入前序周遊結果、中序周遊結果、樹的結點個數
        結點個數大于 0時,向左,向右遞歸。退棧時建立結點把左右子樹連接配接成一棵樹 
        結點個數不大于 0時,傳回空 
*/
BinTree createTree_preAndIn(int *pre, int *in, int n)
{
    if(n > )
    {
        int temp = pre[], i = ;
        while(i < n)
            if(in[i++] == temp)
                break;
        BinTree l = createTree_preAndIn(&pre[], &in[], i - );
        BinTree r = createTree_preAndIn(&pre[i], &in[i], n - i);
        BinTree t = new Node(temp);
        t->left = l;
        t->right = r;
        return t;
    }
    return NULL;
}

/*
    後序和中序建樹(結點數值不能重複): 
        傳入後序周遊結果、中序周遊結果、樹的結點個數
        結點個數大于 0時,向左,向右遞歸。退棧時建立結點把左右子樹連接配接成一棵樹 
        結點個數不大于 0時,傳回空 
*/
BinTree createTree_posAndIn(int *pos, int *in, int n)
{
    if(n > )
    {
        int temp = pos[n - ], i = ;
        while(i < n)
            if(in[i++] == temp)
                break;
        BinTree l = createTree_posAndIn(&pos[], &in[], i - );
        BinTree r = createTree_posAndIn(&pos[i - ], &in[i], n - i);
        BinTree t = new Node(temp);
        t->left = l;
        t->right = r;
        return t;
    }
    return NULL;
}

/*
    每棵樹及其子樹都做鏡面反轉 
        後序遞歸,退棧時交換左右子樹 
*/ 
void reverseTree_mirror(BinTree root)
{
    if(root != NULL)
    {
        reverseTree_mirror(root->left);
        reverseTree_mirror(root->right);
        BinTree temp = root->left;
        root->left = root->right;
        root->right = temp;
    }
}

BinTree copyTree(BinTree root)
{
    if(root != NULL)
    {
        BinTree l = copyTree(root->left);
        BinTree r = copyTree(root->right);
        BinTree temp = new Node(root->val);
        temp->left = l;
        temp->right = r;
        return temp;
    }
    return NULL;
} 
int main()
{
    int pre[] = {, , , , , , , , };
    int in[] = {, , , , , , , , };
    int pos[] = {, , , , , , , , };
    BinTree root = createTree_preOrder();
    print_preOrder_noRecursion(root);
    cout << endl;
    print_inOrder_noRecursion(root);
    cout << endl;
    print_posOrder_noRecursion(root);
    cout << endl;
    print_levelOrder_noLayered(root);
    cout << endl;
    print_levelOrder_layered(root);
    cout << endl;
    cout << count_leaves(root); 
    cout << endl;
    count_leaves_layered(root);
    cout << endl;
    cout << tree_height(root);
    cout << endl;
    cout << node_depth_near(root, );
    cout << endl;
    cout << node_depth_far(root, );
    cout << endl;
    vector<int> *vn = getFathers_near(root, );
    for(int i = ; i < vn->size(); i++)
        cout << vn->at(i) << " ";
    cout << endl;
    vector<int> *vf = getFathers_far(root, );
    for(int i = ; i < vf->size(); i++)
        cout << vf->at(i) << " ";
    cout << endl;
    cout << getDirectFather_near(root, );
    cout << endl;
    cout << getDirectFather_far(root, );
    cout << endl;
    BinTree preAndIn = createTree_preAndIn(pre, in, );
    print_preOrder_recursion(preAndIn);
    cout << endl;
    BinTree posAndIn = createTree_posAndIn(pos, in, );
    print_preOrder_recursion(posAndIn);
    cout << endl;
    reverseTree_mirror(root);
    print_preOrder_recursion(root);
    cout << endl;
    BinTree copy = copyTree(root);
    print_preOrder_recursion(copy);
    return ;
}

/*
                1
            2      3
          4   5  6   7
                8     
                 9
    input:
        1 2 4 -1 -1 5 -1 -1 3 6 8 -1 9 -1 -1 -1 7 -1 -1
    output:
        pre:  124536897
        in:   425189637
        pos:  452986731
        level:123456789
    mirror:
        137689254
*/
           
dsa