根據樹的前序遍歷、中序遍歷、後序遍歷中的兩種遍歷求第三種遍歷結果
阿新 • • 發佈:2019-02-09
學過資料結構,都知道二叉樹有四種遍歷手段,前序遍歷、中序遍歷、後序遍歷以及層序遍歷,而前三種遍歷存在較強的關聯,即:知道中序遍歷及另外兩種遍歷中的一種時,可以求第三種,簡單的講就是根據中序遍歷和前序遍歷、後序遍歷中的一種,可以求第三種。 是不是有些繞了,自己慢慢理解吧!我們這裡要講一下實現程式碼。 遇見這種問題,我聽說好像可以用棧來實現,但是今天要說的是通過建樹來實現的。 分為兩種情況: 1、知道前序遍歷和中序遍歷,求後序遍歷。 這個相對比較簡單,因為我們可以通過查詢根結點在中序遍歷的位置來對兩種遍歷序列切割,分成子序列,這樣通過遞迴可以實現建樹,並且在遞迴函式尾加上一條輸出語句即可實現後序遍歷。 2、知道後序遍歷和中序遍歷,求前序遍歷。 這個就有些難了,對三種遍歷沒有教深入理解的人是無法理解透這個演算法的,其實和前邊的演算法大致一樣,只是有些許的細節差別,我們同樣是要查詢根結點在中序遍歷中的位置,但是我們不能用同樣的手段分隔,我們知道,中序遍歷,根結點的左邊的都是左子樹,右邊的都是右子樹,而後序遍歷中的根結點在尾部,所以想要分隔必須對中序遍歷進行以根結點為中心左右分割(不留下根結點),對後序遍歷進行的分割要保證前半段的長度和中序遍歷的前半段長度一致,後半段去除根結點的部分,這樣分成了兩段同樣也是左右子樹,另外輸出語句也要提前,因為這是前序遍歷,所以輸出語句需要在遞迴函式呼叫自身前就進行輸出。
大致的思路就是這樣,先看第一種的程式碼(程式碼C++):
#include <iostream>
#include <fstream>
#include <string>
struct TreeNode
{
struct TreeNode* left;
struct TreeNode* right;
char elem;
};
void BinaryTreeFromOrderings(char* inorder, char* preorder, int length)
{
if(length == 0)
{
//cout<<"invalid length";
return;
}
TreeNode* node = new TreeNode;//Noice that [new] should be written out.
node->elem = *preorder;
int rootIndex = 0;
for(;rootIndex < length; rootIndex++)
{
if(inorder[rootIndex] == *preorder)
break;
}
//Left
BinaryTreeFromOrderings(inorder, preorder +1 , rootIndex);
//Right
BinaryTreeFromOrderings(inorder + rootIndex + 1, preorder + rootIndex + 1, length - (rootIndex + 1));
cout<<node->elem<<endl;
return;
}
int main(int argc, char* argv[])
{
printf("Hello World!\n");
char* pr="GDAFEMHZ";
char* in="ADEFGHMZ";
BinaryTreeFromOrderings(in, pr, 8);
printf("\n");
return 0;
}
接著,是第二種情況的程式碼(程式碼C):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef char TElemType;
#define MAX_TREE_SIZE 100
typedef struct BiTNode //結點結構
{
TElemType data; //結點資料
struct BiTNode *lchild, *rchild; //左右孩子指標
} BiTNode, *BiTree;
//建樹並前序遍歷
void BinaryTreeFromOrderings(char *mid, char *last, int len)
{
//長度為0則返回空
if (len == 0)
{
return ;
}
BiTree node = (BiTree)malloc(sizeof(BiTNode)); //分配結點空間
node->data = last[len - 1];
//mid中尋找根結點
int rootIndex = 0;
for (; rootIndex < len; rootIndex++)
{
if (mid[rootIndex] == last[len - 1])
{
break;
}
}
//前序遍歷,則在建一個節點列印一次
printf("%c", node->data);
//Left
BinaryTreeFromOrderings(mid, last, rootIndex);
//Right
BinaryTreeFromOrderings(mid + rootIndex + 1, last + rootIndex, len - (rootIndex + 1)); //後段為右子樹
return ;
}
int main(int argc, const char * argv[])
{
char mid[100], last[100], len;
scanf("%s %s", mid, last);
len = (int)strlen(mid);
BinaryTreeFromOrderings(mid, last, len);
printf("\n");
return 0;
}
這兩種情況演算法都是一樣的,差別就在於序列切割的位置不同,切割的方式也不同,也就是存在細節上的一些問題需要多注意才是,其他的就沒有什麼了,對了,要多學學怎麼用指標,沒有過硬的指標使用基礎,會很不好做的,畢竟是資料結構中的知識,��。