二叉樹遍歷模板以及一些例子
//二叉樹三種遍歷模板(本文直接摘自天勤考研資料結構第六章)
void Travel(BTNode *p)
{
if (p != NULL)
{
//(1)
Travel(p->lchild);
//(2)
Travel(p->rchild);
//(3)
}
/************************************************************************/ /* 如果將對結點的訪問操作寫在(1)處,就是先序遍歷 如果將對結點的訪問操作寫在(2)處,就是中序遍歷 如果將對結點的訪問操作寫在(3)處,就是後序遍歷 摘自天勤考研資料結構P142,下面看一個應用 */ /************************************************************************/ } //編寫一個演算法輸出二叉樹先序遍歷中第k個結點的值
int n = 0; void travel1(BTNode *p, int k) { if (p != NULL) { ++n;//當程式第一次來到一個結點時進行計數,表示這是第n個結點 if (k == n)//當第一次來到這個結點時進行判斷,看這個結點是不是先序序列中的第k個結點 { cout << p->data << endl;//如果是則輸出結點的值 return;//並且無需再進行遍歷了,直接return返回 } travel1(p->lchild, k); travel1(p->rchild, k); /************************************************************************/ /* 此處 ++n;//當程式第一次來到一個結點時進行計數,表示這是第n個結點 if (k == n)//當第一次來到這個結點時進行判斷,看這個結點是不是先序序列中的第k個結點 { cout << p->data << endl;//如果是則輸出結點的值 return;//並且無需再進行遍歷了,直接return返回 } 相當於是對結點的訪問函式,當題目變成求後續序列或者中序序列第k個結點是,把這段程式碼放到相應的位置即可 (1,2,3處) */ /************************************************************************/ } }
//二叉樹的層次遍歷 /************************************************************************/ /* 二叉樹要進行層次遍歷,則需要建立一個迴圈佇列。先將這顆二叉樹頭結點如佇列然後出佇列,訪問該結點 ,如果它有左子樹,則將左子樹的根結點入佇列,如果它有右子樹,則將右子樹的根結點入佇列。然後出佇列 再對出佇列的結點訪問,如此反覆,直到佇列為空為止,對應的演算法如下: */ /************************************************************************/
void LevelTravel(BTNode *p)
{
//定義一個迴圈佇列,用來記錄將要訪問的層次上的結點
circular_buffer<BTNode* > circlequeue;//此處使用了在boost庫中提供的迴圈佇列
BTNode *q = NULL ;
if (p != NULL)
{
circlequeue.push_back(p); // 根結點入佇列
//當佇列不為空的時候進行迴圈
while ( !(circlequeue.empty() ) )
{
q = circlequeue.front() ;
circlequeue.pop_front();//頭結點出隊
visit(q);//訪問頭結點
if (q->lchild != NULL)//如果左子樹不為空,則左子樹的根結點入隊
{
circlequeue.push_back(q->lchild);
}
if (q->rchild !=NULL)//如果右子樹不為空,則右子樹的根結點入佇列
{
circlequeue.push_back(q->rchild);
}
}
}
}
//例題:求二叉樹的寬度(寬度指的是具有結點數目最多的那一層的結點個數) /************************************************************************/ /* 分析:要求含有最大結點數的層上的結點數,可以分別求出每層的結點數,然後從中選出最大的。要達到整兒目的,應該明白以下兩個知識點: 1、對於非空樹,根結點所在的層為第一層,並且通過層次遍歷演算法的程式中可以得知,有一個當由當前結點找到其左右孩子結點的操作。這就 提示我們,若果知道當前結點的層號,就可以推出其左右孩子結點的層號,即為當前結點的層號加1,進而可以求出所有結點的層號 2、在層次遍歷過程中,用到了一個迴圈佇列(佇列用陣列表示)。其出隊和入隊操作分別為front=(front+1)%maxsize;和rear=(rear+1)%maxsize; 兩句。如果用來儲存佇列的陣列長度夠長,可以容納樹中所有結點,這時候遍歷遍歷操作中隊頭和隊尾指標不會出現這回陣列起始位置的情況,那麼 fornt=(front+1)%MAXSIZE;就可以用++front;代替,rear=(rear+1)%mAXSIZE;就可以用++rea;代替。出隊操作只是隊頭指標front想後移動了一位, 但並沒有把隊頭元素刪除。在陣列長度足夠長的情況下,隊頭元素也不會被新入隊的元素覆蓋。 搞清楚上面兩點之後,這個題目就好解決了。由第一點可一算出所有結點的層號。由 第二點可以知道所訪問的結點最終會儲存在一個數組中。因此只 需要修改層次遍歷演算法的模板,在其中添上求層號的操作,並將迴圈佇列的操作改為非迴圈佇列的操作。在遍歷結束以後,陣列中記錄了所有結點的 層號資訊。進而可以求得含有最多的層上的結點數,上程式碼 */ /************************************************************************/
typedef struct
{
BTNode* p; //結點指標
int lno; //結點所在的層次號
}ST;
int MaxNode(BTNode* b)
{
circular_buffer<ST > queue2; //boost庫當中的迴圈佇列
int front = 0, rear = -1;
int Lno, i, j, max;
BTNode *q = NULL;
if (NULL != b)
{
++rear;
queue2[rear].p=b; //樹根入隊
queue2[rear].lno = 1; //樹根所在結點層次號設定為1,此為已知條件
while (front != rear)
{
++front;
q = (queue2.front() ).p;
Lno = (queue2.front()).lno; //關鍵語句,Lno用來存取當前結點的層次號
queue2.pop_front();
if (q->lchild != NULL)
{
++rear;
queue2[rear].p = q->lchild;
queue2[rear].lno = Lno + 1;//關鍵語句:根據當前結點的層次號推知其左孩子結點的層次號
}
if(q->rchild != NULL)
{
++rear;
queue2[rear].p = q->rchild;
queue2[rear].lno = Lno + 1;//關鍵語句:根據當前結點的層次號推知其右孩子結點的層次號
}
} //注意:迴圈結束的時候,Lno儲存的是這顆二叉樹的最大層數,下面才是開始求含有結點最多層次中的結點數
max = 0;
for (int i = 1; i <= Lno; ++i)
{
n = 0;
for (j = 1;j <= rear;++j)
{
if (queue2[j].lno == j)
++n;
if (max < n)
max = n;
}
return max;
}
}
else return 0; //空樹直接返回0
}