二叉樹查找和刪除指定結點

来源:https://www.cnblogs.com/malinyan/archive/2022/09/25/SearchAndDeleteNode.html
-Advertisement-
Play Games

二叉樹查找指定的節點 前序查找的思路 1.先判斷當前節點的no是否等於要查找的 2.如果是相等,則返回當前節點 3.如果不等,則判斷當前節點的左子節點是否為空,如果不為空,則遞歸前序查找 4.如果左遞歸前序查找,找到節點,則返回,否繼續判斷,當前的節點的右子節點是否為空,如果不為空,則繼續向右遞歸前 ...


二叉樹查找指定的節點

前序查找的思路

1.先判斷當前節點的no是否等於要查找的

2.如果是相等,則返回當前節點

3.如果不等,則判斷當前節點的左子節點是否為空,如果不為空,則遞歸前序查找

4.如果左遞歸前序查找,找到節點,則返回,否繼續判斷,當前的節點的右子節點是否為空,如果不為空,則繼續向右遞歸前序查找。

中序查找思路

1.判斷當前節點的左子節點是否為空,如果不為空,則遞歸中序查找

2.如果找到,則返回,如果沒有找到,就和當前節點比較,如果是則返回當前節點,否則繼續進行右遞歸的中序查找

3.如果右遞歸中序查找,找到就返回,否則返回null

後序查找思路

1.判斷當前節點的左子節點是否為空,如果不為空,則遞歸後序查找

2.如果找到,就返回,如果沒有找到,就判斷當前節點的右子節點是否為空,如果不為空,則右遞歸進行後序查找,如果找到,就返回

3.就和當前節點進行比較,如果是則返回,否則返回null

要求

1.請編寫前序查找,中序查找和後序查找的方法。

2.並分別使用三種查找方式,查找 heroNO = 5 的節點

3.並分析各種查找方式,分別比較了多少次

代碼實現:

先創建HeroNode 結點

class HeroNode {
	private int no;
	private String name;
	private HeroNode left; //預設null
	private HeroNode right; //預設null
	public HeroNode(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 HeroNode getLeft() {
		return left;
	}
	public void setLeft(HeroNode left) {
		this.left = left;
	}
	public HeroNode getRight() {
		return right;
	}
	public void setRight(HeroNode right) {
		this.right = right;
	}
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + "]";
	}
    //前序遍歷
	public void preOrder() {
		System.out.println(this); //先輸出父結點
		//遞歸向左子樹前序遍歷
		if(this.left != null) {
			this.left.preOrder();
		}
		//遞歸向右子樹前序遍歷
		if(this.right != null) {
			this.right.preOrder();
		}
	}
	//前序遍歷查找
	/**
	 * 
	 * @param no 查找no
	 * @return 如果找到就返回該Node ,如果沒有找到返回 null
	 */
	public HeroNode preOrderSearch(int no) {
		System.out.println("進入前序遍歷");
		//比較當前結點是不是
		if(this.no == no) {
			return this;
		}
		//1.則判斷當前結點的左子節點是否為空,如果不為空,則遞歸前序查找
		//2.如果左遞歸前序查找,找到結點,則返回
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.preOrderSearch(no);
		}
		if(resNode != null) {//說明我們左子樹找到
			return resNode;
		}
		//1.左遞歸前序查找,找到結點,則返回,否繼續判斷,
		//2.當前的結點的右子節點是否為空,如果不空,則繼續向右遞歸前序查找
		if(this.right != null) {
			resNode = this.right.preOrderSearch(no);
		}
		return resNode;
	}
	
	//中序遍歷查找
	public HeroNode infixOrderSearch(int no) {
		//判斷當前結點的左子節點是否為空,如果不為空,則遞歸中序查找
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.infixOrderSearch(no);
		}
		if(resNode != null) {
			return resNode;
		}
		System.out.println("進入中序查找");
		//如果找到,則返回,如果沒有找到,就和當前結點比較,如果是則返回當前結點
		if(this.no == no) {
			return this;
		}
		//否則繼續進行右遞歸的中序查找
		if(this.right != null) {
			resNode = this.right.infixOrderSearch(no);
		}
		return resNode;
		
	}
	
	//後序遍歷查找
	public HeroNode postOrderSearch(int no) {
		
		//判斷當前結點的左子節點是否為空,如果不為空,則遞歸後序查找
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.postOrderSearch(no);
		}
		if(resNode != null) {//說明在左子樹找到
			return resNode;
		}
		
		//如果左子樹沒有找到,則向右子樹遞歸進行後序遍歷查找
		if(this.right != null) {
			resNode = this.right.postOrderSearch(no);
		}
		if(resNode != null) {
			return resNode;
		}
		System.out.println("進入後序查找");
		//如果左右子樹都沒有找到,就比較當前結點是不是
		if(this.no == no) {
			return this;
		}
		return resNode;
	}
	
}

