本文僅作爲二叉樹的基礎入門
一、什麼是二叉樹
簡介
- 每個節點最多只能有兩個子節點的一種形式稱爲二叉樹。
- 二叉樹的子節點分爲左節點和右節點。
- 如果該二叉樹的所有葉子節點都在最後一層,並且結點總數= 2^n -1 , n 爲層數,則我們稱爲滿二叉樹。
- 如果該二叉樹的所有葉子節點都在最後一層或者倒數第二層,而且最後一層的葉子節點在左邊連續,倒數第二層的葉子節點在右邊連續,我們稱爲完全二叉樹。
類型
- 完全二叉樹
- 滿二叉樹
- 平衡二叉樹(AVL樹)
相關術語
樹的結點(node):包含一個數據元素及若干指向子樹的分支;
孩子結點(child node):結點的子樹的根稱爲該結點的孩子;
雙親結點:B 結點是A 結點的孩子,則A結點是B 結點的雙親;
兄弟結點:同一雙親的孩子結點; 堂兄結點:同一層上結點;
祖先結點: 從根到該結點的所經分支上的所有結點
子孫結點:以某結點爲根的子樹中任一結點都稱爲該結點的子孫
結點層:根結點的層定義爲1;根的孩子爲第二層結點,依此類推;
樹的深度:樹中最大的結點層
結點的度:結點子樹的個數
樹的度: 樹中最大的結點度。
葉子結點:也叫終端結點,是度爲 0 的結點;
分枝結點:度不爲0的結點;
有序樹:子樹有序的樹,如:家族樹;
無序樹:不考慮子樹的順序;
二、實現一個二叉樹
搞清楚了什麼是二叉樹,先來創建一個二叉樹
1、創建二叉樹
- 創建一個節點,節點中需要包含兩個指針指向左子結點和右子結點
class StudentNode {
private int id;
private String name;
private StudentNode left;
private StudentNode right;
public StudentNode(int id, String name) {
this.id = id;
this.name = name;
}
// Get And Set
@Override
public String toString() {
return "StudentNode{id=" + id +", name='" + name+"'}";
}
}
- 創建二叉樹,其中有一個根節點(root)
class BinaryTree {
/**
* 根節點
*/
private StudentNode root;
public void setRoot(StudentNode root) {
this.root = root;
}
}
- main方法,向二叉樹中添加數據
public static void main(String[] args) {
//創建二叉樹
BinaryTree binaryTree = new BinaryTree();
//創建向二叉樹中添加的節點
StudentNode root = new StudentNode(1,"aaa");
StudentNode node2 = new StudentNode(2,"bbb");
StudentNode node3 = new StudentNode(3,"ccc");
StudentNode node4 = new StudentNode(4,"ddd");
StudentNode node5 = new StudentNode(5,"eee");
//手動創建二叉樹
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
binaryTree.setRoot(root);
}
2、遍歷二叉樹
思路分析
前序遍歷: 先輸出父節點,再遍歷左子樹和右子樹
中序遍歷: 先遍歷左子樹,再輸出父節點,再遍歷右子樹
後序遍歷: 先遍歷左子樹,再遍歷右子樹,最後輸出父節點
小結: 看輸出父節點的順序,就確定是前序,中序還是後序
代碼實現
//節點
class StudentNode {
/**
* 前序遍歷
*/
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);
}
}
//二叉樹
class BinaryTree {
/**
* 前序遍歷
*/
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("二叉樹爲空,不可遍歷");
}
}
2、查找二叉樹中的某個節點
//學生節點
class StudentNode {
/**
* 前序遍歷查找
* @param id 學生id
* @return
*/
public StudentNode preOrderSearch(int id){
System.out.println("進入前序");
//1.比較當前節點
if(this.id == id){
return this;
}
StudentNode resultNode = null;
//2.判斷左子節點是否爲空,不爲空則繼續向左子節點查找
if(this.left != null){
resultNode = this.left.preOrderSearch(id);
}
//說明在左子樹找到
if(resultNode != null){
return resultNode;
}
//3.判斷右子節點
if(this.right != null){
resultNode = this.right.preOrderSearch(id);
}
return resultNode;
}
/**
* 中序遍歷查找
* @param id 學生id
* @return
*/
public StudentNode infixOrderSearch(int id){
StudentNode resultNode = null;
//1.判斷左子節點
if(this.left != null){
resultNode = this.left.infixOrderSearch(id);
}
//說明在左子樹找到
if(resultNode != null){
return resultNode;
}
System.out.println("進入中序");
//2.比較當前節點
if(this.id == id){
return this;
}
//3.判斷右子節點
if(this.right != null){
resultNode = this.right.infixOrderSearch(id);
}
return resultNode;
}
/**
* 後序遍歷查找
* @param id 學生id
* @return
*/
public StudentNode postOrderSearch(int id){
StudentNode resultNode = null;
//1.判斷左子節點
if(this.left != null){
resultNode = this.left.postOrderSearch(id);
}
//說明在左子樹找到
if(resultNode != null){
return resultNode;
}
//2.判斷右子節點
if(this.right != null){
resultNode = this.right.postOrderSearch(id);
}
//說明在右子樹找到
if(resultNode != null){
return resultNode;
}
System.out.println("進入後序");
//3.比較當前節點
if(this.id == id){
return this;
}
return resultNode;
}
}
//二叉樹
class BinaryTree {
/**
* 前序遍歷查找
* @param id
* @return
*/
public StudentNode preOrderSearch(int id){
if(root != null){
return root.preOrderSearch(id);
}else {
return null;
}
}
/**
* 中序遍歷查找
* @param id
* @return
*/
public StudentNode infixOrderSearch(int id){
if(root != null){
return root.infixOrderSearch(id);
}else {
return null;
}
}
/**
* 後序遍歷查找
* @param id
* @return
*/
public StudentNode postOrderSearch(int id){
if(root != null){
return root.postOrderSearch(id);
}else {
return null;
}
}
}
3、刪除二叉樹中的某個節點
要求
如果刪除的節點是葉子節點,則刪除該節點
如果刪除的節點是非葉子節點,則刪除該子樹.
代碼實現
/**
* 學生節點
*/
class StudentNode {
/**
* 節點刪除
* @param id
*/
public void deleteNode(int id){
//1.如果當前節點的左子節點不爲空,就將左子節點刪除
if(this.left != null && this.left.id == id){
this.left = null;
return;
}
//2.如果當前節點的右子節點不爲空,就將右子節點刪除
if(this.right != null && this.right.id == id){
this.right = null;
return;
}
//3.將左子樹遞歸刪除
if(this.left!= null){
this.left.deleteNode(id);
}
//4.將右子樹遞歸刪除
if(this.right != null){
this.right.deleteNode(id);
}
}
}
/**
* 二叉樹
*/
class BinaryTree {
/**
* 刪除節點
* @param id
*/
public void deleteNode(int id){
if(root != null){
//需要先判斷root是不是你要刪除的節點
if(root.getId() == id){
root = null;
}
else{
root.deleteNode(id);
}
}else{
System.out.println("root is empty");
}
}
}
三、附完整代碼
/**
* 二叉樹
*/
public class BinaryTreeDemo {
public static void main(String[] args) {
//創建二叉樹
BinaryTree binaryTree = new BinaryTree();
//創建向二叉樹中添加的節點
StudentNode root = new StudentNode(1,"aaa");
StudentNode node2 = new StudentNode(2,"bbb");
StudentNode node3 = new StudentNode(3,"ccc");
StudentNode node4 = new StudentNode(4,"ddd");
StudentNode node5 = new StudentNode(5,"eee");
//手動創建二叉樹
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
binaryTree.setRoot(root);
// // 測試遍歷
// System.out.println("前序遍歷");
// binaryTree.preOrder();
//
// System.out.println("中序遍歷");
// binaryTree.infixOrder();
//
// System.out.println("後序遍歷");
// binaryTree.postOrder();
//測試遍歷查找
// System.out.println("前序遍歷查找");
// StudentNode resNode = binaryTree.preOrderSearch(5);
// if (resNode!=null){
// System.out.println(resNode);
// }
// else{
// System.out.println("查找失敗");
// }
//
// System.out.println("中序遍歷查找");
// resNode = binaryTree.infixOrderSearch(5);
// if (resNode!=null){
// System.out.println(resNode);
// }
// else{
// System.out.println("查找失敗");
// }
//
// System.out.println("後序遍歷查找");
// resNode = binaryTree.postOrderSearch(5);
// if (resNode!=null){
// System.out.println(resNode);
// }
// else{
// System.out.println("查找失敗");
// }
//測試刪除節點
System.out.println("刪除前二叉樹");
binaryTree.preOrder();
binaryTree.deleteNode(3);
System.out.println("刪除後二叉樹");
binaryTree.preOrder();
}
}
/**
* 二叉樹
*/
class BinaryTree {
/**
* 根節點
*/
private StudentNode root;
public void setRoot(StudentNode root) {
this.root = root;
}
/**
* 前序遍歷
*/
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("二叉樹爲空,不可遍歷");
}
}
/**
* 前序遍歷查找
* @param id
* @return
*/
public StudentNode preOrderSearch(int id){
if(root != null){
return root.preOrderSearch(id);
}else {
return null;
}
}
/**
* 中序遍歷查找
* @param id
* @return
*/
public StudentNode infixOrderSearch(int id){
if(root != null){
return root.infixOrderSearch(id);
}else {
return null;
}
}
/**
* 後序遍歷查找
* @param id
* @return
*/
public StudentNode postOrderSearch(int id){
if(root != null){
return root.postOrderSearch(id);
}else {
return null;
}
}
/**
* 刪除節點
* @param id
*/
public void deleteNode(int id){
if(root != null){
//需要先判斷root是不是你要刪除的節點
if(root.getId() == id){
root = null;
}
else{
root.deleteNode(id);
}
}else{
System.out.println("root is empty");
}
}
}
/**
* 學生節點
*/
class StudentNode {
private int id;
private String name;
private StudentNode left;
private StudentNode right;
public StudentNode(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public StudentNode getLeft() {
return left;
}
public void setLeft(StudentNode left) {
this.left = left;
}
public StudentNode getRight() {
return right;
}
public void setRight(StudentNode right) {
this.right = right;
}
@Override
public String toString() {
return "StudentNode{id=" + id +", name='" + name+"'}";
}
/**
* 前序遍歷
*/
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);
}
/**
* 前序遍歷查找
* @param id 學生id
* @return
*/
public StudentNode preOrderSearch(int id){
System.out.println("進入前序");
//1.比較當前節點
if(this.id == id){
return this;
}
StudentNode resultNode = null;
//2.判斷左子節點是否爲空,不爲空則繼續向左子節點查找
if(this.left != null){
resultNode = this.left.preOrderSearch(id);
}
//說明在左子樹找到
if(resultNode != null){
return resultNode;
}
//3.判斷右子節點
if(this.right != null){
resultNode = this.right.preOrderSearch(id);
}
return resultNode;
}
/**
* 中序遍歷查找
* @param id 學生id
* @return
*/
public StudentNode infixOrderSearch(int id){
StudentNode resultNode = null;
//1.判斷左子節點
if(this.left != null){
resultNode = this.left.infixOrderSearch(id);
}
//說明在左子樹找到
if(resultNode != null){
return resultNode;
}
System.out.println("進入中序");
//2.比較當前節點
if(this.id == id){
return this;
}
//3.判斷右子節點
if(this.right != null){
resultNode = this.right.infixOrderSearch(id);
}
return resultNode;
}
/**
* 後序遍歷查找
* @param id 學生id
* @return
*/
public StudentNode postOrderSearch(int id){
StudentNode resultNode = null;
//1.判斷左子節點
if(this.left != null){
resultNode = this.left.postOrderSearch(id);
}
//說明在左子樹找到
if(resultNode != null){
return resultNode;
}
//2.判斷右子節點
if(this.right != null){
resultNode = this.right.postOrderSearch(id);
}
//說明在右子樹找到
if(resultNode != null){
return resultNode;
}
System.out.println("進入後序");
//3.比較當前節點
if(this.id == id){
return this;
}
return resultNode;
}
/**
* 節點刪除
* @param id
*/
public void deleteNode(int id){
//1.如果當前節點的左子節點不爲空,就將左子節點刪除
if(this.left != null && this.left.id == id){
this.left = null;
return;
}
//2.如果當前節點的右子節點不爲空,就將右子節點刪除
if(this.right != null && this.right.id == id){
this.right = null;
return;
}
//3.將左子樹遞歸刪除
if(this.left!= null){
this.left.deleteNode(id);
}
//4.將右子樹遞歸刪除
if(this.right != null){
this.right.deleteNode(id);
}
}
}