聲明:單純的從零開始,自己的理解記憶一些東西。雖然從零開始但是隻寫自己不太記得的。什麼什麼是父節點子節點就懶得打字了。
樹
- 樹基本定義:一種非線性的數據結構,有且只有一個節點沒有直接前驅(父節點),這個就是根節點,樹本身沒有限制有多少個直接後記(子節點),如果做了限制2,那就是二叉樹了,個人感覺把樹反過來- -更像個“樹”,畢竟根在地上。
- 節點的度:一個節點所包含的子樹個數(圈底下有幾個線),比如D的度是3。樹的度即爲 最大的節點度。
- 節點的層數:從根開始,根是1層,一次加。節點的最大層數就是樹的深度。此樹深度4。
二叉樹
- 倆個常見的特殊二叉樹:滿二叉樹,完全二叉樹。滿的必須最後一層滿,完全的最後一次可以不滿,但是從左到右必須連貫。滿二叉樹是完全二叉樹的子類。
滿二叉樹的性質:
1、一顆樹深度爲h,最大層數爲k,深度與最大層數相同,k=h;
2、葉子數爲2h;
3、第k層的結點數是:2k-1;
4、總結點數是:2k-1,且總節點數一定是奇數。
完全二叉樹的性質:對於一個順序存儲包含n個節點,對於任意一個節點m
1、如果m!=1,父節點的編號爲m/2;
2、如果2*m n,那麼節點左子樹根節點編號爲2*m ,如果2*m >n,則他無左右子樹。
3、如果2*m+1 n,那麼節點右子樹根節點編號爲2*m+1 ,如果2*m >n,則他無左右子樹。
4、深度:[ ]+1 ,1是因爲根節點。
遍歷
-先序遍歷:根左右,從根開始,從上到下,從左到右。ABDECF
-中序遍歷:左根右,從左面開始,向根靠攏,最後走右。DBEAFC
-後序遍歷:左右根,把左邊倒着弄完,再把右邊倒着弄完,加個根。 DEBFCA
遇到題目,無非是知道倆個求另一個,知道倆個情況下,必然知道先後,那麼必然知道根節點!如果另一個是中序,那麼以中序的根節點左右拆分左右子樹繼續層層畫就好了。
比如上面,知道先序和中序。
1、根據先序,知道根節點爲A,然後知道根據中序,拆分倆顆左右子樹DBE,FC,同時根據中序,把先序也去掉A,變成BDE ,CF 。
2、再根據先序的特點根在最左面。那麼B,C爲下一層的根節點。
3、依次重複下去畫出二叉樹,如果知道中後,那麼就找最右邊的根節點就行了。
另一種就是知道先後,這種這種情況並不能完全的求出所有情況的二叉樹中序遍歷。因爲由前序和後序並不能完全確定一顆樹。但是,如果已知是滿二叉樹或者完全二叉樹的話,我想是可以的。
1、前序的第一個節點和後序的最後一個節點一定是根節點,
2、如果前序的第二個節點與後序的倒數第二個節點不相等,,那麼前序的第二節點是根的左子樹B,後序的倒數第二節點是根的右子樹C。(但是 如果前序的第二個節點與後序的倒數第二個節點相等,那就不能確定到底是左子樹還是右子樹了,因爲缺省一個子樹中左與左中,中右與右中都會相等。所以這就需要題目有要求該樹的特徵了)
3、然後再後序中找到左子樹根節點,在後序中從左子樹根節點結合前序左子樹根節點開始遞歸上述得到根節點左子樹的子樹, 同樣在前序中找到右子樹根節點,在前序中從右子樹根節點結合後序右子樹根節點開始遞歸上述得到根節點右子樹的子樹。
參考:遍歷具體方法
java二叉樹數據結構,以及練習,看書敲得。
import java.util.Scanner;
class CBTType //定義二叉樹結點類型
{
String data; //元素數據
CBTType left; //左子樹結點指針
CBTType right; //右子樹結點指針
}
public class C2_5 {
static final int MAXLEN=20;
static Scanner input=new Scanner(System.in);
CBTType InitTree() //初始化二叉樹的根
{
CBTType node;
if((node=new CBTType())!=null) //申請內存
{
System.out.printf("請先輸入一個根結點數據:\n");
node.data=input.next();
node.left=null;
node.right=null;
if(node!=null) //如果二叉樹根結點不爲空
{
return node;
}
else
{
return null;
}
}
return null;
}
void AddTreeNode(CBTType treeNode) //添加結點
{
CBTType pnode,parent;
String data;
int menusel;
if((pnode=new CBTType())!=null) //分配內存
{
System.out.printf("輸入二叉樹結點數據:\n");
pnode.data=input.next();
pnode.left=null; //設置左右子樹爲空
pnode.right=null;
System.out.printf("輸入該結點的父結點數據:");
data=input.next();
parent=TreeFindNode(treeNode,data); //查找指定數據的結點
if(parent==null) //如果未找到
{
System.out.printf("未找到該父結點!\n");
pnode=null; //釋放創建的結點內存
return;
}
System.out.printf("1.添加該結點到左子樹\n2.添加該結點到右子樹\n");
do
{
menusel=input.nextInt(); //輸入選擇項
if(menusel==1 || menusel==2)
{
if(parent==null)
{
System.out.printf("不存在父結點,請先設置父結點!\n");
}
else
{
switch(menusel)
{
case 1: //添加到左結點
if(parent.left!=null) //左子樹不爲空
{
System.out.printf("左子樹結點不爲空!\n");
}
else
{
parent.left=pnode;
}
break;
case 2: //添加到右結點
if( parent.right!=null) //右子樹不爲空
{
System.out.printf("右子樹結點不爲空!\n");
}
else
{
parent.right=pnode;
}
break;
default:
System.out.printf("無效參數!\n");
}
}
}
}while(menusel!=1 && menusel!=2);
}
}
CBTType TreeFindNode(CBTType treeNode,String data) //查找結點
{
CBTType ptr;
if(treeNode==null)
{
return null;
}
else
{
if(treeNode.data.equals(data))
{
return treeNode;
}
else
{ // 分別向左右子樹遞歸查找
if((ptr=TreeFindNode(treeNode.left,data))!=null)
{
return ptr;
}
else if((ptr=TreeFindNode(treeNode.right, data))!=null)
{
return ptr;
}
else
{
return null;
}
}
}
}
CBTType TreeLeftNode(CBTType treeNode) //獲取左子樹
{
if(treeNode!=null)
{
return treeNode.left; //返回值
}
else
{
return null;
}
}
CBTType TreeRightNode(CBTType treeNode) //獲取右子樹
{
if(treeNode!=null)
{
return treeNode.right; //返回值
}
else
{
return null;
}
}
int TreeIsEmpty(CBTType treeNode) //判斷空樹
{
if(treeNode!=null)
{
return 0;
}
else
{
return 1;
}
}
int TreeDepth(CBTType treeNode) //計算二叉樹深度
{
int depleft,depright;
if(treeNode==null)
{
return 0; //對於空樹,深度爲0
}
else
{
depleft = TreeDepth(treeNode.left); //左子樹深度 (遞歸調用)
depright = TreeDepth(treeNode.right); //右子樹深度 (遞歸調用)
if(depleft>depright)
{
return depleft + 1;
}
else
{
return depright + 1;
}
}
}
void ClearTree(CBTType treeNode) // 清空二叉樹
{
if(treeNode!=null)
{
ClearTree(treeNode.left); //清空左子樹
ClearTree(treeNode.right); //清空右子樹
treeNode=null; //釋放當前結點所佔內存
// treeNode=null;
}
}
void TreeNodeData(CBTType p) //顯示結點數據
{
System.out.printf("%s ",p.data); //輸出結點數據
}
void LevelTree(CBTType treeNode) //按層遍歷
{
CBTType p;
CBTType[] q=new CBTType[MAXLEN]; //定義一個順序棧
int head=0,tail=0;
if(treeNode!=null) //如果隊首指針不爲空
{
tail=(tail+1)%MAXLEN; //計算循環隊列隊尾序號
q[tail] = treeNode; //將二叉樹根指針進隊
}
while(head!=tail) //隊列不爲空,進行循環
{
head=(head+1)%MAXLEN; //計算循環隊列的隊首序號
p=q[head]; //獲取隊首元素
TreeNodeData(p); //處理隊首元素
if(p.left!=null) //如果結點存在左子樹
{
tail=(tail+1)%MAXLEN; //計算循環隊列的隊尾序號
q[tail]=p.left; //將左子樹指針進隊
}
if(p.right!=null) //如果結點存在右子樹
{
tail=(tail+1)%MAXLEN; //計算循環隊列的隊尾序號
q[tail]=p.right; //將右子樹指針進隊
}
}
}
void DLRTree(CBTType treeNode) //先序遍歷
{
if(treeNode!=null)
{
TreeNodeData(treeNode); //顯示結點的數據
DLRTree(treeNode.left);
DLRTree(treeNode.right);
}
}
void LDRTree(CBTType treeNode) //中序遍歷
{
if(treeNode!=null)
{
LDRTree(treeNode.left); //中序遍歷左子樹
TreeNodeData(treeNode); //顯示結點數據
LDRTree(treeNode.right); //中序遍歷右子樹
}
}
void LRDTree(CBTType treeNode) //後序遍歷
{
if(treeNode!=null)
{
LRDTree(treeNode.left); //後序遍歷左子樹
LRDTree(treeNode.right); //後序遍歷右子樹
TreeNodeData(treeNode); //顯示結點數據
}
}
public static void main(String[] args) {
CBTType root=null; //root爲指向二叉樹根結點的指針
int menusel;
C2_5 t=new C2_5();
//設置根元素
root=t.InitTree();
//添加結點
do{
System.out.printf("請選擇菜單添加二叉樹的結點\n");
System.out.printf("0.退出\t"); //顯示菜單
System.out.printf("1.添加二叉樹的結點\n");
menusel=input.nextInt();
switch(menusel)
{
case 1: //添加結點
t.AddTreeNode(root);
break;
case 0:
break;
default:
;
}
}while(menusel!=0);
//遍歷
do{
System.out.printf("請選擇菜單遍歷二叉樹,輸入0表示退出:\n");
System.out.printf("1.先序遍歷DLR\t"); //顯示菜單
System.out.printf("2.中序遍歷LDR\n");
System.out.printf("3.後序遍歷LRD\t");
System.out.printf("4.按層遍歷\n");
menusel=input.nextInt();
switch(menusel)
{
case 0:
break;
case 1: //先序遍歷
System.out.printf("\n先序遍歷DLR的結果:");
t.DLRTree(root);
System.out.printf("\n");
break;
case 2: //中序遍歷
System.out.printf("\n中序LDR遍歷的結果:");
t.LDRTree(root);
System.out.printf("\n");
break;
case 3: //後序遍歷
System.out.printf("\n後序遍歷LRD的結果:");
t.LRDTree(root);
System.out.printf("\n");
break;
case 4: //按層遍歷
System.out.printf("\n按層遍歷的結果:");
t.LevelTree(root);
System.out.printf("\n");
break;
default:;
}
}while(menusel!=0);
//深度
System.out.printf("\n二叉樹深度爲:%d\n",t.TreeDepth(root));
t.ClearTree(root); //清空二叉樹
root=null;
}
}