定義BinaryTree 二叉樹

class BinaryTree {
	private HeroNode root;

	public void setRoot(HeroNode root) {
		this.root = root;
	}
	
	//前序遍歷查找
	public HeroNode preOrderSearch(int no) {
		if(root != null) {
			return root.preOrderSearch(no);
		} else {
			return null;
		}
	}
	//中序遍歷查找
	public HeroNode infixOrderSearch(int no) {
		if(root != null) {
			return root.infixOrderSearch(no);
		}else {
			return null;
		}
	}
	//後序遍歷查找
	public HeroNode postOrderSearch(int no) {
		if(root != null) {
			return this.root.postOrderSearch(no);
		}else {
			return null;
		}
	}
}

測試:

public class BinaryTreeDemo {

	public static void main(String[] args) {
		//先需要創建一顆二叉樹
		BinaryTree binaryTree = new BinaryTree();
		//創建需要的結點
		HeroNode root = new HeroNode(1, "宋江");
		HeroNode node2 = new HeroNode(2, "吳用");
		HeroNode node3 = new HeroNode(3, "盧俊義");
		HeroNode node4 = new HeroNode(4, "林沖");
		HeroNode node5 = new HeroNode(5, "關勝");
		
		//說明,我們先手動創建該二叉樹,後面我們學習遞歸的方式創建二叉樹
		root.setLeft(node2);
		root.setRight(node3);
		node3.setRight(node4);
		node3.setLeft(node5);
		binaryTree.setRoot(root);
		
		// 前序遍歷
		// 前序遍歷的次數 :4
		System.out.println("前序遍歷方式~~~");
		HeroNode resNode = binaryTree.preOrderSearch(5);
		if (resNode != null) {
			System.out.printf("找到了,信息為 no=%d name=%s", resNode.getNo(), resNode.getName());
		} else {
			System.out.printf("沒有找到 no = %d 的英雄", 5);
		}
		
		/**
			// 中序遍歷查找
			// 中序遍歷3次
			System.out.println("中序遍歷方式~~~");
			HeroNode resNode = binaryTree.infixOrderSearch(5);
			if (resNode != null) {
				System.out.printf("找到了,信息為 no=%d name=%s", resNode.getNo(), resNode.getName());
			} else {
				System.out.printf("沒有找到 no = %d 的英雄", 5);
			}
		*/
		/**
			// 後序遍歷查找
			// 後序遍歷查找的次數 2次
			System.out.println("後序遍歷方式~~~");
			HeroNode resNode = binaryTree.postOrderSearch(5);
			if (resNode != null) {
				System.out.printf("找到了,信息為 no=%d name=%s", resNode.getNo(), resNode.getName());
			} else {
				System.out.printf("沒有找到 no = %d 的英雄", 5);
			}
		*/
		
	}

}

運行結果如圖:

前序遍歷:

中序遍歷:

後序遍歷:

二叉樹刪除指定的節點

要求

1.如果刪除的節點是葉子節點,則刪除該節點

2.如果刪除的節點是非葉子節點,則刪除該子樹.

3.測試,刪除掉 5 號葉子節點

思路:

1.考慮如果樹是空樹root,如果只有一個root節點,則等價將二叉樹置空

