二叉樹的順序儲存結構

2021-04-06 23:36:19 字數 4935 閱讀 7324

此結構是將二叉樹的所有結點,按照一定的次序,儲存到一片連續的儲存單元中。因此,必須將結點排成乙個適當的線性序列,使得結點在這個序列中的相應位置能反映出結點之間的邏輯關係。這種結構特別適用於近似滿二叉樹。

在一棵具有n個結點的近似滿二叉樹中,我們從樹根起,自上層到下層,逐層從左到右給所有結點編號,就能得到乙個足以反映整個二叉樹結構的線性序列,如圖6所示。其中每個結點的編號就作為結點的名稱。

圖6 近似滿二叉樹的結點編號

因此,我們可以對樹的型別作如下說明:

tposition=integer;

treetype=record

nodecount:integer;     

nodelist:array [1..maxnodecount] of labeltype;

end;

將陣列下標作為結點名稱(編號),就可將二叉樹中所有結點的標號儲存在一維陣列中。例如,圖6中的二叉樹的順序儲存結構如圖7所示。

圖7 近似滿二叉樹的順序儲存結構

在二叉樹的這種表示方式下,各結點之間的邏輯關係是隱含表示的。近似滿二叉樹中,除最下面一層外,各層都充滿了結點。可能除最底層外,每一層的結點個數恰好是上一層結點個數的2倍。因此,從乙個結點的編號就可推知其父親,左、右兒子,和兄弟等結點的編號。例如,對於結點i我們有:

僅當i=1時,結點i為根結點;

當i>1時,結點i的父結點為i/2;

結點i的左兒子結點為2i;

結點i的右兒子結點為2i+1;

當i為奇數且不為1時,結點i的左兄弟結點為i-1;

當i為偶數時,結點i的右兄弟結點為i+1。

由上述關係可知,近似滿二叉樹中結點的層次關係足以反映結點之間的邏輯關係。因此,對近似滿二叉樹而言,順序儲存結構既簡單又節省儲存空間。

對於一般的二叉樹,採用順序儲存時,為了能用結點在陣列中的位置來表示結點之間的邏輯關係,也必須按近似滿二叉樹的形式來儲存樹中的結點。顯然,這將造成儲存空間的浪費。在最壞情況下,乙個只有k個結點的右單枝樹卻需要2k-1個結點的儲存空間。例如,只有3個結點的右單枝樹,如圖8(a)所示,添上一些實際不存在的虛結點後,成為一棵近似滿二叉樹,相應的順序儲存結構如圖8(b)所示。

圖8 一般二叉樹的順序儲存結構

下面我們就用這種順序儲存結構來實現二叉樹的常用操作。在這種表示法中,整數0表示空結點∧。對於非近似滿二叉樹,我們將其補為近似滿二叉樹,並規定乙個特殊的標號&,用來表示補充的結點,&要根據標號的具體型別來確定。

順序儲存結構實現adt二叉樹的操作

函式 parent(v,t);功能

這是乙個求父結點的函式,函式值為樹t中結點v的父親。當v是根結點時,函式值為∧,表示結點v沒有父結點。

實現

function parent(v:tposition;var t:treetype):tposition;

begin

return(v div 2);

end;

說明

根據這種表示法,我們知道,當i>1時,結點i的父結點為i/2。

複雜性

顯然為o(1)。

函式 left_child(v,t);功能

這是乙個求左兒子結點的函式。函式值為樹t中結點v的左兒子。當結點v沒有左兒子時,函式值為∧。

實現

function left_child(v:tposition;var t:treetype):tposition;

begin

if (2*v>t.nodecount)or(t.nodelist[2*v]=&) then return(0)

else return(2*v);

end;

說明

如果結點v的左兒子存在,則其下標為2*v。

複雜性

顯然為o(1)。

函式 right_child(v,t);功能

這是乙個求右兒子結點的函式。函式值為樹t中結點v的右兒子。當結點v沒有右兒子時,函式值為∧。

實現

procedure right_child(v:tposition;var t:treetype):tposition;

begin

if (2*v+1>t.nodecount)or(t.nodelist[2*v+1]=&) then return(0)

else return(2*v+1);

end;

說明

如果結點v的左兒子存在,則其下標為2*v+1。

複雜性

顯然為o(1)。

函式 create(x,left,right,t);功能

這是乙個建樹過程。該函式生成一棵新的二叉樹t,t的根結點標號為x,左右兒子分別為left和right。

實現

procedure create(x:labeltype;var left,right,t:treetype);

begin

t.nodelist[1]:=x;

t.nodecount:=left.nodecount+right.nodecount+1;

h_left:=cal(left.nodecount);

h_right:=cal(right.nodecount);

if h_left>h_right then h:=h_left else h:=h_right;

for i:=left.nodecount+1 to (1 shl (h+1))-1 do left.nodelist[i]:=&;

left.nodecount:=(1 shl (h+1))-1;

if h_rightbegin

for i:=right.nodecount+1 to (1 shl h)-1 do right.nodelist[i]:=&;

