數據結構-二叉樹(2)鏈表法和廣義表法表示二叉樹


數組表示法用於完全二叉樹的存儲表示非常有效,但表示一般二叉樹,尤其是形態劇烈變化的二叉樹,存儲空間的利用很不理想

使用二叉鏈表表示二叉樹:

#include <iostream>
using namespace std;

template <class T>
struct BinTreeNode{
    T data;
    BinTreeNode<T> *leftChild,*rightChild;
    BinTreeNode():leftChild(NULL),rightChild(NULL){}
    BinTreeNode(T x,BinTreeNode<T> *l=NULL,BinTreeNode<T> *r=NULL):data(x),leftChild(l),rightChild(r){};
};

template <class T>
class BinaryTree{
public:
    BinaryTree():root(NULL){}
    BinaryTree(T value):RefValue(value),root(NULL){}
    BinaryTree(const BinaryTree<T>& s){root=Copy(s.root);}  //復制構造函數
    ~BinaryTree(){destroy(root);}
    bool IsEmpty(){return(root==NULL);}
    BinTreeNode<T> *Parent(BinTreeNode<T> *current){        //返回父結點
        return(root==NULL||root==current)?NULL:Parent(root,current);
    }
    BinTreeNode<T> *LeftChild(BinTreeNode<T> *current){    //返回左子女
        return(current!=NULL)?current->leftChild:NULL;
    }
    BinTreeNode<T> *RightChild(BinTreeNode<T> *current){    //返回右子女
        return(current!=NULL)?current->rightChild:NULL;
    }
    int Height(){return Height(root);}     //返回樹高度
    int Size(){return Size(root);}       //返回結點數
    BinTreeNode<T> *getRoot()const{return root;} //取根
    void preOrder(void (*visit)(BinTreeNode<T> *p)){preOrder(root,visit);}   //對根結點前序遍歷
    void InOrder(void (*visit)(BinTreeNode<T> *p)){InOrder(root,visit);}   //對根結點中序遍歷
    void postOrder(void (*visit)(BinTreeNode<T> *p)){postOrder(root,visit);}   //對根結點后序遍歷
    void levelOrder(void (*visit)(BinTreeNode<T> *p));   //層次序遍歷
    int Insert(const T& item);             //插入新元素
    BinTreeNode<T> *Find(T& item)const;   //搜索
protected:
    BinTreeNode<T> *root;  //二叉樹根指針
    T RefValue;            //數據輸入停止標志,用廣義表表示二叉樹的時候用
    void CreateBinTree(istream& in,BinTreeNode<T> *subTree); //從文件讀入建樹
    bool Insert(BinTreeNode<T> *subTree,const T&x);      //插入
    void destroy(BinTreeNode<T> *subTree);              //刪除
    BinTreeNode<T> *Copy(BinTreeNode<T> *orignode);      //復制
    int Height(BinTreeNode<T> *subTree)const;                 //返回樹高度
    int Size(BinTreeNode<T> *subTree)const;                    //返回結點數
    BinTreeNode<T> *Parent(BinTreeNode<T> *subTree,BinTreeNode<T> *current); //從結點subTree開始搜索結點current的父結點
    BinTreeNode<T> *Find(BinTreeNode<T> *subTree,const T& x)const;   //搜尋值為x的結點
    void Traverse(BinTreeNode<T> *subTree,ostream& out);     //前序遍歷輸出
    void preOrder(BinTreeNode<T>* subTree,
                  void (*visit)(BinTreeNode<T> *p));   //對p結點前序遍歷
    void InOrder(BinTreeNode<T>* subTree,
                 void (*visit)(BinTreeNode<T> *p));   //中序遍歷
    void postOrder(BinTreeNode<T>* subTree,
                   void (*visit)(BinTreeNode<T> *p));   //后序遍歷
    friend istream& operator>>(istream& in,BinaryTree<T>& Tree);
    friend ostream& operator<<(ostream& out,BinaryTree<T>& Tree);
    friend bool operator==(const BinaryTree<T>& s,const BinaryTree<T>& t);
    bool equal(BinTreeNode<T> *a,BinTreeNode<T> *b)const;
};