2.因為我們的二叉樹是單向的,所以我們是判斷當前節點的子節點是否是需要刪除節點,而不能去判斷當前這個節點是不是需要刪除節點。

3.如果當前節點的左子節點不為空,並且左子節點就是要刪除節點,就將this.left=null;

並且就返回(結束遞歸刪除)

4.如果當前節點的右子節點不為空,並且右子節點就是要刪除節點,就將this.right=null;

並且就返回(結束遞歸刪除)

5.如果3,4步沒有刪除節點,那麼我們就需要向左子樹進行遞歸刪除

6.如果第5步也沒有刪除節點,則應當向右子樹進行遞歸刪除。

代碼實現:

//HeroNode 類增加方法

//遞歸刪除結點
	//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);
		}
	}

//在 BinaryTree 類增加方法

//刪除結點
	public void delNode(int no) {
		if(root != null) {
			//如果只有一個root結點, 這裡立即判斷root是不是就是要刪除結點
			if(root.getNo() == no) {
				root = null;
			} else {
				//遞歸刪除
				root.delNode(no);
			}
		}else{
			System.out.println("空樹,不能刪除~");
		}
	}

//在 BinaryTreeDemo 類增加測試代碼:

//測試一把刪除結點
		System.out.println("刪除前,前序遍歷");
		binaryTree.preOrder(); //  1,2,3,5,4
		binaryTree.delNode(5);
		//binaryTree.delNode(3);
		System.out.println("刪除後,前序遍歷");
		binaryTree.preOrder(); // 1,2,3,4

代碼運行如圖:

