tbwshc

          二叉樹三種非遞歸遍歷的區(qū)別

          1 #include <iostream>
            2
            3 #define MAXN  100
            4 using namespace stbd;
            5
            6
            7 struct BTNode
            8 {
            9     char tag;
          10     BTNode *left;
          11     BTNode *right;
          12 };
          13
          14 class BTree
          15 {
          16 private:
          17     BTNode **root;
          18     void BuildBTree(BTNode **root);
          19
          20 public:
          21     /*遞歸版本*/
          22     void PreVisit(BTNode *root);
          23     void InVisit(BTNode *root);
          24     void PostVisit(BTNode *root);
          25
          26     /*非遞歸版本*/
          27     void NR_PreVisit(BTNode *root);
          28     void NR_InVisit(BTNode *root);
          29     void NR_PostVisit(BTNode *root);
          30
          31     BTree(BTNode **r);
          32     BTree();
          33 };
          34
          35 BTree::BTree()
          36 {
          37
          38 }
          39
          40 BTree::BTree(BTNode **r)
          41 {
          42     root = r;
          43     /*
          44 *root = new BTNode; 45     (*root)->left = NULL;
          46 (*root)->right = NULL; 47     */
          48     BuildBTree(root);
          49 }
          50
          51 /*先序方式插入結(jié)點(diǎn)*/
          52 void BTree::BuildBTree(BTNode **root)
          53 {
          54     char c;
          55    
          56     c = getchar();
          57     if(c == '#')
          58         *root=NULL;
          59     else{
          60         *root = new BTNode;
          61         (*root)->tag = c;
          62         BuildBTree(&(*root)->left);
          63         BuildBTree(&(*root)->right);
          64     }
          65 }
          66
          67 void BTree::PreVisit(BTNode *root)
          68 {
          69     if(root!=NULL)
          70     {
          71         printf("%c ", root->tag );
          72         PreVisit(root->left);
          73         PreVisit(root->right);
          74     }
          75 }
          76
          77 void BTree::InVisit(BTNode *root)
          78 {
          79     if(root!=NULL)
          80     {
          81         InVisit(root->left);
          82         printf("%c ", root->tag );
          83         InVisit(root->right);
          84     }
          85 }
          86
          87 void BTree::PostVisit(BTNode *root)
          88 {
          89     if(root!=NULL)
          90     {
          91         PostVisit(root->left);
          92         PostVisit(root->right);
          93         printf("%c ", root->tag );
          94     }
          95 }
          96
          97 void BTree::NR_PreVisit(BTNode *root)
          98 {
          99     BTNode *s[MAXN];
          100     int top=0;
          101
          102     while(top!=0 || root!=NULL)
          103     {
          104         while(root!=NULL)
          105         {
          106             s[top] = root;
          107             printf("%c ", s[top++]->tag);
          108             root = root->left;
          109         }
          110         if(top>0)
          111         {
          112             root = s[--top];
          113             root = root->right;
          114         }
          115     }
          116 }
          117
          118 void BTree::NR_InVisit(BTNode *root)
          119 {
          120     BTNode *s[MAXN];
          121     int top=0;
          122    
          123     while(top!=0 || root!=NULL)
          124     {
          125         while(root!=NULL)
          126         {
          127             s[top++]=root;
          128             root = root->left;
          129         }
          130         if(top>0)
          131         {
          132             root = s[--top];
          133             printf("%c ", root->tag);
          134             root = root->right;
          135         }
          136     }
          137 }
          138
          139 void BTree::NR_PostVisit(BTNode *root)
          140 {
          141     BTNode *s[MAXN], *tmp=NULL;
          142     int top=0;
          143
          144     while(top!=0 || root!=NULL)
          145     {
          146         while(root!=NULL)
          147         {
          148             s[top++]=root;
          149             root=root->left;
          150         }
          151         if(top>0)
          152         {
          153             root = s[--top];
          154
          155             /*右孩子不存在或者已經(jīng)訪問過,root出棧并訪問*/
          156             if( (root->right == NULL) || (root->right == tmp) ) 
          157             {
          158                 printf("%c ", root->tag);
          159                 tmp = root;        //保存root指針
          160                 root=NULL;         //當(dāng)前指針置空,防止再次入棧
          161             }
          162
          163             /*不出棧,繼續(xù)訪問右孩子*/
          164             else
          165             {
          166                 top++;             //與root=s[--top]保持平衡
          167                 root = root->right;
          168             }
          169         }
          170     }
          171 }
          172
          173 int main()
          174 {
          175     BTNode *root=NULL;
          176     BTree bt(&root);  //頭指針的地址
          177    
          178     bt.NR_PreVisit(root);
          179     printf("\n");
          180     bt.NR_InVisit(root);
          181     printf("\n");
          182     bt.NR_PostVisit(root);
          183     printf("\n");
          184     return 0;
          185 }
          復(fù)制代碼

          先上代碼,tb帶NR(Non-recursive)的表示非遞歸遍歷。

           

          測(cè)試數(shù)據(jù):

          124#8##5##369###7##

           

          表示的二叉樹:

          用windows自帶的畫圖畫的,的確是粗糙了點(diǎn)。。。

           

          測(cè)試結(jié)果:

          1 2 4 8 5 3 6 9 7
          4 8 2 5 1 9 6 3 7
          8 4 5 2 9 6 7 3 1

           

           

          一、關(guān)于二叉樹的建立

           

            首先要注意二叉樹的創(chuàng)建過程,這里用的是先序方式遞歸插入結(jié)點(diǎn),所以輸入數(shù)據(jù)的時(shí)候,必須按照先序方式輸入,

          左結(jié)點(diǎn)或右結(jié)點(diǎn)為空的,用#表示。否則,輸入不會(huì)有響應(yīng),因?yàn)檫f歸過程還未結(jié)束,按CTRL+Z也沒用。當(dāng)然可以用其

          他方式插入(如中序遞歸插入,后序遞歸插入等)。

           

          二、三種非遞歸遍歷的區(qū)別

           

            前序、中序和后序的遞歸遍歷方式比較簡單,這里就不講了。而非遞歸的遍歷方式,只需要用數(shù)組存儲(chǔ)結(jié)點(diǎn)指針,模擬系統(tǒng)棧的工作機(jī)制就可以了。

          先說先序非遞歸遍歷,按照根-左-右的方式訪問的話,需要將當(dāng)前結(jié)點(diǎn)壓棧(同時(shí)打印當(dāng)前結(jié)點(diǎn)信息),直到左子樹為空(內(nèi)層while);然后出棧,訪問

          右結(jié)點(diǎn);后面的操作就跟前面的一樣了(外層while)。

            對(duì)于中序非遞歸遍歷,可以看到代碼結(jié)構(gòu)幾乎一模一樣,只是打印結(jié)點(diǎn)信息的位置不同而已。這是因?yàn)橹行虮闅v是左-根-右,這樣前序和中序非

          遞歸遍歷(根-左和左-根都是壓棧動(dòng)作,且出棧動(dòng)作的對(duì)象都是父節(jié)點(diǎn))是一致的。

           

            對(duì)于后序非遞歸遍歷,因?yàn)楹笮虮闅v是左-右-根,根的訪問是在右孩子之后,而這意味著兩種情況:

            1、右孩子不為空(繼續(xù)訪問右孩子);

            2、右孩子為空,從左孩子返回,則需要訪問根結(jié)點(diǎn)。

            為了區(qū)分這兩種情況(物理形式上從左孩子返回,還是從右孩子返回來訪問根節(jié)點(diǎn)),對(duì)于右孩子的訪問又需要判斷根結(jié)點(diǎn)的右孩子是否為空或者已

          訪問過(右子樹已遍歷過)。除這兩種情況外,都不應(yīng)該訪問根節(jié)點(diǎn),而是要繼續(xù)進(jìn)入右子樹。

            

          三、補(bǔ)充說明

           

            在后序非遞歸遍歷的else語句中top++純粹是為了使棧保持平衡,因?yàn)閷?duì)于2)繼續(xù)訪問右孩子這種情況,不需要出棧,而前面的root[--top]包含

          出棧操作,以此保證棧的正確性(當(dāng)然可以有其他的處理,這里也是考慮到三種非遞歸遍歷方式的統(tǒng)一性)。

            兩個(gè)while不會(huì)提高程序的時(shí)間復(fù)雜度,因?yàn)槎鏄涞慕Y(jié)點(diǎn)個(gè)數(shù)是固定的,內(nèi)層while是為了提高算法的邏輯性。

           

          四、遞歸->非遞歸

           

            另外,今天實(shí)習(xí)看到一個(gè)老師寫的非遞歸代碼,非常棒,贊一個(gè)!他僅僅是將程序的返回地址和函數(shù)的形參、局部變量都保存起來,然后在退出時(shí)

          還原現(xiàn)場(chǎng);同樣是非遞歸,但是這種方式更接近編譯器的處理方式,同操作系統(tǒng)的任務(wù)切換也比較一致;所以這種處理方法為遞歸自動(dòng)轉(zhuǎn)換為非遞歸奠

          定了基礎(chǔ)。

            分享一下他當(dāng)場(chǎng)編寫的非遞歸的漢諾塔:

           

          復(fù)制代碼
            1 #include <stdio.h>
            2 #include <iostream>
            3 
            4 using namespace std ;
            5 
            6 #define  MAXSIZE  1000 
            7 
            8 struct SNode
            9 {
           10     int  n;
           11     char from ;
           12     char to;
           13     char aux ;
           14     int  label ;
           15 } ;
           16 
           17 struct STK
           18 {
           19     
           20     SNode  stack[MAXSIZE] ;
           21     int sp  ;
           22     STK()
           23     {
           24         sp = 0 ;
           25     };
           26     void push (int n,char from,char to,char aux, int label )
           27     {
           28         if ( sp>= MAXSIZE )
           29         {
           30             printf ( "STK is full!\n" ) ;
           31         }
           32         stack[sp].n = n ;
           33         stack[sp].from = from ;
           34         stack[sp].to = to ;
           35         stack[sp].aux = aux ;
           36         stack[sp++].label = label ;
           37     };
           38     SNode POP()
           39     {
           40         if ( sp <=0 )
           41         {
           42             printf ( "STK is empty!\n" ) ;
           43         }
           44         return stack[--sp] ;
           45     };
           46 } ;
           47 
           48 void move(int n,char from,char to,char aux)
           49 {
           50     if(n==1)
           51     {
           52         cout<<"將#1盤從"<<from<<"移到"<<to<<endl;
           53 }
           54     else
           55     {
           56          move(n-1,from,aux,to);
           57          cout<<"將#"<<n<<"盤從"<<from<<"移到"<<to<<endl;
           58          move(n-1,aux,to,from);
           59 }
           60 }
           61 
           62 
           63 void move_stk(int n,char from,char to,char aux)
           64 {
           65     STK stk ;
           66     char tmp;
           67 S1:
           68     if(n==1)
           69     {
           70         cout<<"將#1盤從"<<from<<"移到"<<to<<endl;
           71     }
           72     else
           73    {
           74     stk.push (n,from,to,aux,2 ) ;
           75     n = n-1 ;
           76     tmp = to ;
           77     to = aux ;  
           78     aux = tmp ;
           79     goto S1;
           80          // move(n-1,from,aux,to);
           81 S2:
           82          cout<<"將#"<<n<<"盤從"<<from<<"移到"<<to<<endl;
           83 
           84     stk.push (n,from,to,aux,3 ) ;
           85     n = n-1 ;
           86     tmp = from ;
           87     from = aux ;  
           88     aux = tmp ;
           89     goto S1;
           90          // move(n-1,aux,to,from);
           91 }
           92 S3:
           93     if ( stk.sp > 0 )
           94     {
           95         SNode sn = stk.POP() ;
           96         n = sn.n ;
           97         from = sn.from;
           98         to = sn.to ;
           99         aux = sn.aux ;
          100         if  ( 1 == sn.label  )
          101             goto S1;
          102         else if ( 2 == sn.label )
          103             goto S2;
          104         else 
          105             goto S3;        
          106     }
          107 }
          108 
          109 
          110 
          111 int main(int argc, char * argv[])
          112 {
          113     move ( 3,'A','B', 'C' );
          114     printf ( "================================\n" ) ;
          115     move_stk ( 3,'A','B', 'C' );
          116 
          117     return 0;
          118 }

          posted on 2012-07-06 15:45 chen11-1 閱讀(2099) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 威信县| 东平县| 武宁县| 卢龙县| 安乡县| 唐河县| 图片| 德清县| 南丹县| 吉林市| 县级市| 彭阳县| 乌拉特中旗| 海兴县| 抚宁县| 玛曲县| 甘南县| 梨树县| 东乌| 泸州市| 新泰市| 扎鲁特旗| 专栏| 通辽市| 贡嘎县| 崇仁县| 体育| 焦作市| 定南县| 黑水县| 和顺县| 襄城县| 景洪市| 金湖县| 十堰市| 潜江市| 揭东县| 隆化县| 长泰县| 宣城市| 金华市|