template <class T>
void BinaryTree<T>::destroy(BinTreeNode<T> *subTree){
    //私有函數,若指針subTree不為空,則刪除根為subTree的子樹
    if(subTree!=NULL){
        destroy(subTree->leftChild);
        destroy(subTree->rightChild);
        delete subTree;
    }
}

template <class T>
BinTreeNode<T> *BinaryTree<T>::Parent(BinTreeNode<T> *subTree,BinTreeNode<T> *current){
    //私有函數,從結點subTree開始搜索結點current的父結點,返回父結點地址或者NULL
    if(subTree==NULL) return NULL;
    if(subTree->leftChild==current || subTree->rightChild==current) return subTree;
    BinTreeNode<T> *p;
    if((p=Parent(subTree->leftChild,current))!=NULL) return p;      //使用p=Parent(subTree->leftChild,current)遞歸在左子樹中搜索,p==NULL則說明搜索失敗
    else return Parent(subTree->rightChild,current);
}

template <class T>
void BinaryTree<T>::Traverse(BinTreeNode<T> *subTree,ostream& out){
    //私有函數,搜索並前序輸出根為subTree的二叉樹
    if(subTree!=NULL){
        out<<subTree->data<<'';
        Traverse(subTree->leftChild,out);  //遞歸搜索並輸出subTree的左子樹
        Traverse(subTree->rightChild,out); //遞歸搜索並輸出subTree的右子樹
    }
}

template <class T>
istream& operator>>(istream& in,BinaryTree<T>& Tree){
    //重載操作,輸入並建立一顆二叉樹Tree,in是輸入流對象
    Tree.CreateBinTree(in,Tree.root);    //此處友元函數不能直接訪問類的成員函數
    return in;
}

template <class T>
ostream& operator<<(ostream& out,BinaryTree<T>& Tree){
    //重載操作,輸出一顆二叉樹Tree,out是輸出流對象
    out<<"二叉樹的前序遍歷\n";
    Tree.Traverse(Tree.root,out);         //從根開始輸出
    out<<endl;
    return out;
}

template <class T>
bool operator==(const BinaryTree<T>& s,const BinaryTree<T>& t){
    //判斷兩棵二叉樹的等價性,它需要是BinaryTree類的友元函數
    return s.equal(s.root,t.root);   //此處s是const對象,equal應該是const方法
}

template <class T>
void BinaryTree<T>::preOrder(BinTreeNode<T> *subTree, void (*visit)(BinTreeNode<T> *)) {
    if(subTree!=NULL){
        visit(subTree);
        preOrder(subTree->leftChild,visit);
        preOrder(subTree->rightChild,visit);
    }
}

template <class T>
void BinaryTree<T>::InOrder(BinTreeNode<T> *subTree, void (*visit)(BinTreeNode<T> *)) {
    //遞歸函數,此算法按照中序次序遍歷以subTree為根的子樹
    if(subTree!=NULL){
        InOrder(subTree->leftChild,visit);
        visit(subTree);
        InOrder(subTree->rightChild,visit);
    }
}

template <class T>
void BinaryTree<T>::postOrder(BinTreeNode<T> *subTree, void (*visit)(BinTreeNode<T> *)) {
    if(subTree!=NULL){
        postOrder(subTree->leftChild,visit);
        postOrder(subTree->rightChild,visit);
        visit(subTree);
    }
}

template <class T>
int BinaryTree<T>::Size(BinTreeNode<T> *subTree)const{
    //私有函數,介紹以subTree為根的二叉樹的結點個數
    if(subTree==NULL) return 0;
    else return 1+Size(subTree->leftChild)+Size(subTree->rightChild);
}

