L2_006樹的遍歷(後序+中序->前序/層序)
給定一棵二叉樹的後序遍歷和中序遍歷,請你輸出其層序遍歷的序列。這裡假設鍵值都是互不相等的正整數。
輸入格式:
輸入第一行給出一個正整數N(<=30),是二叉樹中結點的個數。第二行給出其後序遍歷序列。第三行給出其中序遍歷序列。數字間以空格分隔。
輸出格式:
在一行中輸出該樹的層序遍歷的序列。數字間以1個空格分隔,行首尾不得有多餘空格。
輸入樣例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
輸出樣例:
4 1 6 3 5 7 2
- 後序+中序->前序
因為輸出順序是根,左樹,右樹,就可以先處理根,然後遞迴的處理左樹,再遞迴的處理右樹
每一步進行處理時先根據結點node在後序中的下標輸出node(下標時呼叫函式時就已知的),接下來遞迴,需要知道左,右子樹根在後序中的下標,左子樹根的下標=根後序下標-右子樹的長度-1
右子樹的長度=樹中序中最後一個結點的下標-根的中序下標
樹的中序下標,根據後序下標索引到值,然後在中序中for迴圈找,要注意這裡不是朝找整個中序陣列,而是以該點為根的樹在中序中的起始與結尾這段
所以遞迴時還應該傳入以該節點為根的樹在中序中起始點與結尾點的下標左子樹的開始=它父節點為根的樹的開始
左子樹的結束=父節點中序下標-1
右子樹根的下標=父節點後序下標-1
右子樹的開始=父節點中序下標+1
右子樹的結束=它父節點為根的樹的結束
注意在中序中找根時,若根中序下標等於start說明沒有左樹,若等於end說明沒有右樹
那麼遞迴到下一輪的時候就會造成start>end就可以return了
#include <iostream>
#define N 31
using namespace std;
int back[N], mid[N];
void front(int kb, int start, int end)
{
if (start > end)
return;
cout << back[kb]<<" ";
int i = start;
for (; i <= end; ++i) {
if (mid[i] == back[kb])
break;
}//如果沒有左子樹的話i就會等於start
//沒有右子樹i等於end
//就會造成遞迴呼叫左右子樹時的start>end
int km = i;
int lkb = kb - (end - km) - 1;
int lstart = start;
int lend = km - 1;
int rkb = kb - 1;
int rstart = km + 1;
int rend = end;
front(lkb, lstart, lend);
front(rkb, rstart, rend);
}
int main()
{
int n; cin >> n;
for (int i = 0; i < n; ++i) {
cin >> back[i];
}
for (int i = 0; i < n; ++i) {
cin >> mid[i];
}
front(n-1, 0, n - 1);
system("pause");
return 0;
}
- 後序+中序->層序
在前面轉前序的基礎上就只要修改一些就先行了
由於遞迴是處理完了左樹才處理右樹的
但層序遍歷並不是輸完了左樹才樹右樹的
所以下面這部很重要
在以前序的順序訪問到每個點時,不將它輸出,將他們儲存起來並有一個標記可以標識等會兒的輸出順序
這裡定義一個index的向量,index的索引代表滿二叉樹中層序時每個結點的編號,值就代表結點的值,一開始把值全初始化為-1表示該索引下還沒有值
然後遞迴呼叫時再傳入該結點在這棵滿樹上應該放的位置的索引,然後利用後序下標把值賦給這個索引,計算左右子樹的索引就可以利用2i+1,2i+2(下標從0開始)
最後在遍歷這個index遇到非-1的輸出,若輸出的數量達到n了就不再遍歷了
#include <iostream>
#include <vector>
#define N 31
using namespace std;
int back[N], mid[N];
vector<int> index(100000,-1);
void front(int kb, int start, int end,int ind)
{
if (start > end)
return;
//=======修改部分=================================
index[ind]=back[kb];
//===============================================
int i = start;
for (; i <= end; ++i) {
if (mid[i] == back[kb])
break;
}//如果沒有左子樹的話i就會等於start
//沒有右子樹i等於end
//就會造成遞迴呼叫左右子樹時的start>end
int km = i;
int lkb = kb - (end - km) - 1;
int lstart = start;
int lend = km - 1;
int rkb = kb - 1;
int rstart = km + 1;
int rend = end;
front(lkb, lstart, lend,ind*2+1);
front(rkb, rstart, rend,ind*2+2);
}
int main()
{
int n; cin >> n;
for (int i = 0; i < n; ++i) {
cin >> back[i];
}
for (int i = 0; i < n; ++i) {
cin >> mid[i];
}
front(n-1, 0, n - 1,0);
int cnt=0;
for(int i=0;i<index.size()&&cnt<=n;++i){
if(index[i]!=-1){
if(i)
cout<<" ";
cout<<index[i];
++cnt;
}
}
return 0;
}
以上參考:https://www.liuchuo.net/archives/2093
- 另一個思路
宣告一個結構體node,成員有這個點的值value,以這個值為根的樹的開始中序中下標start,結束end,這個值的後序下標
然後利用佇列
一開始把後序中最後一個結點入隊,start是0,end是n-1,後序下標是n-1
每出隊一個點就輸出這個點的value,並計算出它左右孩子的以上引數,並且入隊,計算方法和前面相同
注意當根中序下標為start就沒有左孩子,為end就沒有有孩子,這兩種情況是不用入隊的
因為層序遍歷本身就是採用佇列的,所以感覺還挺有道理的
程式碼實現改天補
相關文章
- 刷題筆記:樹的前序、中序、後序遍歷筆記
- 二叉樹的前序、中序、後序三種遍歷二叉樹
- 二叉樹的前序,中序,後序遍歷方法總結二叉樹
- 二叉樹的四種遍歷方法:先序,中序,後序,層序二叉樹
- 144. 二叉樹的遍歷「前序、中序、後序」 Golang實現二叉樹Golang
- 遞迴和迭代實現二叉樹先序、中序、後序和層序遍歷遞迴二叉樹
- 二叉樹迭代器(中序遞迴、前序和後序遍歷)演算法二叉樹遞迴演算法
- 144.二叉樹的前序遍歷145.二叉樹的後序遍歷 94.二叉樹的中序遍歷二叉樹
- 【樹01】對二叉樹前序/中序/後序遍歷演算法的一些思考二叉樹演算法
- 【資料結構與演算法】二叉樹的 Morris 遍歷(前序、中序、後序)資料結構演算法二叉樹
- 二叉樹中序和後序遍歷表示式二叉樹
- 根據前序遍歷序列、中序遍歷序列,重建二叉樹二叉樹
- 二叉樹的層序遍歷二叉樹
- python-二叉樹:前、中、後、層序遍歷Python二叉樹
- 演算法 -- 實現二叉樹先序,中序和後序遍歷演算法二叉樹
- 後序+中序(前序+中序)重構樹,嚴格O(N)演算法演算法
- 二叉樹--後序遍歷二叉樹
- 從中序與後序遍歷序列構造二叉樹二叉樹
- 二叉樹 ---- 前序 中序 後序 知二求一二叉樹
- 二叉樹的先中後序遍歷二叉樹
- 二叉樹的先,中,後序遍歷二叉樹
- 二叉樹的前中後序遍歷二叉樹
- 根據二叉樹的前序遍歷和中序遍歷輸出二叉樹;二叉樹
- 7-1 根據後序和中序遍歷輸出先序遍歷 (25 分)
- ast 後序遍歷AST
- 二叉樹:構造二叉樹(通過前序和中序遍歷)、映象翻轉、層次遍歷二叉樹
- 力扣#94 樹的中序遍歷力扣
- 889. 根據前序和後序遍歷構造二叉樹二叉樹
- 二叉樹的前序、中序、後序的遞迴和迭代實現二叉樹遞迴
- Leetcode 889. 根據前序和後序遍歷構造二叉樹LeetCode二叉樹
- Morris中序遍歷
- 層序遍歷樹的節點,佇列實現佇列
- LeetCode102.二叉樹的層序遍歷LeetCode二叉樹
- LeetCode-106-從中序與後序遍歷序列構造二叉樹LeetCode二叉樹
- 非遞迴實現先序遍歷和中序遍歷遞迴
- PAT 1043 Is It a Binary Search Tree (25分) 由前序遍歷得到二叉搜尋樹的後序遍歷
- LeetCode 105. 從前序與中序遍歷序列構造二叉樹LeetCode二叉樹
- LeetCode-105-從前序與中序遍歷序列構造二叉樹LeetCode二叉樹