right.nodecount:=(1 shl h)-1;

end;

for i:=1 to left.nodecount do

t.nodelist[(1 shl cal(i))+i]:=left.nodelist[i];

for i:=1 to right.nodecount do

t.nodelist[(1 shl (cal(i)+1))+i]:=right.nodelist[i];

end;

其中cal(i)用來計算含有i個結點的近似滿二叉樹t的高度,cal(i)=log2(i+1)-1,可以實現如下:

function cal(i:integer;):integer;

varx:real;

begin

x:=log2(i+1)-1;

if x=int(x) then return(x) else return(int(x)+1);

end;

其中log2(n)計算實數n以2為底的對數。

說明

在順序儲存的結構下,建立一棵新的二叉樹的過程比較複雜。我們首先給出以下幾個命題:

命題一

一棵高度為h的滿二叉樹有2h+1-1個結點。

證明:

滿二叉樹的第i層有2i個結點,i=0,1,2,...,h(樹根為第0層),因此高度為h的滿二叉樹有20+21+..+2h = 2h+1-1個結點。

推論一

我們從樹根起,自上層到下層,逐層從左到右給二叉樹的所有結點編號,如圖6所示,則近似滿二叉樹的第h層的從左到右第k個結點的編號為2h+k-1。

證明:

由於是近似滿二叉樹,所以第0層到第h-1層是滿二叉樹,根據命題一知道共有2h-1個結點,因此第h層的從左到右第1個結點的編號為2h-1+1,第h層的從左到右第k個結點的編號為2h-1+k。

推論二

一棵有n個結點的近似滿二叉樹,高度為log2(n+1)-1,其中是天花板符號,x表示大於等於x的最小整數。

證明:

有n個結點的近似滿二叉樹,若其高度為h,則滿足2h-1h+1-1,化簡得 log2(n+1)-1 ≤ h < [log2(n+1)-1]+1,即h=log2(n+1)-1。

推論三

在近似滿二叉樹t中,設編號為i的結點處於t的第h層從左到右第k個位置上,則h=log2(i+1)-1,k=i-(2h-1)。

證明:

我們先不考慮編號大於i的結點,則前i個結點構成一棵近似滿二叉樹,根據推論二知其層數為h=log2(i+1)-1,又因為第0層到第h-1層是滿二叉樹,根據命題一知道共有2h-1個結點,所以編號為i的結點處於第h層的第k=i-(2h-1)個位置上。

我們用t(h,k)表示樹t的第h層的第k個結點,則有下列命題:

命題二

left(h,k)=t(h+1,k),right(h,k)=t(h+1,k+2h),其中left和right分別是樹t的根結點的左右子樹。

證明:

顯然。

我們用n(v,t)表示結點v在生成的新樹t中的編號,則有下列命題:

命題三

對於left中編號為i的結點v,n(v,t)=2h +i,其中h=log2(i+1)-1;對於right中編號為i的結點v,n(v,t)=2h+1+i,其中h=log2(i+1)-1。

證明:

在left中編號為i的結點,根據推論三,他處於left的第h=log2(i+1)-1層,第k=i-(2h-1)個位置上。根據命題二該結點處於新樹t的第h+1層第k個位置上,所以根據推論一,它在二叉樹t中的編號為2h+1+k-1=2*2h+[i-(2h-1)]-1=2h+i。結點在right中的情況同理可證。

有了命題三,我們就可以完成建樹的過程。演算法如下:

根據推論二計算left和right的高度,分別為hleft和hright ;

設h=max,新樹t的高度就為h+1;

將left補成高度為h的滿二叉樹;

若hright

依次掃瞄left的每乙個結點,根據命題三計算出left中編號為i的結點在t中的位置,將其複製到t中;

依次掃瞄right的每乙個結點,根據命題三計算出right中編號為i的結點在t中的位置,將其複製到t中;

具體程式見前文的實現。

複雜性

演算法的主要時間花在掃瞄和賦值結點上,設新樹有n個結點,則複雜性為o(n)。

二叉樹的順序儲存結構

二叉樹的順序儲存結構 include includeusing namespace std define virnode 0 定義虛擬節點 define max tree size 100 定義儲存空間最大量 typedef char elemtype 定義節點型別 typedef elemtype...

二叉樹的順序儲存結構

新增鏈結描述 上面文章中講述二叉樹的順序儲存結構的 這裡給執行了一下,以及遇到的一些問題,我都在 裡標註了.include includeusing namespace std const int m 100 class bitree int create bt 手動輸入二叉樹各節點的資訊 void...

二叉樹的順序儲存結構

完全二叉樹的順序儲存結構的性質 完全二叉樹的順序儲存結構 採用一維陣列,按層序順序依次儲存二叉樹的每乙個結 點。如下圖所示 一般二叉樹的順序儲存結構 通過虛設部分結點,使其變成相應的完全二叉樹。如已知某結點的層序編號i,則可求得該結點的雙親結點 左孩子結點和右孩子結點,然後檢測其值是否為虛設的特殊結...