1、二叉樹的定義和初始化
//二叉樹節點定義 typedef struct BinTreeNode{ ElemType data; struct BinTreeNode* leftChild; struct BinTreeNode* rightChild; }BinTreeNode; //二叉樹定義 typedef struct BinTree{ BinTreeNode* root; ElemType refvalue; //結束標記 }BinTree; //初始化二叉樹,並規定結束標記為 # void initBinTree(BinTree* tree,ElemType ref){ tree->root = NULL; tree->refvalue = ref; }
2、二叉樹的建立方式
// 建立二叉樹方式1 [node 是二級指標 C++可以透過BinTreeNode*& node引用的簡便寫法] void createBinTree_1(BinTree* bt,BinTreeNode** node){ ElemType item; scanf("%c",&item); if(item == bt->refvalue) *node = NULL; else{ (*node) = (BinTreeNode*) malloc(sizeof(BinTreeNode)); assert(*node != NULL); //建立根 (*node)->data = item; //遞迴建立 createBinTree_1(bt,&(*node)->leftChild); createBinTree_1(bt,&(*node)->rightChild); } } //建立二叉樹方式2 透過返回根節點建立二叉樹 BinTreeNode* createBinTree_2(BinTree* bt){ ElemType item; scanf("%c",&item); if(item == bt->refvalue) return NULL; else{ BinTreeNode* node = (BinTreeNode*) malloc(sizeof(BinTreeNode)); assert(node != NULL); node->data = item; node->leftChild = createBinTree_2(bt); node->rightChild = createBinTree_2(bt); return node; } } //建立二叉樹方式3 根據字串str建立二叉樹 //此處是錯誤程式碼,原因:char* str // 1.createBinTree_3(bt,&(*node)->leftChild,++str); // 2.createBinTree_3(bt,&(*node)->rightChild,++str); // 在執行這兩行程式碼時,如果 在執行1時又遞迴呼叫了 1 , // str不會進行改變,也就說不會"+2",在回來執行2時還是+1的狀態 // 所以此處不應該char* 想要改變一級指標的值就需要二級指標 //void createBinTree_3(BinTree* bt,BinTreeNode** node,char* str){ // if(*str == bt->refvalue){ // *node = NULL; // ++str; // } else { // *node = (BinTreeNode*) malloc(sizeof(BinTreeNode)); // assert(node != NULL); // (*node)->data = *str; // //遞迴建立 // str++ // createBinTree_3(bt,&(*node)->leftChild,str); // createBinTree_3(bt,&(*node)->rightChild,str); // } //} //改進 ABC##DE##F##G#H## void createBinTree_3(BinTree* bt,BinTreeNode** node,char** str){ if(**str == bt->refvalue){ ++(*str); *node = NULL; } else { *node = (BinTreeNode*) malloc(sizeof(BinTreeNode)); assert(node != NULL); (*node)->data = **str; //遞迴建立 ++(*str); createBinTree_3(bt,&(*node)->leftChild,str); createBinTree_3(bt,&(*node)->rightChild,str); } }
3、二叉樹遍歷
3.1、遞迴方式
//先序遍歷 void preOrder(BinTreeNode* node){ if(node != NULL){ printf("%c ",node->data); preOrder(node->leftChild); preOrder(node->rightChild); } } //中序遍歷 void inOrder(BinTreeNode* node){ if(node != NULL){ inOrder(node->leftChild); printf("%c ",node->data); inOrder(node->rightChild); } } //後序遍歷 void postOrder(BinTreeNode* node){ if(node != NULL){ postOrder(node->leftChild); postOrder(node->rightChild); printf("%c ",node->data); } }
3.2、非遞迴方式
//先序遍歷-不採用遞迴 void preOrder(BinTreeNode* node){ if(node != NULL){ SeqStack st; InitStack(&st); BinTreeNode* p; //根節點入棧 push(&st,node); while(!isEmpty(&st)){ //當棧不為空 //獲取棧頂 元素 GetTop(&st,&p); //出棧 Pop(&st); //訪問元素 printf("%c ",p->data); if(p->rightChild != NULL) //先將右節點入棧 push(&st,p->rightChild); if(p->leftChild != NULL) //在將左節點入棧 push(&st,p->leftChild); } } } // 中序遍歷 void inOrder(BinTreeNode* node){ if(node != NULL){ SeqStack st; InitStack(&st); BinTreeNode* p; //根節點入棧 push(&st,node); while(! isEmpty(&st)){ //將當前節點的左子樹入棧 while(node != NULL && node->leftChild != NULL){ Push(&st,node->leftChild); node = node->leftChild; } //當訪問該節點的所有左子樹時 GetTop(&st,&p); Pop(&st); printf("%c ",p->data); //訪問完該節點的所有左子樹,將該節點的右子樹入棧 if(p->rightChild != NULL){ node = p->rightChild; if(node != NULL) Push(&st,node); } } } } //後序遍歷-非遞迴 核心思想:將該節點的左右子樹都遍歷完才訪問該元素 //修改結構,增加標記位來記錄該節點從哪邊返回 typedef enum{L,R} Tag; typedef struct StkNode{ BinTreeNode* prt; Tag tag; }StkNode; void postOrder(BinTreeNode* t){ if(t != NULL){ SeqStack st; InitStack(&st); StkNode sn; BinTreeNode* p; do{ while(t != NULL){ sn.prt = t; sn.tag = L; Push(&st,sn); t = t->leftChild; } bool flag = true;//是否繼續訪問的標記 while(flag && !isEmpty(&st)){ GetTop(&st, &sn); Pop(&st); p = sn->prt; switch(sn.tag){ case L: //說明還沒訪問該節點的右子樹 sn->tag = R; Push(&st,sn); flag = false;//第一次右節點,先找該右節點的左子樹 t = p->rightChild; break; case R: //說明訪問過右子樹 printf("%c",p->data); break; } } }while(!isEmpty(&st)); } }
3.3、層次遍歷