基於左子結點/右兄弟結點表示法和二叉鏈表來實現二叉樹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("\n");
20     printf("輸出樹的結點個數:"); 
21     printf("%d",T.count(r));
22     printf("\n");
23     printf("按前序遍歷輸出結果\n");
24     T.preorder(r,visit);
25     printf("\n");
26     printf("按中序遍歷輸出結果\n");
27     T.inorder(r,visit);
28     printf("\n");
29     printf("按后序遍歷輸出結果\n");
30     T.postorder(r,visit);
31     printf("\n");
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("輸入的注意事項\n");
54     printf("(1)使用前序遍歷的順序輸入\n");
55     printf("(2)空節點以'/'替代\n");
56     printf("(3)輸入只有一行\n");
57     printf("(4)輸入的數據類型都為char\n");
58     printf("(5)輸入樣例:AB/D//CEG///FH//I//\n\n");
59     printf("請輸入二叉樹\n"); 
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]!='\0';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("輸入的注意事項\n");
28     printf("(1)使用層次遍歷的順序輸入\n");
29     printf("(2)空節點以'/'替代\n");
30     printf("(3)輸入只有一行\n");
31     printf("(4)輸入的數據類型都為char\n");
32     printf("(5)輸入的樹的結點要么是葉子結點要么必有左子結點\n");
33     printf("(7)輸入樣例ABCD/E/FG//HI//\n\n");
34     printf("請輸入二叉樹\n"); 
35     scanf("%s",s);
36     creatTree(T);
37 }
38 int main()
39 {
40         input();
41         printf("輸出樹的深度:");
42         printf("%d",T.depth(0));
43         printf("\n");
44         printf("輸出樹的結點個數:"); 
45         printf("%d",T.count(0));
46         printf("\n");
47         printf("按前序遍歷輸出結果\n");
48         T.preorder(0,visit);
49         printf("\n");
50         printf("按中序遍歷輸出結果\n");
51         T.inorder(0,visit);
52         printf("\n");
53         printf("按后序遍歷輸出結果\n");
54         T.postorder(0,visit);
55         printf("\n");
56         return 0;
57 }

 


免責聲明!

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



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