zoukankan      html  css  js  c++  java
  • 基于左子结点/右兄弟结点表示法和二叉链表来实现二叉树ADT

    实现二叉树的ADT需要分别实现结点ADT和树ADT,同时也要保证其封装性

    二叉链表

    树结点ADT的声明以及实现

    (1)每一个结点包括其要储存的数据以及左右子节点的指针,通常一颗二叉树中只有根结点能被直接访问,所以要把数据以及子节点的指针设为private

    (2)成员函数要包括:

    • 构造函数,析构函数(也可以不写)
    • 获取和设置结点内储存的数据,左子节点,右子节点   
    • 判断该节点是否为叶子节点
     1 #ifndef _BINNODE_HPP_
     2 #define _BINNODE_HPP_
     3 #include<iostream>
     4 using namespace std;
     5 class BinNode{
     6     private:
     7             char data;
     8             BinNode *lc;
     9             BinNode *rc;
    10     public:
    11             BinNode(char dataval,BinNode *l=NULL,BinNode* r=NULL){data=dataval;lc=l;rc=r;}
    12             BinNode(BinNode *l=NULL,BinNode* r=NULL){lc=l;rc=r;}
    13             void setLeftChild(BinNode *l){lc=l;}
    14             void setRightChild(BinNode *r){rc=r;}
    15             void setdata(char d){data=d;}
    16             BinNode *getlc(){return lc;}
    17             BinNode *getrc(){return rc;}
    18             char getdata(){return data;}
    19             bool isLeaf(){return lc==NULL&&rc==NULL;}
    20 };    
    21 #endif

    树ADT的声明

    成员变量:根结点

    基本操作:获取树的高度,结点数目,前序/中序/后序遍历,设置根节点的值,撤销整棵树

     1 #ifndef _BINTREE_HPP_
     2 #define _BINTREE_HPP_
     3 #include "BinNode.hpp"
     4 #include <iostream>
     5 using namespace std;
     6 class BinTree{
     7     public:
     8             BinNode * root;
     9             int depth(BinNode*);
    10             int count(BinNode*);
    11             void setroot(BinNode*);
    12             void clear(BinNode*);
    13             void preorder(BinNode*,void(*visit)(BinNode*));
    14             void inorder(BinNode*,void(*visit)(BinNode*));
    15             void postorder(BinNode*,void(*visit)(BinNode*));
    16 };
    17 #endif

    树ADT的实现

    树很多操作都需要用到递归,学会运用递归是实现这些基本操作的必要条件

    而递归可以使用栈来模拟,所以只要理解好了栈就很好理解递归操作了,这里就不赘述了

    前序遍历:根节点->左子树->右子树

    中序遍历:左子树->根节点->右子树

    后序遍历:左子树->右子树->根节点

    这三种遍历实现方法大同小异,不同点就在于访问的先后顺序不同罢了

    简单的描述一下过程(尝试用栈的知识去理解,先进先出):把递归函数看作是一个元素,若要执行某一层的递归函数,则将该函数入栈,如果函数执行过程中碰到终止条件则终止函数进程即弹栈,反复进行直到栈为空,即所有的函数都被执行完

    获取树的高度以及结点的个数也要使用递归,代码的也大同小异

    #include "BinTree.hpp"
    void BinTree::preorder(BinNode* r,void (*visit)(BinNode* c)){
        if(r==NULL)return ;
        visit(r);
        preorder(r->getlc(),visit);
        preorder(r->getrc(),visit);
    }
    void BinTree::inorder(BinNode* r,void (*visit)(BinNode* c)){
        if(r==NULL)return ;
        inorder(r->getlc(),visit);
        visit(r);
        inorder(r->getrc(),visit);
    }
    void BinTree::postorder(BinNode* r,void (*visit)(BinNode* c)){
        if(r==NULL)return ;
        postorder(r->getlc(),visit);
        postorder(r->getrc(),visit);
        visit(r);
    }
    void BinTree::setroot(BinNode* r){
        root=r;
    }
    void BinTree::clear(BinNode*r){
        if(r==NULL)return;
        clear(r->getlc());
        clear(r->getrc());
        delete r;
    }
    int BinTree::depth(BinNode* r){
        int lh=0,rh=0;
        if(r!=NULL)
        {
            lh=depth(r->getlc());
            rh=depth(r->getrc());
            return (lh>rh?lh:rh)+1;
         } 
        else return 0;
    }
    int BinTree::count(BinNode*r){
        if(r==NULL)return 0;
        return (count(r->getlc())+count(r->getrc()))+1;
    }

     demo程序

    此部分首先碰到的问题就是如何构造一个二叉树了,构造二叉树有很多种方法,这里采用前序遍历的方法来实现

     1 #include"BinTree.hpp"
     2 #include"BinTree.cpp"
     3 #include<iostream>
     4 #include<stdio.h>
     5 #include<stdlib.h>
     6 using namespace std;
     7 BinNode* r;
     8 BinTree T;
     9 char s[1000];
    10 int cnt=0;
    11 void visit(BinNode*r);
    12 BinNode * creatTree(char c);
    13 void input();
    14 int main()
    15 {
    16     input();
    17     printf("输出树的深度:");
    18     printf("%d",T.depth(r));
    19     printf("
    ");
    20     printf("输出树的结点个数:"); 
    21     printf("%d",T.count(r));
    22     printf("
    ");
    23     printf("按前序遍历输出结果
    ");
    24     T.preorder(r,visit);
    25     printf("
    ");
    26     printf("按中序遍历输出结果
    ");
    27     T.inorder(r,visit);
    28     printf("
    ");
    29     printf("按后序遍历输出结果
    ");
    30     T.postorder(r,visit);
    31     printf("
    ");
    32     return 0;
    33 }
    34 void visit(BinNode*r){
    35     printf("%c",r->getdata());
    36 }
    37 BinNode * creatTree(char c){
    38     BinNode* temp;
    39     if(c=='/') temp=NULL;
    40     else
    41     {
    42         temp=new BinNode;
    43         temp->setdata(c);
    44         c=s[++cnt];
    45         temp->setLeftChild(creatTree(c));
    46         c=s[++cnt];
    47         temp->setRightChild(creatTree(c));
    48     }
    49     T.setroot(temp);
    50     return temp; 
    51 }
    52 void input(){
    53     printf("输入的注意事项
    ");
    54     printf("(1)使用前序遍历的顺序输入
    ");
    55     printf("(2)空节点以'/'替代
    ");
    56     printf("(3)输入只有一行
    ");
    57     printf("(4)输入的数据类型都为char
    ");
    58     printf("(5)输入样例:AB/D//CEG///FH//I//
    
    ");
    59     printf("请输入二叉树
    "); 
    60     scanf("%s",s);
    61     r=creatTree(s[0]);
    62 }

    左子节点右兄弟节点

    树节点ADT

    成员变量:节点存储的数据,左子节点的指向,父节点的指向,右兄弟节点的指向

    成员函数:跟二叉链表很相似,都包括构造函数,获取,设置函数,但是少了判断是否为叶子节点的函数,因为仅仅根据以上已知的东西无法判断是否为叶子节点

     1 #ifndef _BINNODE_HPP_
     2 #define _BINNODE_HPP_
     3 #include <iostream>
     4 using namespace std;
     5 class BinNode{
     6     private:
     7         char data;
     8         int parent;
     9         int lc;
    10         int rightbro;
    11     public:
    12         BinNode(){data='/';parent=-1;lc=-1;rightbro=-1;}
    13         void setdata(char d){data=d;}
    14         void setparent(int p){parent=p;}
    15         void setLc(int l){lc=l;}
    16         void setRightbro(int r){rightbro=r;}
    17         char getData(){return data;}
    18         int getParent(){return parent;}
    19         int getLc(){return lc;}
    20         int getRightbro(){return rightbro;}
    21 };
    22 #endif

    树ADT的声明

    与二叉链表大同小异,只是实现的方法不同罢了,这里不多加赘述了

     1 #ifndef _BINTREE_HPP_
     2 #define _BINTREE_HPP_
     3 #include "BinNode.hpp"
     4 #include <iostream>
     5 using namespace std;
     6 class BinTree{
     7     public:
     8         BinNode node[1024+10];
     9         int depth(int );
    10         int count(int );
    11         void preorder(int ,void(*visit)(BinNode no));
    12         void inorder(int ,void(*visit)(BinNode no));
    13         void postorder(int ,void(*visit)(BinNode no));
    14 };
    15 #endif

    树ADT的实现

    这里注意一个问题:

    遍历操作的终止条件多了一项,因为左子节点右兄弟节点使用数组来实现的,所以数组的下标有很大的作用,稍不注意就可能越界

     1 #include "BinTree.hpp"
     2 void BinTree::preorder(int n,void(*visit)(BinNode no)){
     3     if(node[n].getData()=='/'||n==-1)return;
     4     visit(node[n]);
     5     preorder(node[n].getLc(),visit);
     6     preorder(node[node[n].getLc()].getRightbro(),visit);
     7 }
     8 void BinTree::inorder(int n,void(*visit)(BinNode no)){
     9     if(node[n].getData()=='/'||n==-1)return;    
    10     inorder(node[n].getLc(),visit);
    11     visit(node[n]);
    12     inorder(node[node[n].getLc()].getRightbro(),visit);
    13 }
    14 void BinTree::postorder(int n,void(*visit)(BinNode no)){
    15     if(node[n].getData()=='/'||n==-1)return;    
    16     postorder(node[n].getLc(),visit);
    17     postorder(node[node[n].getLc()].getRightbro(),visit);
    18     visit(node[n]);
    19 }
    20 int BinTree::count(int n){
    21     if(node[n].getData()=='/'||n==-1)return 0;
    22     return count(node[n].getLc())+count(node[node[n].getLc()].getRightbro())+1;
    23 }
    24 int BinTree::depth(int n){
    25     if(node[n].getData()=='/'||n==-1)return 0;
    26     int lh=depth(node[n].getLc());
    27     int rh=depth(node[node[n].getLc()].getRightbro());
    28     return (lh>rh?lh:rh)+1;
    29 }

    demo程序

    (1)在构造一颗二叉树时使用的是按层次遍历的顺序,使用其他的顺序都不好构造

    (2)在构造函数的时候,注意可以利用二叉树的性质,比如左节点的下标一定是奇数,左子节点的下标与父节点的下标之间的关系,兄弟节点之间下标之间的关系

    弄清楚这些后就很容易的按照层次遍历的顺序构造好一颗二叉树

    我比较懒,这里就没有考虑父节点的指向了

     1 #include "BinTree.hpp"
     2 #include "BinTree.cpp"
     3 #include<iostream>
     4 #include<stdio.h>
     5 #include<stdlib.h>
     6 #include<cstring>
     7 using namespace std;
     8 char s[1000];
     9 int cnt=0;
    10 BinTree T;
    11 int n=0,m=0;
    12 void visit(BinNode n){
    13     printf("%c",n.getData());
    14 }
    15 void creatTree(BinTree &t){
    16     for(int i=0;i<=1024;i++){
    17         t.node[i].setdata('/');
    18     }
    19     for(int i=0;s[i]!='';i++){
    20         t.node[i].setdata(s[i]);
    21         if(s[i]=='/')continue;
    22         t.node[i].setLc((2*i)+1);
    23         if((i+1)%2==0&&i!=0)t.node[i].setRightbro(i+1);
    24     }
    25 }
    26 void input(){
    27     printf("输入的注意事项
    ");
    28     printf("(1)使用层次遍历的顺序输入
    ");
    29     printf("(2)空节点以'/'替代
    ");
    30     printf("(3)输入只有一行
    ");
    31     printf("(4)输入的数据类型都为char
    ");
    32     printf("(5)输入的树的结点要么是叶子结点要么必有左子结点
    ");
    33     printf("(7)输入样例ABCD/E/FG//HI//
    
    ");
    34     printf("请输入二叉树
    "); 
    35     scanf("%s",s);
    36     creatTree(T);
    37 }
    38 int main()
    39 {
    40         input();
    41         printf("输出树的深度:");
    42         printf("%d",T.depth(0));
    43         printf("
    ");
    44         printf("输出树的结点个数:"); 
    45         printf("%d",T.count(0));
    46         printf("
    ");
    47         printf("按前序遍历输出结果
    ");
    48         T.preorder(0,visit);
    49         printf("
    ");
    50         printf("按中序遍历输出结果
    ");
    51         T.inorder(0,visit);
    52         printf("
    ");
    53         printf("按后序遍历输出结果
    ");
    54         T.postorder(0,visit);
    55         printf("
    ");
    56         return 0;
    57 }
  • 相关阅读:
    python不同包之间调用时提示文件模块不存在的问题
    adb shell 查看内存信息
    adb shell top 使用
    Android读取logcat信息
    父类的引用对象指向子类的对象
    我的阿里梦——淘宝前端必备技能
    我也做了一个1/4圆形菜单
    可编辑tab选项卡
    canvas 之
    canvas之----浮动小球
  • 原文地址:https://www.cnblogs.com/bo2000/p/9955876.html
Copyright © 2011-2022 走看看