轉載自:https://www.cnblogs.com/eudiwffe/p/6207196.html
https://blog.csdn.net/weixin_38629529/article/details/81171245
目錄
4)樹的遍歷(前序、中序、後序、深度遍歷、廣度遍歷、遞歸與非遞歸)
1.二叉樹(Binary Tree)
一個節點分出兩個節點,稱其爲左右子節點;每個子節點又可以分出兩個子節點,這樣遞歸分叉,其形狀很像一顆倒着的樹。
二叉樹限制了每個節點最多有兩個子節點,沒有子節點的節點稱爲葉子。
二叉樹引導出很多名詞概念:
其中節點B只有一個子節點D;
葉子:D, E, F沒有子節點,被稱爲葉子。
深度: 指的是根節點到該節點的路徑長度,A的深度爲0,D的深度爲2
高度:只有一個節點的樹,高度爲0,非空樹的高度爲從根結點到最遠的葉結點的路徑長度,習慣上將空樹高度定義爲-1。
出度:節點C分出兩子節點,所以C的出度爲2;
入度:C有且只有一個父節點,所以其入度爲1。
出度、入度的概念來源於圖(Graph,一種更加高級複雜的數據結構),二叉樹或者說樹形數據結構也是一類特殊的圖,
二叉樹的根節點入度爲0,葉子節點出度爲0。
2.完全二叉樹:
除了最高層以外,其餘層節點個數都達到最大值,並且最高層節點都優先集中在最左邊。
3.滿二叉樹:
除了最高層有葉子節點,其餘層無葉子,並且非葉子節點都有2個子節點。
滿二叉樹一定是一個完全二叉樹,反之則不然
4.二叉查找樹
二叉查找樹(binary search tree,BST)是一種特殊的二叉樹,相對較小的值保存在左節點中,較大的值保存在右節點中。
二叉查找樹(沒有重複元素)的特徵是:對於樹中的每一個結點,它的左子樹中結點的值都小於該結點的值,而它的右子樹中結點的值都大於該結點的值。
5.二叉查找樹基本方法
轉載自:《Java語言程序設計進階篇》
1)二叉查找樹表示
使用一個鏈式結點的集合來表示二叉樹。每個結點都包含一個數值和兩個稱爲left和right的鏈接,分別指向左孩子和右孩子,如圖所示
節點可以定義爲一個類:E是泛型,表示該節點可以放不同的類型
class TreeNode<E> {
protected E element;
protected TreeNode left;
protected TreeNode right;
public TreeNode(E element) {
this.element = element;
}
}
創建一顆樹:
代碼如下:
TreeNode<Integer> root = new TreeNode<>(60);
root.left = new TreeNode(50);
root.right = new TreeNode(70);
變量root指向樹的根結點。如果樹爲空,那root的值爲null
2)查找一個元素
要在二叉查找樹中查找一個元素,可從根結點開始向下掃描,直到找到一個匹配元素,或者達到一棵空子樹爲止。
該算法在程序清單1中描述。讓current指向根結點,
重複下面的步驟直到current爲null或者元素匹配current.element:
如果element小於current.element,就將current.left賦給current
如果element大於current.element,就將current.right賦給current
如果element等於current.element,就返回true
如果current爲null,那麼子樹爲空且該元素不在這棵樹中 返回false
public boolean search(E element){
TreeNode<E> current = root;
while(current!=null){
if (element < current.element){
current = current.left;
}else if(element > current.element){
current = current.right
}else
return true;
}
return false;
}
3) 插入一個元素
爲了在BST中插入一個元素,需要確定在樹中插入元素的位置。關鍵思路是確定新結點的父結點所在的位置。
若當前樹不爲空,尋找新元素結點的父結點位置。 如果新元素小於父元素值,設置爲左子節點,大於則設置爲右子節點。
4)樹的遍歷
樹的遍歷(tree traversal)就是訪問樹中每個結點一次且只有一次的過程。
中序(inorder)、前序(preorder)、後序(postorder)、深度優先(depth-first)和廣度優先(breadth-first)等遍歷方法。
A 中序遍歷(inorder traversal)法
首先遞歸地訪問當前結點的左子樹,然後訪問當前結點,最後遞歸地訪問該結點的右子樹。中序遍歷法以遞增順序顯示BST中的所有結點。
B 後序遍歷(postorder traversal)法,首先遞歸地訪問當前結點的左子樹,然後遞地訪問該結點的右子樹,最後訪問該結點本身。後序遍歷的一個應用就是找出一個文件系統中目錄的個數。
C 前序遍歷(preorder traversal)法,首先訪問當前結點,然後遞歸地訪問該結點的左子樹,最後遞歸地訪問該結點的右子樹
D 深度優先遍歷法與前序遍歷法相同。
E 廣度優先遍歷法逐層訪問樹中的結點。首先訪問根結點,然後從左往右訪問根結點的所有子結點,再從左往右訪問根結點的所有孫子結點,以此類推。
public class TreeNode {
protected int data;
protected TreeNode left;
protected TreeNode right;
public TreeNode(int data) {
this.data = data;
}
/**遞歸 就是有調用自己————————————*/
/**前序遞歸遍歷*/
public static void preOrder(TreeNode root){
if (root != null){
System.out.print(root.data+"\t");
preOrder(root.left);
preOrder(root.right);
}
}
/**中序遞歸遍歷*/
public static void inOrder(TreeNode root){
if (root != null){
inOrder(root.left);
System.out.print(root.data+"\t");
inOrder(root.right);
}
}
/**後序遞歸遍歷*/
public static void postOrder(TreeNode root){
if (root != null){
postOrder(root.left);
postOrder(root.right);
System.out.print(root.data+"\t");
}
}
/**非遞歸-----------非遞歸寫法一定會用到棧-------------------*/
// 如何寫非遞歸代碼呢?
// 一句話:讓代碼跟着思維走。我們的思維是什麼?思維就是中序遍歷的路徑。
// 首先,我們遍歷左子樹,邊遍歷邊打印,並把根節點存入棧中,
// 以後需藉助這些節點進入右子樹開啓新一輪的循環。
// 接下來就是:出棧,根據棧頂節點進入右子樹。
/**前序非遞歸遍歷*/
public static void preOrderNoRe(TreeNode root){
Stack<TreeNode> s = new Stack<>();
while (root != null || !s.empty()) {
//邊遍歷 邊打印 將根節點存入棧中
while (root !=null){
System.out.print(root.data+"\t");
s.push(root);
root = root.left;
}
if (!s.empty()){
root = s.pop();
root = root.right;
}
}
}
// 中序遍歷非遞歸
public static void inOrderNoRe(TreeNode root) {
Stack<TreeNode> s = new Stack<TreeNode>();
while (root != null || !s.empty()) {
while (root != null) {
s.push(root);
root = root.left;
}
if (!s.empty()) {
root = s.pop();
System.out.print(root.data+"\t");
root = root.right;
}
}
}
// 後序遍歷非遞歸
public static void postOrderNoRe(TreeNode root) {
Stack<TreeNode> s = new Stack<TreeNode>();
Stack<Integer> s2 = new Stack<Integer>();
Integer i = new Integer(1);
while (root != null || !s.empty()) {
while (root != null) {
s.push(root);
s2.push(new Integer(0));
root = root.left;
}
while (!s.empty() && s2.peek().equals(i)) {
s2.pop();
System.out.print(s.pop().data+"\t");
}
if (!s.empty()) {
s2.pop();
s2.push(new Integer(1));
root = s.peek();
root = root.right;
}
}
}
}
5)刪除BST中的一個元素