二叉樹的遞迴和非遞迴遍歷
阿新 • • 發佈:2019-01-24
二叉樹的遍歷
- 前序遍歷:
遍歷順序:根節點,左子樹,右子樹
遞迴遍歷:訪問根節點,遞迴呼叫再訪問左子樹,右子樹
//前序遍歷
void PrevOrder()
{
_PrevOrder(_root);
cout << endl;
}
void _PrevOrder(Node* root)
{
if (root == NULL)
{
return;
}
cout << root->_data << " ";//根節點
_PrevOrder(root->_leftNode);//左子樹
_PrevOrder(root->_rightNode);//右子樹
}
非遞迴遍歷:壓入根節點的左子樹節點並訪問,取棧頂元素,對其右子樹節點進行壓棧(右子樹節點作為子樹的根節點說不定會有左子樹節點)。
//前序遍歷
void PrevOrder_NonR()
{
Node* cur = _root;
stack<Node*> s;
while (cur || !s.empty())
{
while (cur)
{
cout << cur->_data << " ";
s.push(cur);
cur = cur->_leftNode;
}
Node* top = s.top();
cur = top->_rightNode;
s.pop();
}
cout << endl;
}
- 中序遍歷
遍歷順序:左子樹,根節點,右子樹
遞迴遍歷:遞迴呼叫左子樹並訪問,根節點,再右子樹
//中序遍歷
void InOrder()
{
_InOrder(_root);
cout << endl;
}
void _InOrder(Node* root)
{
if (root == NULL)
{
return;
}
_InOrder(root->_leftNode);//左子樹
cout << root->_data << " ";//根節點
_InOrder(root->_rightNode);//右子樹
}
非遞迴遍歷:
和前序遍歷一樣,建立棧將根節點的左子樹節點壓入,但不訪問。在取棧頂元素的時候對節點進行訪問。
//中序遍歷
void InOrder_NonR()
{
Node* cur = _root;
stack<Node*> s;
while (cur || !s.empty())
{
//壓入根節點的左子樹節點
while (cur)
{
s.push(cur);
cur = cur->_leftNode;
}
//取棧頂元素並進行訪問
Node* top = s.top();
cout << top->_data << " ";
s.pop();
//對右子樹節點進行遍歷
cur = top->_rightNode;
}
cout << endl;
}
- 後序遍歷
遍歷順序:左子樹,右子樹,根節點
遞迴遍歷:
//後序遍歷
void PostOrder()
{
_PostOrder(_root);
cout << endl;
}
void _PostOrder(Node* root)
{
if (root == NULL)
{
return;
}
_PostOrder(root->_leftNode);//左子樹
_PostOrder(root->_rightNode);//右子樹
cout << root->_data << " ";//根節點
}
非遞迴遍歷:
左子樹節點遍歷後不能對直接取棧頂元素進行pop操作,需要對其右子樹節點進行判斷,這裡需要記錄上次訪問的節點prevNode,右子樹節點為空或右子樹節點為上次訪問過的節點,都說明此子樹已經遍歷完成。
//後序遍歷
void PostOrder_NonR()
{
Node* cur = _root;
Node* prevNode = NULL;//記錄上次訪問的節點
stack<Node*> s;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_leftNode;
}
Node* top = s.top();
if (top->_rightNode == NULL || top->_rightNode == prevNode)
{
cout << top->_data << " ";
s.pop();
prevNode = top;
}
else
{
cur = top->_rightNode;
}
}
cout << endl;
}
- 層序遍歷
- 利用佇列先進先出的特點,將根節點壓進佇列,如果此根節點存在左子樹節點和右子樹節點,就將根節點先出佇列,再將左子樹節點和右子樹節點進佇列;
- 此次進入的左右子樹節點也會作為根節點有其對應的左右子樹節點,再進行根節點出佇列,左右子樹節點進佇列操作即可,直至所有節點全被遍歷。
//層序遍歷
void LevelOrder()
{
queue<Node*> q;
if (_root)
{
q.push(_root);
}
while (!q.empty())
{
Node* front = q.front();
cout << front->_data << " ";
q.pop();
if (front->_leftNode)
{
q.push(front->_leftNode);
}
if (front->_rightNode)
{
q.push(front->_rightNode);
}
}
cout << endl;
}