读书笔记之:数据结构,算法与应用(3)

第8章 二叉树和其他树
1. 术语:
树和二叉树的术语,如高度、深度、层、根、叶子、子节点、父节点和兄弟节点。
4种常用的二叉树遍历方法:前序遍历,中序遍历,后序遍历和按层遍历。
2. 线性数据结构,表数据结构,层次数据结构
3. 二叉树与树的根本区别
4. 二叉树的特性
5. 二叉树遍历方法
在前三种方法中,每个节点的左子树在其右子树之前遍历。这三种遍历的区别在于对同一个节点在不同时刻进行访问。在进行前序遍历时,每个节点是在其左右子树被访问之前进行访问的;在中序遍历时,首先访问左子树,然后访问子树的根节点,最后访问右子树。在后序遍历时,当左右子树均访问完之后才访问子树的根节点。
在逐层遍历过程中,按从顶层到底层的次序访问树中元素,在同一层中,从左到右进行访问。由于遍历中所使用的数据结构是一个队列而不是栈,因此写一个按层遍历的递归程序很困难。
6. 二叉树遍历一个常用问题:数学表达式的形式
当对一棵数学表达式树进行中序,前序和后序遍历时,就分别得到表达式的中缀、前缀和后缀形式。中缀( infix)形式即平时所书写的数学表达式形式,在这种形式中,每个二元操作符(也就是有两个操作数的操作符)出现在左操作数之后,右操作数之前。在使用中缀形式时,可能会产生一些歧义。例如, x+y×z 可以理解为 (x+y)×z 或x+(y×z)。为了避免这种歧义,可
对操作符赋于优先级并采用优先级规则来分析中缀表达式。在完全括号化的中缀表达式中,每个操作符和相应的操作数都用一对括号括起来。更甚者把操作符的每个操作数也都用一对括号括起来。如 ((x)+(y)),((x)+((y)*(z)))和(((x)+(y))*((y)+(z)))*(w)。
在后缀(postfix)表达式中,每个操作符跟在操作数之后,操作数按从左到右的顺序出现。在前缀( p r e f i x)表达式中,操作符位于操作数之前。在前缀和后缀表达式中不会存在歧义。因此,在前缀和后缀表达式中都不必采用括号或优先级。从左到右或从右到左扫描表达式并采用操作数栈,可以很容易确定操作数和操作符的关系。若在扫描中遇到一个操作数,把它压入堆栈,若遇到一个操作符,则将其与栈顶的操作数相匹配。把这些操作数推出栈,由操作符执行相应的计算,并将所得结果作为操作数压入堆栈。
7. 抽象数据结构:二叉树
 

二叉树节点代码:

View Code
#ifndef _BINARYTREENODE_H_
#define _BINARYTREENODE_H_
template <class T>
class BinaryTree;
class Booster;
template <class T>
class BinaryTreeNode{
    friend class BinaryTree<T>;
    friend class Booster;
    friend void PlaceBoosters(BinaryTreeNode<Booster>*);
    public:
    BinaryTreeNode(){
        lchild=rchild=0;
    }
    BinaryTreeNode(const T& e){
        data=e;
        lchild=rchild=0;
    }
    BinaryTreeNode(const T& e,BinaryTreeNode<T>* l,BinaryTreeNode<T>* r){
        data=e;
        lchild=l;
        rchild=r;
    }
    T getData(){
        return data;
    }
    BinaryTreeNode<T>* getLChild(){
        return lchild;
    }
    BinaryTreeNode<T>* getRChild(){
        return rchild;
    }
    void setData(const T& e){
        data=e;
    }
    void setLChild(BinaryTreeNode<T>* l){
        lchild=l;
    }
    void setRChild(BinaryTreeNode<T>* r){
        rchild=r;
    }
    private:
    T data;
    BinaryTreeNode<T> *lchild;
    BinaryTreeNode<T> *rchild;
};
#endif

数据类型二叉树类:

