遍歷二叉樹-------遞迴&非遞迴
一、什麼是樹?什麼又是二叉樹
(1)樹的定義
樹是一種特殊的資料結構,是由N(N>=0)個節點構成的具有層次關係的集合。每棵樹都有一個特殊的結點,就是根結點,根節點沒有前驅結點;除過根節點的其餘結點被分為若干個互不相交的集合,稱之為子樹;每個子樹的根結點有且僅有一個前驅,可以有0個或者多個後繼
(2)那麼問題來了,什麼是二叉樹嘞?
二叉樹是每個結點最多有兩個子樹的有序樹(它由一個根節點加上它的左右子樹組合起來的)。
* 特點:(1)每個結點最多有兩棵子樹,即二叉樹不存在度大於2的結點(分支數最大不超過2)
(2)二叉樹的子樹有左右之分,其子樹的次序不能被顛倒
* 二叉樹有五種基本形態:(如下圖所示)
(1)空二叉樹
(2)只有一個根節點
(3)只有左子樹
(4)只有右子樹
(5)完全二叉樹
- 滿二叉樹:一棵二叉樹上的所有分支結點都存在左右子樹,並且葉子結點都在同一層上面
- 完全二叉樹:如果一個具有N個結點的二叉樹與之滿二叉樹的前N個結點的結構相同,就是完全二叉樹
二叉樹的四種遍歷
1、前序遍歷(VLR):根節點—>左子樹—>右子樹
【遞迴遍歷】
演算法如下:
判斷二叉樹是否為空,倘若為空,則return;否則:
* (1)先訪問根節點
* (2)然後前序遍歷根節點的左子樹
* (3)最後前序遍歷根節點的右子樹
程式碼實現:
//前序遞迴遍歷
void PreOrder()
{
cout<<"前序遍歷"<<endl;
_PreOrder(_pRoot);
cout<<endl;
}
//前序遞迴: 根---根的左子樹---根的右子樹
void _PreOrder(PNode& pRoot)
{
if(pRoot)
{
cout<< pRoot->_data << "";
_PreOrder(pRoot->_pLeft);
_PreOrder(pRoot->_pRight);
}
}
【非遞迴遍歷】:(藉助棧實現)
演算法如下:
判斷二叉樹是否為空,倘若為空,則return;否則:
(1)初始化一個棧
(2)根節點入棧
(3)當棧不為空時,迴圈執行下列步驟
* 訪問取出棧頂元素
* 倘若該被訪問的節點的左子樹非空時,將該結點左子樹指標入棧
* 倘若該被訪問的節點的右子樹非空時,將該結點右子樹指標入棧
(4)重複執行直至棧為空,return
程式碼實現:
//前序非遞迴
void PreOrder_N()
{
_PreOrder_N(_pRoot);
}
//前序非遞迴
void _PreOrder_N(PNode& pRoot)
{
//判斷樹是否存在
if(NULL == pRoot)
return;
stack<PNode> s;
s.push(pRoot);
while(!s.empty())
{
PNode pTop = s.top();
cout<<pTop->_data<<"";
if(pTop->_pLeft)
s.push(pTop->_pLeft);
if(pTop->_pRight)
s.push(pTop->_pRight);
}
cout<<endl;
}
2、中序遍歷(LVR):左子樹—>根節點—>右子樹
【遞迴遍歷】
演算法如下:
判斷二叉樹是否為空,倘若為空,則return;否則:
* (1)先中序遍歷根節點的左子樹
* (2)訪問根節點
* (3)最後中序遍歷根節點的右子樹
程式碼實現:
//中序遞迴遍歷
void InOrder()
{
cout<<"中序遍歷"<<endl;
_InOrder(_pRoot);
cout<<" "<<endl;
}
//中序遞迴: 左子樹---根節點---右子樹
void _InOrder(PNode pRoot)
{
if(pRoot)
{
_InOrder(pRoot->_pLeft);
cout<< pRoot->_data <<"";
_InOrder(pRoot->_pRight);
}
}
【非遞迴遍歷】
演算法如下:
判斷二叉樹是否為空,倘若為空,則return;否則:
(1)初始化一個棧
(2)給定一個任意節點pCur,倘若pCur的左孩子不為空時,則將其入棧,並將pCur指向pCur的左孩子;(一直迴圈執行,直至左孩子為空)
(3)執行完步驟(2)後,說明最左邊的結點已被找到,訪問輸出棧頂元素,並進行出棧操作
(4)將pCur指向其右孩子
(5)重複2、3、4步驟,直至當前結點為空或者棧為空,return
程式碼實現:
//中序非遞迴
void InOrder_N()
{
_InOrder_N(_pRoot);
}
//中序非遞迴
void _InOrder_N(PNode pRoot)
{
if(NULL == pRoot)
return;
stack<PNode> s;
PNode pCur = pRoot;
while(pCur || !s.empty())
{
while(pCur)
{
s.push(pCur);
pCur = pCur->_pLeft;
}
pCur = s.top();
cout<<pCur->_data<<"";
s.pop();
pCur = pCur->_pRight;
}
}
3、後序遍歷(LRV):左子樹—>右子樹—>根節點
【遞迴遍歷】
演算法如下:
判斷二叉樹是否為空,倘若為空,則return;否則:
* (1)先後序遍歷根節點的左子樹
* (2)後序遍歷根節點的右子樹
* (3)訪問根節點
程式碼實現:
//後序遞迴遍歷
void PostOrder()
{
cout<<"後序遍歷"<<endl;
_PostOrder(_pRoot);
cout<<""<<endl;
}
//後序遞迴: 左子樹---右子樹---根節點
void _PostOrder(PNode pRoot)
{
if(pRoot)
{
_PostOrder(pRoot->_pLeft);
_PostOrder(pRoot->_pRight);
cout<< pRoot->_data <<"";
}
}
【非遞迴遍歷】:出棧順序為左右根,則壓棧順序為根右左
演算法如下:
判斷二叉樹是否為空,倘若為空,則return;否則:
(1)初始化一個棧
(2)給定一個任意節點pCur
(3)將PCur入棧,倘若pCur的左孩子不為空時,將pCur指向pCur的左孩子;(一直迴圈執行,直至左孩子為空)
(4)執行完步驟(2)後,說明最左邊的結點已被找到,訪問棧頂元素
(5)此時倘若棧頂元素沒有右孩子,或者有右孩子但已被訪問輸出;則直接列印輸出該結點,並將其出棧
(6)否則當不滿足(4)的情況時,將該結點的右孩子給pCur
(7)重複3、4、5、6步驟,直至棧為空,return
程式碼實現:
//後序非遞迴
void PostOrder_N()
{
_PostOrder_N(_pRoot);
}
//後序非遞迴
void _PostOrder_N(PNode pRoot)
{
if(NULL == pRoot)
return;
stack<PNode> s;
PNode pCur = pRoot;
PNode prev = NULL:
while()
{
while()
{
s.push(pCur);
pCur = pCur->_pLeft;
}
pTop = s.top();
if(NULL == pTop->_pRight || prev == pTop->_pRight)
{
cout<<pTop->_data<<"";
s.pop;
}
else
{
pCur = pTop->_pRight;
}
}
}
4、層序遍歷(非遞迴)
層序遍歷就是:從根節點到葉子結點按照同一層先左子樹後右子樹的次序遍歷二叉樹。層序遍歷用佇列的方式實現
演算法如下:
(1)初始化一個佇列
(2)將根節點的指標入佇列,即插入隊尾
(3)倘若佇列非空,則迴圈執行下列步驟:
* 從對頭取出一個結點訪問
* 倘若被訪問的結點非空,則讓其左子樹指標入佇列
* 倘若被訪問的結點非空,則讓其左子樹指標入佇列
(4)佇列清空後,return
程式碼實現:
//層序遍歷
void LevelOrder()
{
cout<<"層序遍歷"<<endl;
_LevelOrder(_pRoot);
cout<<""<<endl;
}
//層序遍歷
void _LevelOrder(PNode pRoot)
{
if(pRoot)
{
queue<PNode> q;
q.push(pRoot);
while(!q.empty())
{
PNode pCur = q.front();
cout<< pCur->_data <<"";
q.pop();
if(pCur->_pLeft)
q.push(pCur->_pLeft);
if(pCur->_pRight)
q.push(pCur->_pRight);
}
}
}
相關文章
- 二叉樹非遞迴遍歷二叉樹遞迴
- 二叉樹的四種遍歷(遞迴與非遞迴)二叉樹遞迴
- 【資料結構】二叉樹遍歷(遞迴+非遞迴)資料結構二叉樹遞迴
- 什麼是遍歷二叉樹,JavaScript實現二叉樹的遍歷(遞迴,非遞迴)二叉樹JavaScript遞迴
- 非遞迴先序遍歷二叉樹遞迴二叉樹
- 【刷題】二叉樹非遞迴遍歷二叉樹遞迴
- 遍歷二叉樹的遞迴與非遞迴程式碼實現二叉樹遞迴
- 二叉樹建立及遍歷演算法(遞迴及非遞迴)二叉樹演算法遞迴
- 樹3-二叉樹非遞迴遍歷(棧)二叉樹遞迴
- 二叉樹的非遞迴遍歷寫法二叉樹遞迴
- 二叉樹的前中後序遍歷(遞迴和非遞迴版本)二叉樹遞迴
- 二叉樹——後序遍歷的遞迴與非遞迴演算法二叉樹遞迴演算法
- [java] 二叉樹的後序遍歷(遞迴與非遞迴實現)Java二叉樹遞迴
- python實現二叉樹及其七種遍歷方式(遞迴+非遞迴)Python二叉樹遞迴
- 二叉樹的所有遍歷非遞迴實現二叉樹遞迴
- 二叉樹的非遞迴遍歷——java實現二叉樹遞迴Java
- 樹(2)--二叉樹的遍歷(非遞迴)+線索二叉樹二叉樹遞迴
- 【C++】翻轉二叉樹(遞迴、非遞迴)C++二叉樹遞迴
- 二叉樹的遍歷 → 不用遞迴,還能遍歷嗎二叉樹遞迴
- 遍歷二叉樹的迭代和遞迴方法二叉樹遞迴
- Day14 | 二叉樹遞迴遍歷二叉樹遞迴
- 二叉樹的建立與遍歷(遞迴實現)二叉樹遞迴
- Java遍歷資料夾的兩種方法(非遞迴和遞迴)Java遞迴
- 刷題系列 - Python用非遞迴實現二叉樹前序遍歷Python遞迴二叉樹
- 二叉樹建立後,如何使用遞迴和棧遍歷二叉樹?二叉樹遞迴
- Android遍歷所有控制元件的遞迴和非遞迴實現Android控制元件遞迴
- 刷題系列 - Python用非遞迴實現二叉樹後續遍歷Python遞迴二叉樹
- 刷題系列 - Python用非遞迴實現二叉樹中序遍歷Python遞迴二叉樹
- 非遞迴實現先序遍歷和中序遍歷遞迴
- 資料結構-樹以及深度、廣度優先遍歷(遞迴和非遞迴,python實現)資料結構遞迴Python
- 重拾演算法(1)——優雅地非遞迴遍歷二叉樹及其它演算法遞迴二叉樹
- 快速排序【遞迴】【非遞迴】排序遞迴
- js遞迴遍歷講解JS遞迴
- 【Java資料結構與演算法筆記(二)】樹的四種遍歷方式(遞迴&非遞迴)Java資料結構演算法筆記遞迴
- 每天刷個演算法題20160518:非遞迴二叉樹遍歷演算法遞迴二叉樹
- 資料結構初階--二叉樹(前中後序遍歷遞迴+非遞迴實現+相關求算結點實現)資料結構二叉樹遞迴
- 迴圈遍歷二叉樹二叉樹
- 遞迴遍歷樹狀結構優雅實現遞迴