1、基本概念:
1) 樹有很多種,每個節點最多隻能有兩個子節點的一種形式稱爲二叉樹。
2)二叉樹的子節點分爲左節點和右節點
3)如果該二叉樹的所有葉子節點都在最後一層,並且結點總數= 2^n -1 , n 爲層數,則我們稱爲滿二叉樹。
4)如果該二叉樹的所有葉子節點都在最後一層或者倒數第二層,而且最後一層的葉子節點在左邊連續,倒數第二層的葉子節點在右邊連續,我們稱爲完全二叉樹。
樹的常用術語(結合示意圖理解):
1)節點
2)根節點
3)父節點
4)子節點
5)葉子節點 (沒有子節點的節點)
6)節點的權(節點值)
7)路徑(從root節點找到該節點的路線)
8)層
9)子樹
10)樹的高度(最大層數)
11)森林 :多顆子樹構成森林
2.二叉樹的遍歷:
前序遍歷: 先輸出父節點,再遍歷左子樹和右子樹
中序遍歷: 先遍歷左子樹,再輸出父節點,再遍歷右子樹
後序遍歷: 先遍歷左子樹,再遍歷右子樹,最後輸出父節點
小結: 看輸出父節點的順序,就確定是前序,中序還是後序
實際上,二叉樹的前、中、後序遍歷就是一個遞歸的過程
3.代碼實現:
//先創建Node 節點
class Node{
private int no;
private String name;
private Node left;//默認null
private Node right;//默認null
public Node(int no , String name){
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
@Override
public String toString() {
return "Node [no=" + no + ", name=" + name + "]";
}
//遞歸刪除結點
//1.如果刪除的節點是葉子節點,則刪除該結點
//2.如果刪除的節點是非葉子節點,則刪除該子樹
public void delNode(int no){
//思路
/*
* 1. 因爲我們的二叉樹是單向的,所以我們是判斷當前結點的子結點是否需要刪除結點,而不能去判斷當前這個結點是不是需要刪除結點.
2. 如果當前結點的左子結點不爲空,並且左子結點 就是要刪除結點,就將this.left = null; 並且就返回(結束遞歸刪除)
3. 如果當前結點的右子結點不爲空,並且右子結點 就是要刪除結點,就將this.right= null ;並且就返回(結束遞歸刪除)
4. 如果第2和第3步沒有刪除結點,那麼我們就需要向左子樹進行遞歸刪除
5. 如果第4步也沒有刪除結點,則應當向右子樹進行遞歸刪除.
*/
//2. 如果當前結點的左子結點不爲空,並且左子結點 就是要刪除結點,就將this.left = null; 並且就返回(結束遞歸刪除)
if(this.left != null && this.left.no == no){
this.left = null;
return;
}
//3.如果當前結點的右子結點不爲空,並且右子結點 就是要刪除結點,就將this.right= null ;並且就返回(結束遞歸刪除)
if(this.right != null && this.right.no == no){
this.right = null;
return;
}
//4.我們就需要向左子樹進行遞歸刪除
if(this.left != null){
this.left.delNode(no);
}
//5.則應當向右子樹進行遞歸刪除
if(this.right != null){
this.right.delNode(no);
}
}
//編寫前序遍歷的方法
public void preOrder(){
System.out.println(this);
//遞歸向左子樹前序遍歷
if(this.left !=null){
this.left.preOrder();
}
//遞歸向右子樹前序遍歷
if(this.right !=null){
this.right.preOrder();
}
}
//中序遍歷
public void infixOrder(){
//遞歸向左子樹中序遍歷
if(this.left !=null){
this.left.infixOrder();
}
//輸出父節點
System.out.println(this);
//遞歸向右子樹中序遍歷
if(this.right !=null){
this.right.infixOrder();
}
}
//後序遍歷
public void postOrder(){
//遞歸向左子樹後序遍歷
if(this.left !=null){
this.left.postOrder();
}
//遞歸向右子樹中序遍歷
if(this.right !=null){
this.right.postOrder();
}
//輸出父節點
System.out.println(this);
}
//前序遍歷查找
public Node preSearch(int no){
System.out.println("進入前序遍歷");
//比較當前結點是不是
if(this.no == no){
return this;
}
//1.則判斷當前結點的左子節點是否爲空,如果不爲空,則遞歸前序查找
//2.如果左遞歸前序查找,找到結點,則返回
Node resNode = null;
if(this.left !=null){
resNode = this.left.preSearch(no);
}
//說明找到了
if(resNode != null){
return resNode;
}
//1.左遞歸前序查找,找到結點,則返回,否繼續判斷,
//2.當前的結點的右子節點是否爲空,如果不空,則繼續向右遞歸前序查找
if(this.right !=null){
resNode = this.right.preSearch(no);
}
return resNode;
}
//中序遍歷查找
public Node infixSearch(int no){
//1.則判斷當前結點的左子節點是否爲空,如果不爲空,則遞歸前序查找
//2.如果左遞歸前序查找,找到結點,則返回
Node resNode = null;
if(this.left !=null){
resNode = this.left.infixSearch(no);
}
//說明找到了
if(resNode != null){
return resNode;
}
System.out.println("進入中序遍歷");
//比較當前結點是不是
if(this.no == no){
return this;
}
//1.左遞歸前序查找,找到結點,則返回,否繼續判斷,
//2.當前的結點的右子節點是否爲空,如果不空,則繼續向右遞歸前序查找
if(this.right !=null){
resNode = this.right.infixSearch(no);
}
return resNode;
}
//後序遍歷查找
public Node postSearch(int no){
//1.則判斷當前結點的左子節點是否爲空,如果不爲空,則遞歸前序查找
//2.如果左遞歸前序查找,找到結點,則返回
Node resNode = null;
if(this.left !=null){
resNode = this.left.postSearch(no);
}
//說明找到了
if(resNode != null){
return resNode;
}
//1.左遞歸前序查找,找到結點,則返回,否繼續判斷,
//2.當前的結點的右子節點是否爲空,如果不空,則繼續向右遞歸前序查找
if(this.right !=null){
resNode = this.right.postSearch(no);
}
System.out.println("進入後序遍歷");
//比較當前結點是不是
if(this.no == no){
return this;
}
return resNode;
}
}
//創建BinaryTree二叉樹
class BinaryTree{
private Node root;
public void setRoot(Node root){
this.root = root;
}
//刪除結點
public void delNode(int no){
if(root != null){
//如果只有一個root結點, 這裏立即判斷root是不是就是要刪除結點
if(root.getNo() == no){
root = null;
}else{
//遞歸刪除
root.delNode(no);
}
}else{
System.out.println("空樹,不能刪除~");
}
}
//前序遍歷
public void preOrder(){
if(this.root != null){
this.root.preOrder();
}else{
System.out.println("二叉樹爲空,無法遍歷");
}
}
//中序遍歷
public void infixOrder(){
if(this.root != null){
this.root.infixOrder();
}else{
System.out.println("二叉樹爲空,無法遍歷");
}
}
//後序遍歷
public void postOrder(){
if(this.root != null){
this.root.postOrder();
}else{
System.out.println("二叉樹爲空,無法遍歷");
}
}
//前序查找
public Node preSearch(int no){
if(root != null){
return root.preSearch(no);
}else{
return null;
}
}
//中序查找
public Node infixSearch(int no){
if(root != null){
return root.infixSearch(no);
}else{
return null;
}
}
//後序查找
public Node postSearch(int no){
if(root != null){
return root.postSearch(no);
}else{
return null;
}
}
}
//測試
public static void main(String[] args) {
//創建一個二叉樹
BinaryTree binaryTree = new BinaryTree();
//
Node root = new Node(1,"趙");
Node node2 = new Node(2,"錢");
Node node3 = new Node(3,"孫");
Node node4 = new Node(4,"李");
Node node5 = new Node(5,"王");
Node node6 = new Node(6,"王");
Node node7 = new Node(7,"王");
//我們先手動創建該二叉樹,後面我們學習遞歸的方式創建二叉樹
root.setLeft(node2);
root.setRight(node3);
node2.setRight(node5);
node2.setLeft(node4);
node3.setRight(node7);
node3.setLeft(node6);
binaryTree.setRoot(root);
//System.out.println("前序遍歷"); // 1,2,3,5,4
// binaryTree.preOrder();
System.out.println("中序遍歷"); // 2,1,5,3,4
binaryTree.infixOrder();
//System.out.println("後序遍歷"); // 2,5,4,3,1
//binaryTree.postOrder();
//測試刪除
//System.out.println("刪除前,前序遍歷");
//binaryTree.preOrder();
// binaryTree.delNode(5);
// System.out.println("刪除後,前序遍歷");
// binaryTree.preOrder();//1,2,3,4
}