二叉樹的深度優先dfs遍歷(前序、中序和後序;遞迴與非遞迴)
阿新 • • 發佈:2019-02-17
總結:所有結點都看作根結點,關鍵在於何時訪問。前序:入棧時訪問;中序:第一次退棧時訪問;後序:第二次退棧時訪問。//前序遍歷 //遞迴實現:根左右 void preOrder1(BinTree *root) { if (root != NULL) { cout<<root->data<<endl; preOrder1(root->lchild); preOrder1(root->rchild); } } //非遞迴實現 /*注意,如前所述,我們將二叉樹的每一個結點都看作根結點。因此,從整個二叉樹的根結點root出發,一路向左,遇到的每一個結點都立即訪問(它是根,同時也是其父親的左子樹的根,所以這個過程訪問了“根和左”)併入棧,直到不能再左,轉向右(這個“右”上哪找呢?當然是父親的右兒子。父親去哪裡找呢?當然是棧裡),將這個右兒子當成新的根結點重複上述過程,直到棧為空且當前根結點也為空。*/ void preOrder2(BinTree *root) { stack<BinTree *> s; BinTree *p=root; while (p!=NULL || !s.empty()) { //一路向左 while (p!=NULL) { cout<<p->data<<endl; //訪問根結點 s.push(p); p=p->lchild; } //當不能再左時,開始向右 if (!s.empty()) { p=s.top();//從棧裡面取出根結點 s.pop(); p=p->rchild; //作為新的根結點 } } } //中序遍歷 //遞迴實現:左根右 void inOrder1(BinTree *root) { if (root != NULL) { inOrder1(root->lchild); cout<<root->data<<endl; inOrder1(root->rchild); } } //中序遍歷 //非遞迴實現 /*與前序遍歷類似,但是,根結點進棧時不訪問(否則就成了前序遍歷),根結點彈棧時才訪問(左根右)。*/ void inOrder2(BinTree *root) { stack<BinTree *> s; BinTree *p=root; while (p!=NULL || !s.empty()) { //一路向左 while (p!=NULL) { s.push(p); p=p->lchild; } //當不能再左時,訪問根結點,向右 if (!s.empty()) { p=s.top(); cout<<p->data<<endl; //在中間訪問根結點 s.pop(); p=p->rchild; } } } //後序遍歷 //遞迴實現:左右根 void postOrder1(BinTree *root) { if (root != NULL) { postOrder1(root->lchild); postOrder1(root->rchild); cout<<p->data<<endl; } } //順便說一句,刪除一棵二叉樹,即釋放一棵二叉樹的記憶體,用後續遍歷即可實現(這裡的“訪問”變成了delete 結點)。 //後序遍歷 //非遞迴實現 /*對任一結點p,邊一路向左邊進棧,直到其左兒子為空,這時,各個根結點在棧裡存放。然後依次出棧,但是此時還不能訪問(否則就是中序遍歷了),出棧之後以當前根節點的右兒子設定為新的根節點,重複前述過程;直到當前根節點第二次出棧(說明它的左右兒子都已被訪問),然後訪問此根結點(左右根)。*/ typedef struct _poNode { BinTree *btnode; bool isFirst; } poNode; void postOrder2(BinTree *root) { stack<poNode *> s; BinTree *p=root; poNode *temp; while (p!=NULL || !s.empty()) { //一路向左直到不能再左 while (p!=NULL) { temp = (poNode *)malloc(sizeof(poNode)); temp->btnode = p; temp->isFirst = True; //第一次進棧標記 s.push(temp); p=p->lchild; } if (!s.empty()) { temp = s.top(); //此時還不能訪問,否則就是中序遍歷了 s.pop(); //如果是第一次進棧,那還需要再進棧一次,之後以它的右兒子為新的根結點 if (temp->isFirst == true) { temp->isFirst = false; s.push(temp); p = temp->btnode->rchild; } else { cout<<temp->btnode->data<<endl; //後序訪問根結點 p = NULL; //不要忘了這一句,因為訪問過根結點之後應該直接彈棧考察上一個父結點 } } } }