View Code
#ifndef _BINARYTREE_H_
#define _BINARYTREE_H_
#include <iostream>
#include <queue>
#include "BinaryTreeNode.h"
int _count;
template <class T>
class BinaryTree{
    public:
        BinaryTree():root(0){}
        ~BinaryTree(){}
        bool IsEmpty()const{
            return root?false:true;
        }
        bool Root(T& x)const;
        void MakeTree(const T& elem,BinaryTree<T>& left,BinaryTree<T>& right);
        void BreakTree(T& elem,BinaryTree<T>& left,BinaryTree<T>& right);
        void PreOrder(void(*Visit)(BinaryTreeNode<T>* u)){
            PreOrder(Visit,root);
        }
        void InOrder(void(*Visit)(BinaryTreeNode<T>* u)){
            InOrder(Visit,root);
        }
        void PostOrder(void(*Visit)(BinaryTreeNode<T>* u)){
            PostOrder(Visit,root);
        }
        void LevelOrder(void(*Visit)(BinaryTreeNode<T>*u));
        void PreOutput(){
            PreOrder(Output,root);
            std::cout<<std::endl;
        }
        void InOutput(){
            InOrder(Output,root);
            std::cout<<std::endl;
        }
        void PostOutput(){
            PostOrder(Output,root);
            std::cout<<std::endl;
        }
        void LevelOutput(){
            LevelOrder(Output);
            std::cout<<std::endl;
        }
        void Delete(){
            PostOrder(Free,root);
            root=0;
        }
        int Height()const{
            return Height(root);
        }
        int Size(){
            _count=0;
            PreOrder(Add1,root);
            return _count;
        }
    private:
        BinaryTreeNode<T> *root;
        void PreOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t);
        void InOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t);
        void PostOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t);
        static void Output(BinaryTreeNode<T>* t){
            std::cout<<t->data<<' ';
        }
        static void Free(BinaryTreeNode<T>* t){
            delete t;
        }
        int Height(BinaryTreeNode<T> *t)const;
        static void Add1(BinaryTreeNode<T>* t){
            _count++;
        }
};
template <class T>
bool BinaryTree<T>::Root(T& x)const
{
    if(root){
        x=root->data;
        return true;
    }
    else
        return false;
}
    template <class T>
void BinaryTree<T>::MakeTree(const T& elem,BinaryTree<T>& left,BinaryTree<T>& right)
{
    root=new BinaryTreeNode<T>(elem,left.root,right.root);
    left.root=right.root=0;
}
    template <class T>
void BinaryTree<T>::BreakTree(T& elem,BinaryTree<T>& left,BinaryTree<T>& right)
{
    if(!root)
        throw "BadInput";
    elem=root->data;
    left.root=root->lchild;
    right.root=root->rchild;
    delete root;
    root=0;
}
    template <class T>
void BinaryTree<T>::PreOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t)
{
    if(t){
        Visit(t);
        PreOrder(Visit,t->lchild);
        PreOrder(Visit,t->rchild);
    }

}
    template <class T>
void BinaryTree<T>::InOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t)
{
    if(t){
        InOrder(Visit,t->lchild);
        Visit(t);
        InOrder(Visit,t->rchild);
    }

}
    template <class T>
void BinaryTree<T>::PostOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t)
{
    if(t){
        PostOrder(Visit,t->lchild);
        PostOrder(Visit,t->rchild);
        Visit(t);
    }

}
template <class T>
void BinaryTree<T>::LevelOrder(void(*Visit)(BinaryTreeNode<T>*u )){
    std::queue<BinaryTreeNode<T>*> qu;
    BinaryTreeNode<T>* t;
    qu.push(root);
    while(!qu.empty()){
        t=qu.front();
        if(t){
            Visit(t);
            if(t->lchild)
                qu.push(t->lchild);
            if(t->rchild)
                qu.push(t->rchild);
        }
        qu.pop();
    }
}
template <class T>
int BinaryTree<T>::Height(BinaryTreeNode<T> *t)const{
    if(!t)
        return 0;
    int hl=Height(t->lchild);
    int hr=Height(t->rchild);
    if(hl>hr)
        return ++hl;
    else
        return ++hr;
}
#endif

