二叉樹遍歷(迴圈和遞迴)
阿新 • • 發佈:2018-11-21
遞迴
1.前序遍歷
void preorder(BinTree *T)
{
if(T==NULL)
return;
cout << T->data;
preorder(T->left);
preorder(T->right);
}
2.中序遍歷
void inoeder(BinTree *T) { if(T == NULL) return; inoeder(T->left); cout << T->data; inoeder(T->right); }
3.後序遍歷
void postorder(BinTree *T)
{
if (T==NULL)
return;
postorder(T->left);
postorder(T->right);
cout << T->data;
}
迴圈
1.前序遍歷 法一
void preorder(BinTree *T) { //空樹,直接返回 if(T==NULL) return; //定義一個存放二叉樹節點的棧結構 stack<BinTree*>s; BinTree *pcur; pcur = T; //迴圈遍歷二叉樹直到根節點為空或者棧為空 while (pcur || !s.empty()) { if (pcur) { cout << pcur->data; s.push(pcur); pcur = pcur->left; }else { //當根節點為空時,說明左子樹已遍歷完,通過取出棧頂結點,來訪問根節點的右子樹 pcur = s.top(); s.pop(); pcur = pcur->right; } } }
法二(自己)
void preOrder(binTree * root) { if(root==NULL) return; stack<binTree*> stackTree; binTree* curTree; stackTree.push(root); while(!stackTree.empty()) { curTree=stackTree.top(); stackTree.pop(); cout<<curTree->value; if(curTree->right!=NULL) stackTree.push(curTree->right); if(curTree->left!=NULL) stackTree.push(curTree->left); } }
2.中序遍歷
void inorder(BinTree *T)
{
if(T == NULL)
return;
stack<BinTree*>s;
BinTree *pcur;
pcur = T;
while (pcur || !s.empty())
{
if (pcur)
{
//根節點非空,入棧,繼續遍歷左子樹直到根節點為空
s.push(pcur);
pcur = pcur->left;
}else
{
//根節點為空,說明左子樹已經遍歷完,彈出根節點列印,通過根節點訪問右子樹
pcur = s.top();
s.pop();
cout << pcur->data;
pcur = pcur->right;
}
}
}
3.後序遍歷
法一,會改變原來的內容
void postorder2(BinTree *T)
{
if(T == NULL)
return;
stack<BinTree*>s;
s.push(T);
BinTree *pcur;
pcur = NULL;
while (!s.empty())
{
pcur = s.top();
if (pcur->left == NULL && pcur->right == NULL)
{
cout << pcur->data;
s.pop();
}else
{
//注意右孩子先入棧左孩子後入棧,這樣再次迴圈時左孩子節點才先出棧
if(pcur->right)
{
s.push(pcur->right);
pcur->right = NULL;
}
if (pcur->left)
{
s.push(pcur->left);
pcur->left = NULL;
}
}
}
}
法二,不用輔助棧,不改變內容
void PostOrderWithoutRecursion(BTNode* root)
{
if (root == NULL)
return;
stack<btnode*> s;
//pCur:當前訪問節點,pLastVisit:上次訪問節點
BTNode* pCur, *pLastVisit;
pCur = root;
pLastVisit = NULL;
//先把pCur移動到左子樹最下邊
while (pCur)
{
s.push(pCur);
pCur = pCur->lchild;
}
while (!s.empty())
{
//走到這裡,pCur都是空,並已經遍歷到左子樹底端(看成擴充二叉樹,則空,亦是某棵樹的左孩子)
pCur = s.top();
s.pop();
//一個根節點被訪問的前提是:無右子樹或右子樹已被訪問過
if (pCur->rchild == NULL || pCur->rchild == pLastVisit)
{
cout << pCur->data;
//修改最近被訪問的節點
pLastVisit = pCur;
}
/*這裡的else語句可換成帶條件的else if:
else if (pCur->lchild == pLastVisit)//若左子樹剛被訪問過,則需先進入右子樹(根節點需再次入棧)
因為:上面的條件沒通過就一定是下面的條件滿足。仔細想想!
*/
else
{
//根節點再次入棧
s.push(pCur);
//進入右子樹,且可肯定右子樹一定不為空
pCur = pCur->rchild;
while (pCur)
{
s.push(pCur);
pCur = pCur->lchild;
}
}
}
cout << endl;
}
法三。不用輔助棧,不改變內容,推薦
void beh_traverse(BTree pTree)
{
PSTACK stack = create_stack(); //建立一個空棧
BTree node_pop; //用來儲存出棧的節點
BTree pCur; //定義指標,指向當前節點
BTree pPre = NULL; //定義指標,指向上一各訪問的節點
//先將樹的根節點入棧
push_stack(stack,pTree);
//直到棧空時,結束迴圈
while(!is_empty(stack))
{
pCur = getTop(stack); //當前節點置為棧頂節點
if((pCur->pLchild==NULL && pCur->pRchild==NULL) ||
(pPre!=NULL && (pCur->pLchild==pPre || pCur->pRchild==pPre)))
{
//如果當前節點沒有左右孩子,或者有左孩子或有孩子,但已經被訪問輸出,
//則直接輸出該節點,將其出棧,將其設為上一個訪問的節點
printf("%c ", pCur->data);
pop_stack(stack,&node_pop);
pPre = pCur;
}
else
{
//如果不滿足上面兩種情況,則將其右孩子左孩子依次入棧
if(pCur->pRchild != NULL)
push_stack(stack,pCur->pRchild);
if(pCur->pLchild != NULL)
push_stack(stack,pCur->pLchild);
}
}
}
4.層次遍歷
void leveltraversal(BinTree *T)
{
queue<BinTree*> s;
s.push(T);
BinTree* pcur;
while (!s.empty())
{
pcur=s.front();
cout<<pcur->data;
s.pop();
if (pcur->left)
{
s.push(pcur->left);
}
if (pcur->right)
{
s.push(pcur->right);
}
}
}
分層遍歷二叉樹,即從上到下按層次訪問該樹,每一層單獨輸出一行
void leveltraversal3(BinTree *T)
{
if(T == NULL)
return;
queue<BinTree*>s;
s.push(T);
BinTree *pcur,*last,*nlast;
last = T;
nlast = NULL;
while (!s.empty())
{
pcur = s.front();
cout << pcur->data;
s.pop();
if (pcur->left)
{
s.push(pcur->left);
nlast = pcur->left;
}
if (pcur->right)
{
s.push(pcur->right);
nlast = pcur->right;
}
if (last == pcur)
{
cout << endl;
last = nlast;
}
}
}