這篇博客是我在B站看韓順平老師數據結構和演算法的課時的筆記,記錄一下,防止忘記,也希望能幫助各位朋友。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Stream流呢,以前我也有所瞭解,像一些面試題中也出現過,Java8的新特性,有一塊就是這個Stream操作集合,而且在看一些項目中也使用的比較多。但總感覺自己學的一知半解,所以今天打算系統的過一下,再鞏固鞏固。 ###概念 Stream是JDK8 API中的新成員,它允許以聲明性方式處理集合。 ...
  • 一、開發背景 您好,我是 @馬哥python說 ,這是我獨立開發的Python可視化大屏,看下演示效果: 截圖: 視頻演示效果: https://www.zhihu.com/zvideo/1556218745923821568 這個大屏,是通過pyecharts可視化開發框架實現。 下麵詳細介紹,這 ...
  • 來源:https://www.linuxmi.com/50-million-pc-linux.html 開源社區的一大勝利! 繼德國之後,中國現在想在 5000 萬台 PC 上拋棄 Windows 並運行 Linux! 如果您一直密切關註 Linux 新聞,您可能聽說過德國去年在超過 25000 台 ...
  • ###一、Scrapy 介紹 Scrapy是一個Python編寫的開源和協作的框架。起初是用於網路頁面抓取所設計的,使用它可以快速、簡單、可擴展的方式從網站中提取所需的數據。 Scrapy也是通用的網路爬蟲框架,爬蟲界的django(設計原則很像),可用於數據挖掘、監測和自動化測試、也可以應用在獲取 ...
  • 2022-09-25 首先,要安裝好虛擬環境,之後要切換到虛擬環境中,使用的命令 workon 創建好的虛擬環境的名稱 之後,創建一個Django項目使用的命令: django-admin startproject 項目名稱 進入到該項目的目錄下,創建一個子應用,使用的命令: python mana ...
  • 拉格朗日插值原理及實現(Python) 一. 前言 Lagrange插值是利用n次多項式來擬合**(n+1)個數據點**從而得到插值函數的方法。(註意n次多項式的定義是未知數最高次冪為n,但是多項式繫數有n+1個,因為還有個常數項) **Lagrange插值和Newton插值本質上相同,都是用(n- ...
  • ###一、背景知識 爬蟲的本質就是一個socket客戶端與服務端的通信過程,如果我們有多個url待爬取,只用一個線程且採用串列的方式執行,那隻能等待爬取一個結束後才能繼續下一個,效率會非常低。 需要強調的是:對於單線程下串列N個任務,並不完全等同於低效,如果這N個任務都是純計算的任務,那麼該線程對c ...
  • ##Invalid bound statement (not found)出現原因和解決方法 ###前言: 想必各位小伙伴在碼路上經常會碰到奇奇怪怪的事情,比如出現Invalid bound statement (not found),那今天我就來分析以下出現此問題的原因。 其實出現這個問題實質就是 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 當別人做大數據用Java、Python的時候,我使用.NET做大數據、數據挖掘,這確實是值得一說的事。 寫的並不全面,但都是實際工作中的內容。 .NET在大數據項目中,可以做什麼? 寫腳本(使用控制台程式+頂級語句) 寫工具(使用Winform) 寫介面、寫服務 使用C#寫代碼的優點是什麼? ...
  • 前言 本文寫給想學C#的朋友,目的是以儘快的速度入門 C#好學嗎? 對於這個問題,我以前的回答是:好學!但仔細想想,不是這麼回事,對於新手來說,C#沒有那麼好學。 反而學Java還要容易一些,學Java Web就行了,就是SpringBoot那一套。 但是C#方向比較多,你是學控制台程式、WebAP ...
  • 某一日晚上上線,測試同學在回歸項目黃金流程時,有一個工單項目介面報JSF序列化錯誤,馬上升級對應的client包版本,編譯部署後錯誤消失。 線上問題是解決了,但是作為程式員要瞭解問題發生的原因和本質。但這都是為什麼呢? ...
  • 本文介紹基於Python語言中TensorFlow的Keras介面,實現深度神經網路回歸的方法。 1 寫在前面 前期一篇文章Python TensorFlow深度學習回歸代碼:DNNRegressor詳細介紹了基於TensorFlow tf.estimator介面的深度學習網路;而在TensorFl ...
  • 前段時間因業務需要完成了一個工作流組件的編碼工作。藉著這個機會跟大家分享一下整個創作過程,希望大家喜歡,組件暫且命名為"easyFlowable"。 接下來的文章我將從什麼是工作流、為什麼要自研這個工作流組件、架構設計三個維度跟大家來做個整體介紹。 ...
  • 1 簡介 我們之前使用了dapr的本地托管模式,但在生產中我們一般使用Kubernetes托管,本文介紹如何在GKE(GCP Kubernetes)安裝dapr。 相關文章: dapr本地托管的服務調用體驗與Java SDK的Spring Boot整合 dapr入門與本地托管模式嘗試 2 安裝GKE ...
  • 摘要:在jvm中有很多的參數可以進行設置,這樣可以讓jvm在各種環境中都能夠高效的運行。絕大部分的參數保持預設即可。 本文分享自華為雲社區《為什麼需要對jvm進行優化,jvm運行參數之標準參數》,作者:共飲一杯無。 我們為什麼要對jvm做優化? 在本地開發環境中我們很少會遇到需要對jvm進行優化的需 ...
  • 背景 我們的業務共使用11台(阿裡雲)伺服器,使用SpringcloudAlibaba構建微服務集群,共計60個微服務,全部註冊在同一個Nacos集群 流量轉發路徑: nginx->spring-gateway->業務微服務 使用的版本如下: spring-boot.version:2.2.5.RE ...
  • 基於php+webuploader的大文件分片上傳,帶進度條,支持斷點續傳(刷新、關閉頁面、重新上傳、網路中斷等情況)。文件上傳前先檢測該文件是否已上傳,如果已上傳提示“文件已存在”,如果未上傳則直接上傳。視頻上傳時會根據設定的參數(分片大小、分片數量)進行上傳,上傳過程中會在目標文件夾中生成一個臨 ...
  • 基於php大文件分片上傳至七牛雲,使用的是七牛雲js-sdk V2版本,引入js文件,配置簡單,可以暫停,暫停後支持斷點續傳(刷新、關閉頁面、重新上傳、網路中斷等情況),可以配置分片大小和分片數量,官方文檔https://developer.qiniu.com/kodo/6889/javascrip ...