1. 程式人生 > >6.2.2-1 【指標與引用】在二叉樹建立的應用

6.2.2-1 【指標與引用】在二叉樹建立的應用

0 引子

  本文旨在通過二叉樹的遞迴建立,分析指標與引用,函式形參與實參的具體實現。

  二叉樹的遍歷,通常是利用建立好的二叉連結串列的首地址,也即根節點地址。主函式先定義一指標,再通過二叉樹建立函式返回根結點地址,或者將定義的指標作為形參來實現修改。

  這就涉及函式形參與實參的呼叫機制。實參賦給形參過程是複製的過程,而被調函式結束時,內部所有變數所分配的記憶體會被釋放掉。這便是無法直接在同一層上通過形參去改變形參。

1 程式碼實現

(1)被調函式返回給主函式根節點地址

 1 #include<iostream>
 2 #include<cstdlib>
 3
using namespace std; 4 5 typedef char ElemType; 6 7 typedef struct TreeNode{ 8 ElemType val; 9 struct TreeNode *lchild, *rchild; 10 11 }TreeNode, *BiTree; 12 13 /* 14 方法1:通過返回根節點的指標的指標; 15 */ 16 BiTree createBiTree1(){ 17 18 ElemType ch; 19 cin >> ch; 20 21
BiTree T; 22 if(ch == '#') { 23 T=NULL; 24 cout << "空結點,地址為 " << T << endl; 25 } 26 else{ 27 static int a = 1; 28 T = (BiTree) malloc(sizeof(TreeNode)); 29 cout <<""<< a++ <<""<< "初始化結點地址:" << T << endl;
30 31 T->val = ch; 32 cout << "value succeed! It's: "<< ch << endl; 33 34 T->lchild = createBiTree1(); 35 T->rchild = createBiTree1(); 36 } 37 38 return T; //?返回T的地址 39 } 40 41 //先序遍歷 42 void preOrderTraversal(BiTree T){ 43 44 if(T){ 45 cout<< T->val << " "; 46 preOrderTraversal(T->lchild); 47 preOrderTraversal(T->rchild); 48 } 49 } 50 51 //中序 52 void inOrderTraversal(BiTree T){ 53 54 if(T){ 55 preOrderTraversal(T->lchild); 56 cout<< T->val << " "; 57 preOrderTraversal(T->rchild); 58 } 59 } 60 61 //後序 62 void lastOrderTraversal(BiTree T){ 63 64 if(T){ 65 preOrderTraversal(T->lchild); 66 preOrderTraversal(T->rchild); 67 cout << T->val << " "; 68 } 69 } 70 71 72 int main(){ 73 74 BiTree root; 75 cout<<"請輸入:"<<endl; 76 root = createBiTree1();//* 77 78 cout<<"二叉樹建立成功!"<<endl; 79 cout<<endl; 80 81 cout<< "根節點地址:" << root << endl; 82 83 cout<<"先序遍歷結果:"<< endl; 84 preOrderTraversal(root); 85 cout<<endl; 86 87 cout<<"中序遍歷結果:"<< endl; 88 inOrderTraversal(root); 89 cout<<endl; 90 91 cout<<"後序遍歷結果:"<< endl; 92 lastOrderTraversal(root); 93 cout<<endl; 94 95 return 0; 96 }
方法一

執行結果:

從結果可以看出,root地址等於被調函式內第一個結點地址。其內部結點建立也是按照非空再分配儲存空間的邏輯,若為空結點,則不分配。

(2)採用指標作為形參。由於要建立的是指向結構體的指標的值,所以可採用指標的指標。如果只用指標則無法實現修改。

  1 #include<iostream>
  2 #include<cstdlib>
  3 using namespace std;
  4 
  5 typedef char ElemType;
  6 
  7 typedef struct TreeNode{
  8     ElemType val;
  9     struct TreeNode *lchild, *rchild;
 10     
 11 }TreeNode, *BiTree;
 12 
 13 /*
 14 方法2:通過形參傳遞修改指向結構指標的值。
 15 必須要用指標的指標才能實現修改。 
 16 */
 17 
 18 void createBiTree2(BiTree *T){
 19     ElemType ch;
 20     cin >> ch;
 21     if(ch == '#') {
 22         *T=NULL;
 23         cout << "空結點,地址為 " << *T << endl;
 24     }
 25     else{
 26         static int a =1;
 27         *T = (BiTree)malloc(sizeof(TreeNode));
 28         if(!*T)
 29             cout<<"bad_alloc!"<<endl;
 30         cout <<""<< a++ <<""<< "初始化結點地址:" << *T << endl;
 31         
 32         
 33         (*T)->val = ch;
 34         cout << "value succeed! It's: "<< ch << endl;
 35         
 36         createBiTree2(&(*T)->lchild);
 37         createBiTree2(&(*T)->rchild);    
 38         
 39     }
 40 } 
 41 
 42 
 43  
 44 
 45 
 46 //先序遍歷 
 47 void preOrderTraversal(BiTree T){
 48     
 49     if(T){
 50         cout<< T->val << " ";
 51         preOrderTraversal(T->lchild);
 52         preOrderTraversal(T->rchild); 
 53     }    
 54 }
 55 
 56 //中序 
 57 void inOrderTraversal(BiTree T){
 58     
 59     if(T){
 60         preOrderTraversal(T->lchild);        
 61         cout<< T->val << " ";        
 62         preOrderTraversal(T->rchild); 
 63     }    
 64 }
 65 
 66 //後序
 67 void lastOrderTraversal(BiTree T){
 68     
 69     if(T){
 70         preOrderTraversal(T->lchild);        
 71         preOrderTraversal(T->rchild);
 72         cout << T->val << " ";     
 73     }    
 74 }
 75 
 76 
 77     
 78 int main(){
 79     
 80     BiTree *root;
 81     cout<<"請輸入:"<<endl; 
 82     createBiTree2(root); //**
 83     
 84     cout<<"二叉樹建立成功!"<<endl;
 85     cout<<endl; 
 86     
 87     cout<< "根節點地址:" << *root << endl; //*root
 88       
 89     cout<<"先序遍歷結果:"<< endl; 
 90     preOrderTraversal(*root);  //*root,下同。 
 91     cout<<endl; 
 92             
 93     cout<<"中序遍歷結果:"<< endl; 
 94     inOrderTraversal(*root);
 95     cout<<endl; 
 96     
 97     cout<<"後序遍歷結果:"<< endl; 
 98     lastOrderTraversal(*root);
 99     cout<<endl; 
100     
101     return 0;
102 }
方法二

執行結果:

 

若僅採用指標,則無法遍歷。從結果也看出,根節點地址與被調函式第一結點不一樣。根節點地址是在定義時分配的,而被調函式則是在形參複製實參時分配的。兩者不一樣。