07.Java數據結構與算法之~二叉樹的查找與刪除
本文是上一篇文章的後續,詳情請點擊該鏈接
二叉樹-查找指定結點
使用前序,中序,後序的方式來查詢指定的結點
前序查找思路:
1.先判斷當前結點是否等於要查找的,如果是相等,則返回當前結點
2.如果不等,則判斷當前結點的左子結點是否爲空,如果不爲空,則遞歸前序查找
3.如果左遞歸前序查找,找到結點,則返回。否則繼續判斷當前結點的右子結點是否爲空,如果不空,則繼續向右遞歸前序
中序查找思路:
1.判斷當前結點的左子結點是否爲空,如果不爲空,則遞歸中序查找
2.如果找到則返回,如果沒找到,就和當前結點比較,如果是則返回當前結點,否則繼續進行右遞歸的中序查找
3.如果右遞歸中序查找找到,就返回,否則返回null
後序查找思路:
1.判斷當前節點的左子結點是否爲空,如果不爲空,則遞歸後序查找
2.如果找到就返回,如果沒有找到,就判斷當前結點的右子結點是否爲空。如果不爲空,則右遞歸進行後序查找,如果找到就返回。
3.如果左右結點都沒有找到,就和當前結點進行比較,找到就返回,否則返回Null。
代碼實現:
補充Tree接口
注:遍歷方法在上一篇文章已經實現了,詳情請點擊上方鏈接,這篇文章就不重複敘述了。
不過在文章的最下面,會把完整的代碼最終再發一次
public interface Tree {
//構建樹
void CreateBinaryTree(Object tree, Object left, Object right);
//先序遍歷
void PreOrder();
//中序遍歷
void InfixOrder();
//後序遍歷
void PostOrder();
//前序查找
Object preOrderSearch(Object root);
//中序查找
Object infixOrderSearch(Object root);
//後序查找
Object postOrder(Object root);
}
BinaryTree實現類
//前序查找
@Override
public Object preOrderSearch(Object root) {
Object res = null;
//判斷二叉樹是否爲空
if(root != null) {
//比較當前是不是
if (this.root == root) {
return this;
}
//判斷當前節點左子結點是否爲空,如果不爲空,則遞歸前序查找
//如果左遞歸找到則返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判斷左遞歸是否找到,找到就返回,沒找到就繼續右遞歸
if(res != null){
return res;
}
//如果左遞歸沒找到,就繼續右遞歸查找
if(this.right != null){
res = right.preOrderSearch(root);
}
}else{
throw new NullPointerException();
}
return res;
}
//中序查找
@Override
public Object infixOrderSearch(Object root) {
Object res = null;
//判斷二叉樹是否爲空
if(root != null) {
//判斷當前節點左子結點是否爲空,如果不爲空,則遞歸前序查找
//如果左遞歸找到則返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判斷左遞歸是否找到,找到就返回,沒找到就繼續比較當前結點
if(res != null){
return res;
}
//比較當前是不是
if (this.root == root) {
return this;
}
//如果左遞歸沒找到,就繼續右遞歸查找
if(this.right != null){
res = right.preOrderSearch(root);
}
}else{
throw new NullPointerException();
}
return res;
}
//後序查找
@Override
public Object postOrderSearch(Object root) {
Object res = null;
//判斷二叉樹是否爲空
if(root != null) {
//左遞歸查找,如果左遞歸找到則返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判斷左遞歸是否找到,找到就返回,沒找到就繼續右遞歸
if(res != null){
return res;
}
//如果左遞歸沒找到,就繼續右遞歸查找
if(this.right != null){
res = right.preOrderSearch(root);
}
//比較當前是不是
if (this.root == root) {
return this;
}
}else{
throw new NullPointerException();
}
return res;
}
//重寫toString
@Override
public String toString() {
return (String) root;
}
測試類
//前序查找
Object preOrderSearch = A.preOrderSearch("E");
System.out.println(preOrderSearch);
//中序查找
Object infixOrderSearch = A.infixOrderSearch("G");
System.out.println(infixOrderSearch);
//後序查找
Object postOrderSearch = A.postOrderSearch("A");
System.out.println(postOrderSearch);
二叉樹-刪除結點
思路:
1.因爲我們的二叉樹是單向的,所以我們是判斷當前節點的子結點是否需要刪除節點,而不能去判斷當前這個結點是不是需要刪除的節點
2.如果當前結點的左子樹不爲空,並且左子結點就是需要刪除的結點,就將this.left=null
3.如果當前結點的右子結點不爲空,並且右子結點就是要刪除的結點,就將this.right=null
4.如果2,3都沒有刪除結點,那麼就需要向左子樹進行遞歸刪除
5.如果左子樹沒有成功,就遞歸右子樹
補充Tree接口
//刪除結點
void remove(Object root);
BinaryTree實現類
//遞歸刪除結點
//1.如果刪除的結點是葉子結點,則刪除該結點
//2.如果刪除的結點是非葉子結點,則刪除該子樹
@Override
public void remove(Object root) {
//判斷二叉樹是否爲空
if(root != null){
//如果當前結點的左子結點不爲空,並且左子結點就是要刪除的結點,那麼就置空並返回
if(left != null && left.root == root){
left = null;
return;
}
//如果當前結點的右子結點不爲空,並且右子結點就是要刪除的結點,那麼就置空並返回
if(right != null && right.right == root){
right = null;
return;
}
//如果都沒有就向左子樹遞歸進行刪除
if(left != null){
left.remove(root);
}
//如果左子樹遞歸沒刪除就向右子樹遞歸刪除
if(right != null){
right.remove(root);
}
}else{
throw new NullPointerException();
}
}
最終代碼
Tree接口
public interface Tree {
//構建樹
void CreateBinaryTree(Object tree, Object left, Object right);
//先序遍歷
void PreOrder();
//中序遍歷
void InfixOrder();
//後序遍歷
void PostOrder();
//前序查找
Object preOrderSearch(Object root);
//中序查找
Object infixOrderSearch(Object root);
//後序查找
Object postOrderSearch(Object root);
//刪除結點
void remove(Object root);
}
BinaryTree實現類
public class BinaryTree implements Tree{
private BinaryTree left; //左子樹
private BinaryTree right; //右子樹
private Object root; //根結點
int count = 0;
//-------構造傳值-------
public BinaryTree(Object data){
root = data;
}
@Override
//-------構建樹------- 爲了兼容接口統一Object
public void CreateBinaryTree(Object tree, Object left, Object right){
//強制轉換
BinaryTree Tree = (BinaryTree) tree;
Tree.left = (BinaryTree)left;
Tree.right = (BinaryTree)right;
}
//-------先序遍歷-------
@Override
public void PreOrder() {
//判斷二叉樹是否爲空
if(root != null){
System.out.print(root + " ");
//判斷左子節點是否爲空
if(left != null){
left.PreOrder();
}
if(right != null){
right.PreOrder();
}
}else{
//說明樹爲空,空指針異常
throw new NullPointerException();
}
}
//-------中序遍歷-------
@Override
public void InfixOrder() {
//判斷二叉樹是否爲空
if(root != null){
//判斷左子節點是否爲空
if(left != null){
left.InfixOrder();
}
System.out.print(root + " ");
if(right != null){
right.InfixOrder();
}
}else{
//說明樹爲空,空指針異常
throw new NullPointerException();
}
}
//-------後序遍歷-------
@Override
public void PostOrder() {
//判斷二叉樹是否爲空
if(root != null){
//判斷左子節點是否爲空
if(left != null){
left.PostOrder();
}
if(right != null){
right.PostOrder();
}
System.out.print(root + " ");
}else{
//說明樹爲空,空指針異常
throw new NullPointerException();
}
}
//前序查找
@Override
public Object preOrderSearch(Object root) {
Object res = null;
//判斷二叉樹是否爲空
if(root != null) {
//比較當前是不是
if (this.root == root) {
return this;
}
//判斷當前節點左子節點是否爲空,如果不爲空,則遞歸前序查找
//如果左遞歸找到則返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判斷左遞歸是否找到,找到就返回,沒找到就繼續右遞歸
if(res != null){
return res;
}
//如果左遞歸沒找到,就繼續右遞歸查找
if(this.right != null){
res = right.preOrderSearch(root);
}
}else{
throw new NullPointerException();
}
return res;
}
//中序查找
@Override
public Object infixOrderSearch(Object root) {
Object res = null;
//判斷二叉樹是否爲空
if(root != null) {
//判斷當前節點左子節點是否爲空,如果不爲空,則遞歸前序查找
//如果左遞歸找到則返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判斷左遞歸是否找到,找到就返回,沒找到就繼續比較當前節點
if(res != null){
return res;
}
//比較當前是不是
if (this.root == root) {
return this;
}
//如果左遞歸沒找到,就繼續右遞歸查找
if(this.right != null){
res = right.preOrderSearch(root);
}
}else{
throw new NullPointerException();
}
return res;
}
//後序查找
@Override
public Object postOrderSearch(Object root) {
Object res = null;
//判斷二叉樹是否爲空
if(root != null) {
//左遞歸查找,如果左遞歸找到則返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判斷左遞歸是否找到,找到就返回,沒找到就繼續右遞歸
if(res != null){
return res;
}
//如果左遞歸沒找到,就繼續右遞歸查找
if(this.right != null){
res = right.preOrderSearch(root);
}
//比較當前是不是
if (this.root == root) {
return this;
}
}else{
throw new NullPointerException();
}
return res;
}
//遞歸刪除結點
//1.如果刪除的結點是葉子結點,則刪除該結點
//2.如果刪除的結點是非葉子結點,則刪除該子樹
@Override
public void remove(Object root) {
//判斷二叉樹是否爲空
if(root != null){
//如果當前結點的左子結點不爲空,並且左子結點就是要刪除的結點,那麼就置空並返回
if(left != null && left.root == root){
left = null;
return;
}
//如果當前結點的右子結點不爲空,並且右子結點就是要刪除的結點,那麼就置空並返回
if(right != null && right.right == root){
right = null;
return;
}
//如果都沒有就向左子樹遞歸進行刪除
if(left != null){
left.remove(root);
}
//如果左子樹遞歸沒刪除就向右子樹遞歸刪除
if(right != null){
right.remove(root);
}
}else{
throw new NullPointerException();
}
}
//重寫toString
@Override
public String toString() {
return (String) root;
}
}
Test測試類
public class Test {
public static void main(String[] args) {
Tree A = new BinaryTree("A");
Tree B = new BinaryTree("B");
Tree C = new BinaryTree("C");
Tree D = new BinaryTree("D");
Tree E = new BinaryTree("E");
Tree F = new BinaryTree("F");
Tree G = new BinaryTree("G");
A.CreateBinaryTree(A,B,C); //定義A的兩個子節點
A.CreateBinaryTree(B,D,E); //定義B的兩個子節點
A.CreateBinaryTree(C,F,G); //定義C的兩個子節點
//前序遍歷
A.PreOrder(); System.out.println();
//中序遍歷
A.InfixOrder(); System.out.println();
//後序遍歷
A.PostOrder(); System.out.println();
//前序查找
Object preOrderSearch = A.preOrderSearch("E");
System.out.println(preOrderSearch);
//中序查找
Object infixOrderSearch = A.infixOrderSearch("G");
System.out.println(infixOrderSearch);
//後序查找
Object postOrderSearch = A.postOrderSearch("A");
System.out.println(postOrderSearch);
//刪除測試
A.remove("D");
A.PreOrder();
}
}