android自定义绘制二叉树,安卓数据结构04-二叉树
數(shù)據(jù)結(jié)構(gòu)04-二叉樹(shù)
一、樹(shù)的基本概念
1.樹(shù)
樹(shù)是n(n>=0)個(gè)節(jié)點(diǎn)的有限集。n=0時(shí)稱(chēng)為空樹(shù)。在任意一顆非空樹(shù)中:
有且僅有一個(gè)特定的稱(chēng)為根(Root)的節(jié)點(diǎn);
當(dāng)n>1時(shí),其余節(jié)點(diǎn)可分為m(m>0)個(gè)互不相交的有限集T1、T2、......、Tm,其中每一個(gè)集合本事又是一顆樹(shù),并且稱(chēng)為根的子樹(shù)(SubTree)。
2.度
節(jié)點(diǎn)的度是節(jié)點(diǎn)擁有的子樹(shù)數(shù)。度為0的節(jié)點(diǎn)稱(chēng)為葉子節(jié)點(diǎn)或終端節(jié)點(diǎn),度不為0的節(jié)點(diǎn)稱(chēng)為非終端節(jié)點(diǎn)或分支節(jié)點(diǎn)。除根節(jié)點(diǎn)以外,分支節(jié)點(diǎn)也稱(chēng)為內(nèi)部節(jié)點(diǎn)。樹(shù)的度是樹(shù)內(nèi)各節(jié)點(diǎn)的度的最大值。
3.層次
節(jié)點(diǎn)的層次(Level)從根開(kāi)始定義起,根為第一層,根的孩子為第二層。若某節(jié)點(diǎn)在第n層,則其字?jǐn)?shù)的根就在第n+1層。其雙親在同一層的節(jié)點(diǎn)互為堂兄弟。樹(shù)中節(jié)點(diǎn)的最大層次稱(chēng)為樹(shù)的深度(Depth)或高度。
4.森林
森林(Forest)是m(m>=0)棵互不相交的集合。
5.樹(shù)的存儲(chǔ)結(jié)構(gòu)
簡(jiǎn)單的順序存儲(chǔ)不能滿(mǎn)足樹(shù)的實(shí)現(xiàn),一般結(jié)合順序存儲(chǔ)和鏈?zhǔn)酱鎯?chǔ)來(lái)實(shí)現(xiàn),有四種表示方法:
雙親表示法:在每個(gè)節(jié)點(diǎn)中,附設(shè)一個(gè)指示器指示其雙親節(jié)點(diǎn)到鏈表中的位置。
孩子表示法:在每個(gè)節(jié)點(diǎn)中,附設(shè)幾個(gè)指示器指示子節(jié)點(diǎn)到鏈表中的位置。
雙親孩子表示法:在每個(gè)節(jié)點(diǎn)中,附設(shè)2個(gè)指示器,一個(gè)指示雙親節(jié)點(diǎn),一個(gè)指示孩子鏈表(由它的孩子節(jié)點(diǎn)組成的單鏈表)。
孩子兄弟表示法:在每個(gè)節(jié)點(diǎn)中,附設(shè)2個(gè)指示器,一個(gè)指示它的第一個(gè)孩子節(jié)點(diǎn),一個(gè)指向它的下一個(gè)兄弟節(jié)點(diǎn)。
二、二叉樹(shù)的基本概念
1.二叉樹(shù)
二叉樹(shù)(Binary Tree)是n(n>=0)個(gè)節(jié)點(diǎn)的有限集合,該集合或者位空集(稱(chēng)為空二叉樹(shù)),或者有一個(gè)根節(jié)點(diǎn)和兩顆互不相交的、分別稱(chēng)為根節(jié)點(diǎn)的左子樹(shù)和右子樹(shù)的二叉樹(shù)組成。
2.斜樹(shù)
斜樹(shù)是所有的節(jié)點(diǎn)都只有左子樹(shù)或右子樹(shù)的二叉樹(shù),擁有左子樹(shù)的叫左斜樹(shù),擁有右子樹(shù)的叫右斜樹(shù)。
3.滿(mǎn)二叉樹(shù)
滿(mǎn)二叉樹(shù)是所有的分支節(jié)點(diǎn)都存在左子樹(shù)和右子樹(shù),并且所有葉子都在同一層的二叉樹(shù)。
4.完全二叉樹(shù)
對(duì)一顆具有n個(gè)節(jié)點(diǎn)的而擦汗數(shù)按層序編號(hào),如果編號(hào)為i(1<=i<=n)的節(jié)點(diǎn)與同樣深度的滿(mǎn)二叉樹(shù)中編號(hào)為i的節(jié)點(diǎn)在二叉樹(shù)中位置完全相同,則這顆二叉樹(shù)就是完全二叉樹(shù)。完全二叉樹(shù)可以理解位連續(xù)的二叉樹(shù)。
5.二叉樹(shù)的性質(zhì)
性質(zhì)1:在二叉樹(shù)的第i層上至多有2^(i-1)個(gè)節(jié)點(diǎn)(i>=1)。
性質(zhì)2:深度為k的二叉樹(shù)至多有2^k-1個(gè)節(jié)點(diǎn)(k>=1)。
性質(zhì)3:對(duì)任何一顆二叉樹(shù)T,如果其終端節(jié)點(diǎn)數(shù)為n0,度為2的節(jié)點(diǎn)數(shù)為n1,則n0 = n1+1。
性質(zhì)4:具有n個(gè)節(jié)點(diǎn)的完全二叉樹(shù)深度為log(2)(n)+1。
性質(zhì)5:如果對(duì)一顆有n個(gè)節(jié)點(diǎn)的完全二叉樹(shù)的節(jié)點(diǎn)按層序編號(hào)(從第1層到第log(2)(n)+1層,每層從左到 右),對(duì)任意一個(gè)節(jié)點(diǎn)i(1<=i<=n)有:
如果i=1,則節(jié)點(diǎn)i是二叉樹(shù)的根,無(wú)雙親;如果i>1,則其雙親是結(jié) 點(diǎn)[i/2]
如果2i>n,則節(jié)點(diǎn)i無(wú)左孩子(節(jié)點(diǎn)i為葉子節(jié)點(diǎn));否則其左孩 子是節(jié)點(diǎn)2i。
如果2i+1>n,則節(jié)點(diǎn)i無(wú)右孩子;否則其右孩子是節(jié)點(diǎn)2i+1。
6、二叉樹(shù)的實(shí)現(xiàn)
二叉樹(shù)有兩種實(shí)現(xiàn)方式:數(shù)組和鏈表。
三、二叉樹(shù)的遍歷
二叉樹(shù)有3種遍歷:
前序遍歷:規(guī)則是若二叉樹(shù)為空,則空操作返回,否則先訪問(wèn)根節(jié)點(diǎn),然后前序遍歷左子樹(shù),再前序遍歷右子樹(shù)
中序遍歷:規(guī)則是若樹(shù)為空,則空操作返回,否則從根節(jié)點(diǎn)開(kāi)始(注意并不是先訪問(wèn)根節(jié)點(diǎn)),中序遍歷根節(jié)點(diǎn)的左子樹(shù),然后是訪問(wèn)根節(jié)點(diǎn),最后中序遍歷右子樹(shù)
后序遍歷:規(guī)則是若樹(shù)為空,則空操作返回,否則從左到右先葉子后節(jié)點(diǎn)的方式遍歷訪問(wèn)左右子樹(shù),最后是訪問(wèn)根節(jié)點(diǎn)
二叉樹(shù)的遍歷可以用遞歸和棧來(lái)實(shí)現(xiàn)。遞歸實(shí)現(xiàn)很簡(jiǎn)單,但是棧實(shí)現(xiàn)也需要知道。
1.遞歸
/**
* 遞歸遍歷
*
* @param root 根節(jié)點(diǎn)
* @param type 遍歷方式:0代表前序,1代表中序,2代表后序
*/
public void ergodicRecursion(Node root, int type) {
if (root == null) {
return;
}
if (type == PREORDER) {
ToolShow.log("前序:" + root.toString());
}
ergodicRecursion(root.left, type);
if (type == INORDER) {
ToolShow.log("中序:" + root.toString());
}
ergodicRecursion(root.right, type);
if (type == AFTERORDER) {
ToolShow.log("后序:" + root.toString());
}
}
2.棧
/**
* 用棧遍歷
*
* @param curr 當(dāng)前節(jié)點(diǎn)
* @param type 遍歷方式:0代表前序,1代表中序,2代表后序
*/
public void ergodicStack(Node curr, int type) {
//存放節(jié)點(diǎn)
Stack> stack = new Stack<>();
//記錄已經(jīng)添加過(guò)的節(jié)點(diǎn)
List> nodeList = new ArrayList();
stack.push(curr);
nodeList.add(curr);
while (curr != null) {
//第一次遞歸之前:只執(zhí)行一次
if (type == PREORDER && !nodeList.contains(curr.left) && !nodeList.contains(curr.right)) {
ToolShow.log("前序:" + curr.data);
}
//相當(dāng)于第一次遞歸:已經(jīng)添加過(guò)的節(jié)點(diǎn)不能重復(fù)添加
if (curr.left != null && !nodeList.contains(curr.left)) {
curr = curr.left;
stack.push(curr);
nodeList.add(curr);
} else {
//第二次遞歸之前:只執(zhí)行一次
if (type == INORDER && !nodeList.contains(curr.right)) {
ToolShow.log("中序:" + curr.data);
}
//相當(dāng)于第二次遞歸
if (curr.right != null && !nodeList.contains(curr.right)) {
curr = curr.right;
stack.push(curr);
nodeList.add(curr);
//兩次遞歸結(jié)束
} else {
if (type == AFTERORDER) {
ToolShow.log("后序:" + curr.data);
}
stack.pop();
curr = stack.isEmpty() ? null : stack.lastElement();
}
}
}
}
四、樹(shù)的轉(zhuǎn)換
1.樹(shù)轉(zhuǎn)二叉樹(shù)
加線。在所有兄弟節(jié)點(diǎn)之間就加一條連線。
去線。對(duì)樹(shù)中每一個(gè)節(jié)點(diǎn),只保留它與第一個(gè)孩子節(jié)點(diǎn)的連線,刪除它與其他孩子節(jié)點(diǎn)之間的連線。
層次調(diào)整。以樹(shù)的根節(jié)點(diǎn)為軸心,將整棵樹(shù)順時(shí)針旋轉(zhuǎn)一定的角度,使之結(jié)構(gòu)層次分明。注意第一個(gè)孩子是二叉樹(shù)節(jié)點(diǎn)的左孩子,兄弟轉(zhuǎn)換過(guò)來(lái)的孩子是節(jié)點(diǎn)的右孩子。
2.森林轉(zhuǎn)二叉樹(shù)
把每棵樹(shù)轉(zhuǎn)為二叉樹(shù)
第一棵二叉樹(shù)不動(dòng),從第二棵二叉樹(shù)開(kāi)始,依次把后一棵二叉樹(shù)的根節(jié)點(diǎn)作為前一棵二叉樹(shù)的根節(jié)點(diǎn)的右孩子,用線連接起來(lái)。當(dāng)所有的二叉樹(shù)連接起來(lái)后,就得到了右森林轉(zhuǎn)換的二叉樹(shù)。
3.二叉樹(shù)轉(zhuǎn)樹(shù)
加線。若某節(jié)點(diǎn)的左孩子存在,則將這個(gè)左孩子的右孩子、右孩子的右孩子、...,即這個(gè)左孩子的n個(gè)右孩子作為此節(jié)點(diǎn)的孩子。將該節(jié)點(diǎn)與這些右孩子節(jié)點(diǎn)用線連起來(lái)。
去線。刪除原二叉樹(shù)中所有節(jié)點(diǎn)與其右孩子節(jié)點(diǎn)的連線。
層次調(diào)整。使之層次分明。
4.二叉樹(shù)轉(zhuǎn)森林
判斷一顆二叉樹(shù)能轉(zhuǎn)換成一顆樹(shù)還是森林,只要看這顆二叉樹(shù)的根節(jié)點(diǎn)有沒(méi)有右孩子,有就是森林,沒(méi)有就是一棵樹(shù)。轉(zhuǎn)換森林的步驟如下:
從根節(jié)點(diǎn)開(kāi)始,若有右孩子存在,則把與右孩子節(jié)點(diǎn)的連線刪除,再查看分離后的二叉樹(shù),若右孩子存在,則連線刪除...,直到所有右孩子連線都刪除位置,得到分離的二叉樹(shù)。
再將每顆分離的二叉樹(shù)轉(zhuǎn)為樹(shù)即可。
最后
喜歡請(qǐng)點(diǎn)贊,謝謝!
總結(jié)
以上是生活随笔為你收集整理的android自定义绘制二叉树,安卓数据结构04-二叉树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: android自定义模态框,安卓开发自定
- 下一篇: 游戏使用html签名,关于玩游戏的个性签