二叉树测试代码:

View Code
#include <iostream>
#include "BinaryTree.h"
using namespace std;

int count=0;
BinaryTree<int> a,x,y,z;
template<class T>
void ct(BinaryTreeNode<T> *t){
    count++;
}
void test1(){
    y.MakeTree(10,a,a);
    z.MakeTree(20,a,a);
    x.MakeTree(30,y,z);
    y.MakeTree(40,x,a);
    y.PreOrder(ct);
    cout<<count<<endl;
    y.PreOutput();
    y.InOutput();
    y.PostOutput();
    y.LevelOutput();
}
void test2(){
    y.MakeTree(1,a,a);
    z.MakeTree(2,a,a);
    x.MakeTree(3,y,z);
    y.MakeTree(4,x,a);
    cout << "Preorder sequence is ";
    y.PreOutput();
    cout << "Inorder sequence is ";
    y.InOutput();
    cout << "Postorder sequence is ";
    y.PostOutput();
    cout << "Level order sequence is ";
    y.LevelOutput();
    cout << "Number of nodes = ";
    cout << y.Size() << endl;
    cout << "Height = ";
    cout << y.Height() << endl;
    y.PreOrder(ct);
    cout << "Count of nodes is " << count << endl;

}

int main(){
    test2();

}
8. 删除二叉树
要删除一棵二叉树,需要删除其所有节点。可以通过后序遍历在访问一个节点时,把其删除。也就是说先删除左子树,然后右子树,最后删除根。
9. 计算高度
通过进行后序遍历,可以得到二叉树的高度。首先得到左子树的高度 hl,然后得到右子树的高度hr。此时,树的高度为:
max{hl,hr} + 1

10.设置信号放大器

代码如下:

View Code
#include <iostream>
#include "BinaryTree.h"
using namespace std;

int tolerance = 3;

class Booster{
    friend int main();
    friend void PlaceBoosters(BinaryTreeNode<Booster>*);
    public:
    void Output(ostream& out)const{
        out<<boost<<' '<<D<<' '<<d<<' ';
    }
    private:
    int D,d;
    bool boost;
};
ostream& operator<<(ostream& out,const Booster& x)
{
    x.Output(out);
    return out;
}
void PlaceBoosters(BinaryTreeNode<Booster>* x){
    BinaryTreeNode<Booster> *y=x->getLChild();
    int degr;
    Booster btr;
    btr.D=0;
    x->data.D=0;
    if(y){
        degr=(y->getData()).D+(y->getData()).d;
        if(degr>tolerance){
            y->data.boost=true;
            x->data.D=y->data.d;
        }
        else
            x->data.D=degr;
    }
    y=x->getRChild();
    if(y){
        degr=y->data.D+y->data.d;
        if(degr>tolerance) {
            y->data.boost=true;
            degr=y->data.d;
        }
        if(x->data.D<degr)
            x->data.D=degr;
    }
}
BinaryTree<Booster> T, U, V, W, X, Y;
int main(void)
{
    Booster a, b;
    a.d = 2; a.D =0; a.boost = 0;
    b.d=1; b.D=0; b.boost = 0;
    U.MakeTree(a,X,X);
    V.MakeTree(b,U,X);
    U.MakeTree(a,X,X);
    W.MakeTree(a,U,X);
    b.d=3;
    U.MakeTree(b,V,W);
    V.MakeTree(a,X,X);
    b.d=3;
    W.MakeTree(b,X,X);
    Y.MakeTree(a,V,W);
    W.MakeTree(a,X,X);
    T.MakeTree(b,Y,W);
    b.d=0;
    V.MakeTree(b,T,U);
    V.PostOrder(PlaceBoosters);
    V.PostOutput();
}                                      

 11. 树与二叉树(详细介绍)

 

