1. 程式人生 > >二叉樹的連結實現及基本操作(C++)

二叉樹的連結實現及基本操作(C++)

前言:

學習了棧和佇列後,我們接著在資料結構的海洋中遨遊。這時的我已經被各種棧和佇列折騰的快不行了,然而,當學習了樹之後,才發現自己還是太年輕,跟樹比起來,棧和佇列是那麼的和諧與友好。先來小試牛刀一把,看看最簡單的二叉樹是怎麼實現的:

二叉樹的實現:

二叉樹是節點的有限集合,他或者為空,或者有一個根節點及兩顆互不相交的左右子樹構成,而左右子樹有都是二叉樹。寫到這裡,是不是已經體會到了一點二叉樹與遞迴的曖昧關係。

若一棵樹的任意一層節點數都達到了最大值,則這棵二叉樹稱為滿二叉樹。

而如果將滿二叉樹自右向左依次刪掉幾個節點(注意不要跳過節點),那樣的樹就是完全二叉樹。

FullBT CompleteBT.jpg

二叉樹的常用性質:

1. 一棵非空二叉樹的第i層上最多有2^{i-1}個節點(i>=1)。

2. 一棵高度為k的二叉樹,最多有2^{k} - 1個節點。

3. 對於一棵非空二叉樹,如果葉子節點數為a,度為2的節點數為吧b,則a = b + 1。

4. 具有n個節點的完全二叉樹的高度為k = [log2(n)] + 1。(其中[ ]指不比裡面數大的最大整數)

說了這麼多,下面就來看看具體的C++實現:

#include <iostream>

using namespace std;

template<class elemType>
class queue {
public:
    virtual bool isEmpty() = 0;
    virtual void enQueue(const elemType &x) = 0;
    virtual elemType deQueue() = 0;
    virtual elemType getHead() = 0;
    virtual ~queue(){};
};

template<class elemType>
class linkQueue: public queue<elemType>
{
private:
    struct node{
        elemType data;
        node *next;
        node(const elemType &x, node *N = NULL){
            data = x;
            next = N;
        }
        node():next(NULL){}
        ~node(){}
    };
    
    node *front , *rear;
    
public:
    linkQueue(){
        front = rear = NULL;
        
    }
    ~linkQueue(){
        node *tmp;
        while(front != NULL){
            tmp = front;
            front = front -> next;
            delete tmp;
        }
    }
    bool isEmpty(){
        return front == NULL;
    }
    
    void enQueue(const elemType &x){
        if(rear == NULL){
            front = rear = new node(x);
        }
        else{
            rear -> next = new node(x);
            rear = rear -> next;
        }
    }
    
    elemType deQueue(){
        node *tmp = front;
        elemType value = front -> data;
        front = front -> next;
        if(front == NULL){
            rear = NULL;
        }
        delete tmp;
        return value;
    }
    
    elemType getHead()
    {
        return front-> data;
    }
    
    
};

template<class T>

class bTree{
public:
    virtual void clear() = 0;
    virtual bool isEmpty()const = 0;
    virtual T Root(T flag)const = 0;
    virtual T parent(T x, T flag)const =0;
    virtual T lchild(T x, T flag)const = 0;
    virtual T rchild(T x, T flag)const = 0;
    virtual void delLeft(T x) = 0;
    virtual void delRight(T x) = 0;
    virtual void preOrder() const = 0;
    virtual void midOrder() const = 0;
    virtual void postOrder() const = 0;
    virtual void levelOrder() const = 0;
    
};

template<class T>
class binaryTree:public bTree<T>{
    friend void printTree(const binaryTree &t, T flag);
private:
    struct Node{
        Node *left, *right, *parent;
        T data;
        
        Node():left(NULL), right(NULL), parent(NULL){}
        Node(T item, Node *L = NULL, Node *R = NULL):data(item), left(L), right(R){}
        ~Node(){};
    };
    
    Node *root;
public:
    binaryTree():root(NULL){}
    
    binaryTree(T x){
        root = new Node(x);
    }
    
    ~binaryTree(){
        clear(root);
    }
    
    void clear(Node *t){
        if(t == NULL){
            return;
        }
        clear(t -> left);
        clear(t -> right);
        delete t;
        t = NULL;
    }
    
    void clear(){
        clear(root);
    }
    
    bool isEmpty()const{
        return root == NULL;
    }
    
    T Root(T flag)const{
        if(root == NULL){
            return flag;
        }
        else{
            return root->data;
        }
    }
    