template <class T>
int BinaryTree<T>::Height(BinTreeNode<T> *subTree)const{
    //私有函數,計算以subTree為根的二叉樹的深度
    if(subTree==NULL) return 0;
    else{
        int i=Height(subTree->leftChild);
        int j=Height(subTree->rightChild);
        return(i<j)?j+1:i+1;
    }
}

template <class T>
BinTreeNode<T> *BinaryTree<T>::Copy(BinTreeNode<T> *orignode){
    //私有函數,這個函數返回一個指針,給出一個以orignode為根的二叉樹的副本
    if(orignode==NULL) return NULL;
    BinTreeNode<T> *temp=new BinTreeNode<T>;
    temp->data=orignode->data;
    temp->leftChild=Copy(orignode->leftChild);   //此處注意不能直接=,因為需要建立新結點再賦值
    temp->rightChild=Copy(orignode->rightChild);
    return temp;
}

template <class T>
bool BinaryTree<T>::equal(BinTreeNode<T> *a,BinTreeNode<T> *b)const{
    //如果a和b的子樹不同,則函數返回false,否則函數返回true,它需要是BinTreeNode類的友元函數
    if(a==NULL && b==NULL) return true;
    if(a!=NULL && b!=NULL && a->data==b->data && equal(a->leftChild,b->leftChild) && equal(a->rightChild,b->rightChild)) return true;
    else return false;
}

template <class T>
void BinaryTree<T>::CreateBinTree(istream& in,BinTreeNode<T> *subTree){
    //私有函數,以前序遍歷方式遞歸建立二叉樹
    T item;
    if(!in.eof()){      //讀不到輸入流時in.eof()為真
        in>>item;
        subTree=new BinTreeNode<T>(item);
        if(subTree==NULL){
            cerr<<"分配存儲錯誤!"<<endl;
            exit(1);
        }
        CreateBinTree(in,subTree->leftChild);
        CreateBinTree(in,subTree->rightChild);
    }
    else subTree=NULL;
}

二叉鏈表找到父結點很困難,可以使用三叉鏈表

輸入輸出二叉樹時,可以輸入一個廣義表形式的二叉樹,此時需要用棧保存字符。棧的最大深度==二叉樹的高度==廣義表表示中圓括號嵌套的最大層數加1(根結點)

template <class T>
void CreateBinTree(istream& in,BinTreeNode<char>* &BT){
    //從輸入流in輸入二叉樹的廣義表表示建立對應的二叉鏈表,依次從保存廣義表的字符串ls中輸入字符
    Stack<BinTreeNode<char> *> s;
    BT=NULL;    //置空二叉樹表
    BinTreeNode<char> *p,*t;
    int k;  //用k作為處理左右子樹標志
    char ch;
    in>>ch;
    while(ch!=RefValue){         //逐個字符處理
        switch(ch){
            case '(':s.Push(p);k=1;break;      //輸入若是左擴號,則表明子表的開始,將根結點入棧,K置為1
            case ')':s.Pop(t);break;           //輸入若是右括號,則表明子表結束,將根結點出棧
            case ',':k=2;break;                //遇到的是逗號,則表示以左子女為根的子樹處理完畢
            default:p=new BinTreeNode(ch);     //輸入若是字母,為它建立新結點,根據k的值將其鏈接到父節點上
                if(BT==NULL) BT=p;
                else if(k==1){
                    s.getTop(t);
                    t->leftChild=p;    //鏈入*t的左子女
                }
                else{
                    s.getTop(t);
                    t->rightChild=p;   //鏈入*t的右子女
                }
        }
        in>>ch;
    }
}

template <class T>
void PrintBTree(BinTreeNode<T> *BT){    //以廣義表的形式輸出二叉樹
    if(BT!=NULL){
        cout<<BT->data;
        if(BT->leftChild!=NULL||BT->rightChild!=NULL){
            cout<<'(';
            PrintBTree(BT->leftChild);
            cout<<',';
            if(BT->rightChild!=NULL)
                PrintBTree(BT->rightChild);
            cout<<')';
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM