数据结构,算法与应用(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. 抽象数据结构:二叉树
 

二叉树节点代码:

复制代码
#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
复制代码

数据类型二叉树类:

复制代码
#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
复制代码

二叉树测试代码:

复制代码
#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.设置信号放大器 

代码如下:

复制代码
#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)利用数组解决 

代码如下: 
复制代码
// 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)利用树解决 

代码如下: 
复制代码
// 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)利用重量或高度规则来提高性能

代码如下:

 

复制代码
//  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;

}
复制代码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值