    Node *find(T x, Node *t)const{
        Node *tmp;
        if(t == NULL){
            return t;
            
        }
        if(t -> data == x){
            return t;
        }
        if(tmp = find(x, t -> left)){
            return tmp;
        }
        else{
            return (find(x, t -> right));
        }
    }
    
    T lparent(T x, T flag)const{
        
    }
    
    T lchild(T x, T flag)const{
        Node *tmp = find(x,  root);
        if(tmp == NULL || tmp -> left == NULL){
            return flag;
        }
        return tmp -> left -> data;
        
    }
    
    T rchild(T x, T flag)const{
        Node *tmp = find(x, root);
        if(tmp == NULL || tmp -> right == NULL){
            return flag;
        }
        return tmp -> right -> data;
    }
    

    
    void delLeft(T x){
        Node *tmp = find(x, root);
        if(tmp == NULL){
            return;
        }
        clear(tmp -> left);
        
    }
    
    void delRight(T x){
        Node *tmp = find(x, root);
        if(tmp == NULL){
            return;
        }
        clear(tmp -> right);
    }
    
    //preorder traverse
    void preOrder(Node *t)const{
        if(t == NULL){
            return;
        }
        cout << t -> data << ' ';
        preOrder(t -> left);
        preOrder(t -> right);
    }
    void preOrder()const{
        preOrder(root);
    }
    
    //midorder traverse
    void midOrder(Node *t)const{
        if(t == NULL){
            return;
        }
        midOrder(t -> left);
        cout << t -> data << ' ';
        midOrder(t -> right);
    }
    void midOrder()const{
        midOrder(root);
    }
    
    //postorder traverse
    void postOrder(Node *t) const{
        if(t == NULL){
            return;
        }
        postOrder(t -> left);
        postOrder(t -> right);
        cout << t -> data << ' ';
    }
    
    void postOrder()const{
        postOrder(root);
    }
    
    //levelorder traverse
    void levelOrder()const{
        linkQueue<Node *>que;
        Node *tmp;
        
        que.enQueue(root);
        while(!que.isEmpty()){
            tmp = que.deQueue();
            cout << tmp -> data << ' ';
            if(tmp -> left){
                que.enQueue(tmp -> left);
            }
            if(tmp -> right){
                que.enQueue(tmp -> right);
            }
            
        }
        
    }
    
    //creat a binary tree
    void creatTree(T flag){
        linkQueue<Node *>que;
        Node *tmp;
        T x, ldata, rdata;
        cout << "Please input the root:";
        cin >> x;
        root = new Node(x);
        que.enQueue(root);
        
        while(!que.isEmpty()){
            tmp = que.deQueue();
            cout << "Input the left node and right node:";
            cin >> ldata >> rdata;
            if(!ldata != flag){
                que.enQueue(tmp -> left == new Node(ldata));
            }
            if(!rdata != flag){
                que.enQueue(tmp -> left == new Node(rdata));
            }
        }
        
    }
    
    T parent(T x, T flag)const{
        return flag;
    }
    
    //Judge if it is a complete binary tree
    void isCBT(){

        linkQueue<Node *> que;
        int lastId = 1, nodeCount = 1;
        root -> data = 1;
        Node *tmpNode, *son;
        if(root == NULL){
            cout << 'Y';
            return;
        }

        que.enQueue(root);
        while(!que.isEmpty()){
            tmpNode = que.deQueue();
            if(tmpNode -> left != NULL){
                nodeCount = nodeCount + 1;
                son = tmpNode -> left;
                son -> data = (tmpNode -> data) * 2;
                lastId = son -> data;
                que.enQueue(son);
                
            }
            if(tmpNode -> right != NULL){
                nodeCount = nodeCount + 1;
                son = tmpNode -> right;
                son -> data = (tmpNode -> data) * 2 + 1;
                lastId = son -> data;
                que.enQueue(son);
                
            }
        }
        if(nodeCount == lastId){
            cout << 'Y';
        }
        else{
            cout << 'N';
        }
        
    }

};

總結:

本節內容主要是介紹了樹的基本概念以及二叉樹的定義、特性和實現程式碼,包括構建樹,四種遍歷樹的操作,以及判斷數是否為完全二叉樹的方法,如果你已經覺得樹如此複雜,那隻能說“小朋友,這才是冰山一角中的一角”,想看看冰山的真面目,就鼓足幹勁接著學習吧。