二叉樹的操作
基本概念
二叉樹有5種基本形態,特殊的二叉樹有滿二叉樹、完全二叉樹、二叉排序樹和平衡二叉樹。
性質儲存結構
二叉樹的儲存結構有順序儲存結構和鏈式儲存結構兩種。滿二叉樹和完全二叉樹採取順序儲存結構比較合適,樹中的節點號可以唯一的反映出節點之間的邏輯關係,可以節省空間也可以利用陣列元素的下標確定節點在二叉樹中的位置以及節點之間的關係。一般二叉樹採用鏈式結構儲存,二叉鍊錶中包含3個域,分別是資料域data、左指標lchild和右指標rchild。二叉樹的鏈式儲存結構描述如下:
// 二叉樹鏈式儲存結構
typedef
struct binode binode,
*bitree;
基本概念
線索二叉樹的實質就是對乙個非線性結構進行線性化操作,使在這個訪問序列中的每乙個節點都有乙個直接前驅和乙個直接後繼,引入線索二叉樹是為了加快查詢節點前驅和後繼的速度。
在有n個節點的二叉樹中,一共有n+1空指標。在二叉樹線索化的時候,通常規定:若無左子樹,另lchild指向其前驅節點;若無右子樹,則rchild指向其後繼節點。還需要兩個標誌域ltag和rtag表明當前指標域所指的物件是左子節點還是直接前驅。保標誌域的含義如下所示:
ltag: 0 lchild域指示節點的左孩子;1 lchild域指示節點的前驅;
rtag: 0 rchild域指示節點的右孩子;1 rchild域指示節點的後繼。
線索二叉樹的儲存結構描述如下所示:
typedef
struct threadnode threadnode,
*treadtree;
先序遍歷
由於這種演算法每乙個節點都訪問且僅訪問一次,所以演算法的時間複雜度為o(n),在最壞的情況下,演算法的空間複雜度為o(n).
// 遞迴實現先序遍歷二叉樹
void
preorder
(bitree t)
}/*非遞迴實現先序遍歷二叉樹
演算法思路:
需要借助棧來實現,從根節點開始遍歷二叉樹,如果節點不為空
先輸出節點的資料,節點入棧,然後指標指向節點的左孩子,如
果節點為空那麼從佔中彈出這個節點,並且將指標指向節點的右
孩子,重複這個過程直到棧為空,並且指標指向也為空為止。
*/void
preorder2
(bitree t)
else}}
// 演算法的時間複雜度和空間複雜度都是o(n)
中序遍歷
由於這種演算法每乙個節點都訪問且僅訪問一次,所以演算法的時間複雜度為o(n),在最壞的情況下,演算法的空間複雜度為o(n).
// 遞迴演算法實現中序遍歷二叉樹
void
inorder
(bitree t)
}/*非遞迴實現中序遍歷二叉樹
演算法思路:
需要借助棧來實現,從根節點開始遍歷二叉樹,如果節點不為空
將節點入棧,然後指標指向節點的左孩子,如果節點為空,那麼
從棧中彈出這個節點,輸出節點的資料,並且將指標指向節點的
右孩子,重複這個過程直到棧為空,並且指標指向也為空為止。
*/void
inorder2
(bitree t)
else
}}
後序遍歷
由於這種演算法每乙個節點都訪問且僅訪問一次,所以演算法的時間複雜度為o(n),在最壞的情況下,演算法的空間複雜度為o(n).
// 遞迴實現後序遍歷二叉樹
void
postorder
(bitree t)}/*
非遞迴實現後序遍歷二叉樹
演算法思想:後序遍歷先訪問左節點,再訪問右節點,最後訪問中間節點
在訪問到中間節點的時候要先弄清楚是從左節點返回的中間節點還
是從右節點返回的中間節點,所以需要乙個輔助指標r指向最近訪
問過的節點。
*/void
postorder2
(bitree t)
else
else
}// else
}// while
}
層次遍歷
void
levelorder
(bitree t)
}void
levelorderinverse
(bitree t)
while(!
isempty
(s))
}}
(1)根據二叉樹的先序和中序可以唯一的確定一棵二叉樹:假設先序和中序分別存在兩個一維陣列a[1…n],b[1…n]中,編寫演算法建立該二叉樹的二叉鍊錶。
/*
這個演算法需要遍歷兩個一維陣列,遞迴實現:根據先序序列確定二叉樹的根節點,根據根節點,在中序序列中劃分出左子樹和右子樹,遞迴這個過程。
*/bitree preincreat
(elemtype a[
], elemtype b,
int l1,
int h1,
int12
,int h2)
else
if(lenr)
else
return root;
}
(2)由二叉樹的後序序列和中序序列可以唯一的確定一棵二叉樹
假設後序和中序分別存在兩個一維陣列a[1…n],b[1…n]中,編寫演算法建立該二叉樹的二叉鍊錶。後序序列的最後乙個節點和先序序列的第乙個節點類似,可以將中序分割成兩個子串行。
bitree postincreat
(elemtype a[
], elemtype b,
int l1,
int h1,
int l2,
int h2)
else
if(lenr)
else
return root;
}
(3)由二叉樹的層序序列和中序序列也可以唯一的確定一棵二叉樹
// 假設層序序列和中序分別存在兩個一維陣列a[1....n], b[1....n]中,
// 編寫演算法建立該二叉樹的二叉鍊錶。
/* 演算法思路:從左到右遍歷層序陣列,層序遍歷的第乙個元素如果在中序
中沒有訪問過,那麼這個數可以作為根節點,根據這個根節點可以
將中序序列劃分為左子樹和右子樹。期間需要借助乙個陣列來記錄
元素是否在中序序列中被訪問過。
*/bitree levelincreat
(elemtype a[
], elemtype b[
], boolean c,
int index,
int l,
int r)
else
if(lenr)
else
return root;
}
(1)判斷二叉樹是否為完全二叉樹
思路:使用層次遍歷演算法,將所有節點加入佇列,包括空節點,遍歷結束
後檢視佇列,如果遇到了空節點,看看其後是否有非空節點,如果有,那
麼二叉樹不是完全二叉樹,否則是完全二叉樹。
(2)鏈式儲存,計算二叉樹的所有雙分支節點的個數
思路:採用如下所示的遞迴式:
f(b) = 0; 若b = null
f(b) = f(b->lchild) + f(b->rchild) + 1; 若b為雙分支節點
f(b) = f(b->lchild) + f(b->rchild); 其餘情況
(3)交換二叉樹中所有節點的左右子樹
swap(b->lchild) 遞迴交換左子樹
swap(b->rchild) 遞迴交換右子樹
交換左右孩子節點
(4)指標p,q分別指向二叉樹的任意兩個節點,尋找p,q的最近的公共祖先節點。
採用後序遍歷,訪問到其中乙個節點之後將其之後的所有祖先節點放
入乙個佇列中,另乙個節點也是一樣,訪問到之後將其所有祖先節點
放入另乙個佇列中,遍歷結束之後,比較兩個佇列,兩個佇列第乙個
相同的元素就是兩個節點的最近公共祖先節點。
(5)鏈式儲存,求非空二叉樹的寬度
採用層次遍歷即可得出
(6)滿二叉樹已知先序序列pre,求後序序列post.
先序序列的第乙個節點為後序序列的最後乙個節點,然後除第乙個元
素之外,將先序序列劃分為大小相等的兩份,再對這兩份轉化。
void
pretopost
(pre, post,
int l1,
int h1,
int l2,
int h2)
} ```
二叉樹概念
1996年西安交大考了這個題.主要是對其中的乙個選項有疑問,所以,就整理這乙個點 問下列可稱為二叉樹的是 有乙個選項是這樣的 每個結點至多有兩顆子樹的有序數 答案不是這個,說明這樣說是不對的,但是,什麼原因呢?覺得這個選項對的原因是什麼呀,無非就是說有序,可分為左孩子右孩子,這樣就是二叉樹了.但事實...
二叉樹 概念
為什麼使用樹結構 陣列儲存方式的分析 優點 通過下標方式訪問元素,速度快。對於有序陣列,還可使用二分查詢提高檢索速度。缺點 如果要檢索具體某個值,或者插入值 按一定順序 會整體移動,效率較低 鏈式儲存方式的分析 優點 在一定程度上對陣列儲存方式有優化 比如 插入 乙個數值節點,只需要將插入節點,鏈結...
二叉樹概念
樹和二叉樹 1 定義 雖然沒什麼鳥用,但是需要了解 樹 tree 是n個節點的有限集 非空樹 t 1 有且只有乙個根節點 檔案的目錄介面,根目錄 2 除了根節點外以外多個互相不想交的有限集。2 不說了來一棵樹 二叉樹 二叉樹是重點學習的。3 名詞解釋 需要知道 節點 樹的獨立單元,就是每個圓圈 節點...