12. 在线等价类问题 

 (1)利用数组解决

代码如下:
View Code
//Online equivalence class functions using arrays
#include <iostream>
using namespace std;
int *E, n;

void Initialize(int n)
{// Initialize n classes with one element each.                           
    E = new int [n + 1];
    for (int e = 1; e <= n; e++)
        E[e] = e;
}

void Union(int i, int j)
{// Union the classes i and j.
    for (int k = 1; k <= n; k++)
        if (E[k] == j) E[k] = i;
}

int Find(int e)
{// Find the class that contains element i.
    return E[e];
}

int main(void)
{
    n = 10;
    Initialize(n);
    Union(1,2);
    Union(3,4);
    Union(1,3);
    cout << '1' << ' ' << Find(1) << ' ' << '2' << ' ' << Find(2) << endl;
    cout << '3' << ' ' << Find(3) << ' ' << '4' << ' ' << Find(4) << endl;
    cout << '5' << ' ' << Find(5) << ' ' << '6' << ' ' << Find(6) << endl;
}                                                                          

(2)利用树解决

代码如下:
View Code
//Simple tree solution to union-find problem
//
#include <iostream>
using namespace std;
int *parent;
void Initialize(int n){
    parent=new int[n+1];
    for(int e=1;e<=n;e++)
        parent[e]=0;
}
int Find(int e){
    while(parent[e])
        e=parent[e];
    return e;
}
void Union(int i,int j){
    parent[j]=i;
}
int main(void)
{
   Initialize(10);
   Union(1,2);
   Union(3,4);
   Union(1,3);
   cout << "Find(1) = " << Find(1) << " Find(2) = " << Find(2) << endl;
   cout << "Find(3) = " << Find(3) << " Find(4) = " << Find(4) << endl;
   cout << "Find(5) = " << Find(5) << " Find(6) = " << Find(6) << endl;
}                                                                       

 (3)利用重量或高度规则来提高性能

代码如下:

 

View Code
// union/find with weighting rule
#include <iostream>
#include <cstdlib>
using namespace std;

int *parent;
bool *root;

void Initialize(int n)
{// One element per set/class/tree.
    root = new bool[n+1];
    parent = new int[n+1];
    for (int e = 1; e <= n; e++) {
        parent[e] = 1;
        root[e] = true;}
}

int Find(int e)
{// Return root of tree containing e.
    while (!root[e])
        e = parent[e];  // move up one level
    return e;
}

int Find_compact(int e)
{// Return root of tree containing e.
 
// Compact path from e to root.
   int j = e;
   // find root
   while (!root[j])
      j = parent[j];
      
   // compact
   int f = e;  // start at e
   while (f != j) {// f is not root
      int pf = parent[f];
      parent[f] = j;  // move f to level 2
      f = pf;         // f moves to old parent 
      }

   return j;
}  

void Union(int i, int j)
{// Combine trees with roots i and j.
    
// Use weighting rule.
    if (parent[i] < parent[j]) {
        // i becomes subtree of j
        parent[j] += parent[i];
        root[i] = false;
        parent[i] = j; }
    else {// j becomes subtree of i
        parent[i] += parent[j];
        root[j] = false;
        parent[j] = i;}
}

int main(void)
{
    Initialize(10);
    Union(1,2);
    Union(3,4);
    Union(1,3);
    cout << '1' << ' ' << Find(1) << ' ' << '2' << ' ' << Find(2) << endl;
    cout << '3' << ' ' << Find(3) << ' ' << '4' << ' ' << Find(4) << endl;
    cout << '5' << ' ' << Find(5) << ' ' << '6' << ' ' << Find(6) << endl;

}

 

posted @ 2012-07-02 11:23  Mr.Rico  阅读(324)  评论(0编辑  收藏  举报