1. 程式人生 > >P1132已知先後序和中序求先序排列解題報告

P1132已知先後序和中序求先序排列解題報告

Name: 已知先後序和中序,求出它的先序排列

Copyright: 始發於goal00001111的專欄;允許自由轉載,但必須註明作者和出處

Author: goal00001111

Date: 11-12-08 10:58

Description:

題目描述:

描述 Description

給出一棵二叉樹的中序與後序排列。求出它的先序排列。(約定樹結點用不同的大寫字母表示,長度≤8)

輸入格式 Input Format

第一行為二叉樹的中序序列

第二行為二叉樹的後序序列

輸出格式 Output Format

一行,為二叉樹的先序序列

樣例輸入 Sample Input

BADC BDCA

樣例輸出 Sample Output

ABCD

題目分析:

已知中序和前序排列,或者已知中序和後序序列,都能夠構造一棵二叉樹,此題考查後者。

前序遍歷的規律是:輸出根結點,輸出左子樹,輸出右子樹;

中序遍歷的規律是:輸出左子樹,輸出根結點,輸出右子樹;

後序遍歷的規律是:輸出左子樹,輸出右子樹,輸出根結點;

根據中序和後序序列的規律,我們可以知道構造二叉樹的過程是一個遞迴的過程,根據給定的 中序和後序序列,建立二叉樹的根結點,並將中序序列劃分為左子樹序列和右子樹序列,然後分別把左子樹序列和右子樹序列遞迴的構造左子樹和右子樹。

具體的演算法是分別用陣列mid[lm..rm]

post[tp..rp]儲存給定的中序和後序序列。易知post[rp]為根結點,建立二叉樹的根結點t,設t->data = post[rp];遍歷mid,尋找根結點post[rp]的下標pos,則mid[lm..pos-1]為左子樹序列,mid[pos+1..rm]為右子樹序列;左子樹序列的長度lenL= pos - lm,右子樹序列的長度lenR= rm - pos

很明顯,若pos == lm,則lenL = 0,說明根結點無左子樹;若pos == rm,則lenR = 0,說明根結點無右子樹;

根據後序序列的規律,可以知道根結點t的左子樹的後序排列為post[lp..lp+lenL-1];

根結點t的右子樹的後序排列為post[lp+lenL..rp-1]

採用同樣的方法遞迴構造根結點t的左右子樹。

以樣例輸入為例:

中序序列:BADC

後序序列:BDCA

1.得到根結點t->data = 'A';

2.遍歷中序序列mid,得到mid[pos] = 'A'lenL = 1

3.得到根結點t的左子樹的中序序列為mid[lm..pos-1] = "B",右子樹的中序序列為mid[pos+1..rm] = "DC";根結點t的左子樹的後序序列為post[lp..lp+lenL-1] = "B",右子樹的後序序列為post[lp+lenL..rp-1] = "DC";

4.遞迴構造根結點t的左子樹t->lc,設t= t->lc

1.得到根結點t->data = 'B';

2.遍歷中序序列mid,得到mid[pos] = 'B'lenL = 0

3.得到根結點t的左右子樹均為空,返回呼叫函式。

5. 遞迴構造根結點t的右子樹t->rc,設t= t->rc

1.得到根結點t->data = 'C';

2.遍歷中序序列mid,得到mid[pos] = 'C'lenL = 1

3.得到根結點t的左子樹的中序序列為"D",後序序列為"D";右子樹為空,

4.遞迴構造根結點t的左子樹t->lc

6.最後得到整棵二叉樹,前序遍歷二叉樹,得到前序序列:ABCD

說明:

演算法思想:遞迴和分治。

資料結構:陣列,二叉樹。

時間複雜度:O(N);

空間複雜度:O(N);

程式語言:分別用c++pascal實現。

附註:

若題目改為已知中序和前序序列,輸出後序序列,因為先序序列pre[lp..rp]中根結點是第一個元素,所以只需將函式中的根結點資料由t->data = post[rp] 改為t->data = pre[lp] 然後在遞迴構造左右子樹時注意左子樹中序序列為mid[lm+1..pos-1],右子樹中序序列為mid[pos+1..rm],左子樹先序序列為pre[lp+1..lp+lenL],右子樹先序序列為pre[lp+lenL+1..rp]

最後後序遍歷二叉樹就行了。

c++程式碼:

#include<iostream>

#include<string>

using namespace std;

typedef struct BTNode{

char data;

struct BTNode *lc, *rc;//左,右孩子指標

} *BTree;

void PostBtree(BTree & t, string mid, string post, int lm, int rm, int lp, int rp);

void Preorder(BTree p);

int main(int argc, char* argv[])

{

string mid, post;

BTree root;

cin >> mid;

cin >> post;

PostBtree(root, mid, post, 0, mid.size()-1, 0, post.size()-1);

Preorder(root);

system("pause");

return 0;

}

/*

函式名稱:PostBtree

函式功能:給出一棵二叉樹的中序與後序序列,構造這棵二叉樹。

輸入引數: BTree & t:二叉樹的結點t

string mid:儲存了二叉樹的中序序列的字串

string post:儲存了二叉樹的後序序列的字串

int lm, int rm:二叉樹的中序序列在陣列mid中的左右邊界

int lp, int rp:二叉樹的後序序列在陣列post中的左右邊界

*/

void PostBtree(BTree & t, string mid, string post, int lm, int rm, int lp, int rp)

{

t = new BTNode; //構造二叉樹根結點

t->data = post[rp];

t->lc = t->rc = NULL;

int pos = lm;

while (mid[pos] != post[rp])

pos++;

int lenL = pos - lm;

if (pos > lm)//有左孩子,遞迴構造左子樹

PostBtree(t->lc, mid, post, lm, pos-1, lp, lp+lenL-1);

if (pos < rm)//有右孩子,遞迴構造右子樹

PostBtree(t->rc, mid, post, pos+1, rm, lp+lenL, rp-1);

}

//先序遍歷

void Preorder(BTree p)

{

if(p != NULL)

{

cout << p->data; //輸出該結點

Preorder(p->lc); //遍歷左子樹

Preorder(p->rc); //遍歷右子樹

}

}

PASCAL程式碼:

PROGRAM EXAMP1132(INPUT, OUTPUT);

TYPE

BTree = ^node;

node = record

data : char;

lc, rc : BTree;

end; {record}

VAR

mid, post : string;

root : BTree;

{先序遍歷}

PROCEDURE Preorder(t : BTree);

begin

if t <> nil then

begin

write(t^.data);{輸出該結點}

Preorder(t^.lc); {遍歷左子樹}

Preorder(t^.rc); {遍歷右子樹}

end;

end;

{已知後序和中序,構造二叉樹}

PROCEDURE PostBtree(var t : BTree; mid, post : string; lm, rm, lp, rp : integer);

var

pos, lenL : integer;

begin

new(t);

t^.data := post[rp];

t^.lc := nil;

t^.rc := nil;

pos := lm;

while mid[pos] <> post[rp] do

inc(pos);

lenL := pos - lm;

if pos > lm then {有左孩子,遞迴構造左子樹}

PostBtree(t^.lc, mid, post, lm, pos-1, lp, lp+lenL-1);

if pos < rm then {有右孩子,遞迴構造右子樹}

PostBtree(t^.rc, mid, post, pos+1, rm, lp+lenL, rp-1);

end; {PostBtree}

BEGIN

readln(mid);

readln(post);

PostBtree(root, mid, post, 1, ord(mid[0]), 1, ord(post[0]));

Preorder(root);

END.