欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java數(shù)據(jù)結(jié)構(gòu)之二叉搜索樹詳解

 更新時(shí)間:2022年06月06日 08:30:16   作者:Carol淋  
二叉搜索樹作為一個(gè)經(jīng)典的數(shù)據(jù)結(jié)構(gòu),具有鏈表的快速插入與刪除的特點(diǎn),同時(shí)查詢效率也很優(yōu)秀,所以應(yīng)用十分廣泛。本文將詳細(xì)講講二叉搜索樹的原理與實(shí)現(xiàn),需要的可以參考一下

前言

今天leetcode的每日一題450是關(guān)于刪除二叉搜索樹節(jié)點(diǎn)的,題目要求刪除指定值的節(jié)點(diǎn),并且需要保證二叉搜索樹性質(zhì)不變,做完之后,我覺得這道題將二叉搜索樹特性凸顯的很好,首先需要查找指定節(jié)點(diǎn),然后刪除節(jié)點(diǎn)并且保持二叉搜索樹性質(zhì)不變,就想利用這個(gè)題目講講二叉搜索樹。

二叉搜索樹作為一個(gè)經(jīng)典的數(shù)據(jù)結(jié)構(gòu),具有鏈表的快速插入與刪除的特點(diǎn),同時(shí)查詢效率也很優(yōu)秀,所以應(yīng)用十分廣泛,例如在文件系統(tǒng)和數(shù)據(jù)庫系統(tǒng)一般會(huì)采用這種數(shù)據(jù)結(jié)構(gòu)進(jìn)行高效率的排序與檢索操作。同時(shí)因?yàn)閷?shí)現(xiàn)也簡單,作為一些公司算法題入門題目也是常有的事情,所以很需要被掌握哦~

所有源碼已經(jīng)放在我的github中,其中包括之前實(shí)現(xiàn)算法及每日一題,可以查看Data-Structures-and-Algorithms哦~

性質(zhì)

二叉搜索樹或者是一棵空樹,或者是具有下列性質(zhì)的一棵二叉樹,如果當(dāng)前節(jié)點(diǎn)具有左子樹,則左子樹上的每一個(gè)節(jié)點(diǎn)值均小于等于當(dāng)前節(jié)點(diǎn)值,如果當(dāng)前節(jié)點(diǎn)具有右子樹,則右子樹上的每一個(gè)節(jié)點(diǎn)值均大于等于當(dāng)前節(jié)點(diǎn)值。依據(jù)這個(gè)性質(zhì),當(dāng)我們前序遍歷二叉搜索樹的時(shí)候,得到的序列應(yīng)該是從小到大的非遞減序列。同時(shí)搜索指定值時(shí),只需要與當(dāng)前節(jié)點(diǎn)比較,根據(jù)相對(duì)大小在左子樹或者右子樹上進(jìn)行搜索。

實(shí)現(xiàn)

根據(jù)二叉搜索樹的性質(zhì)我們接下來需要實(shí)現(xiàn)插入節(jié)點(diǎn),查詢節(jié)點(diǎn),刪除節(jié)點(diǎn)功能。

節(jié)點(diǎn)結(jié)構(gòu)

public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;

    public TreeNode() {
    }

    public TreeNode(int val) {
        this.val = val;
    }

    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

初始化

這里我們假設(shè)所有節(jié)點(diǎn)值大于0,初始化一個(gè)頭節(jié)點(diǎn)。ps:對(duì)于樹,鏈表這類數(shù)據(jù)結(jié)構(gòu),為了使第一個(gè)節(jié)點(diǎn)操作與其他節(jié)點(diǎn)保持一致,方便操作,常見的方法是添加一個(gè)額外的頭節(jié)點(diǎn),指向第一個(gè)節(jié)點(diǎn)。

TreeNode head;
    private void init() {
        //添加一個(gè)頭節(jié)點(diǎn)
        head = new TreeNode(-1);
    }

插入節(jié)點(diǎn)

從頭節(jié)點(diǎn)開始我們遍歷二叉搜索樹,如果當(dāng)前節(jié)點(diǎn)值小于等于插入節(jié)點(diǎn)值,則插入節(jié)點(diǎn)在當(dāng)前節(jié)點(diǎn)的右子樹上,否則在左子樹上,一直深度遍歷知道當(dāng)前節(jié)點(diǎn)的右子樹(左子樹)為空,則插入。

/**
     * 插入新節(jié)點(diǎn),假設(shè)新節(jié)點(diǎn)均大于0
     * @param val 插入節(jié)點(diǎn)值
     * @return 插入的節(jié)點(diǎn)
     */
    public TreeNode insert(int val) {
        TreeNode temp = head;
        while (true) {
            if (temp.val < val) {
                //val應(yīng)該在右子樹上
                if (null != temp.right) {
                    temp = temp.right;
                    continue;
                } else {
                    temp.right = new TreeNode(val);
                    return temp.right;
                }
            }
            //應(yīng)該在左子樹上
            if (null != temp.left) {
                temp = temp.left;
                continue;
            }
            temp.left = new TreeNode(val);
            return temp.left;
        }
    }

查找節(jié)點(diǎn)

查找節(jié)點(diǎn)的步驟其實(shí)在插入節(jié)點(diǎn)的時(shí)候已經(jīng)有體現(xiàn),其實(shí)就是將查找值與當(dāng)前節(jié)點(diǎn)比較,大于當(dāng)前節(jié)點(diǎn)走右子樹,小于當(dāng)前節(jié)點(diǎn)走左子樹,直到值匹配返回節(jié)點(diǎn),或者沒有找到返回null。ps:這里為了后面方便實(shí)現(xiàn)刪除,同時(shí)返回了當(dāng)前節(jié)點(diǎn)以及當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn),這里使用了commons-lang3包下的Pair工具。

/**
     * 搜索節(jié)點(diǎn)值
     * @param val
     * @return
     */
    public Pair<TreeNode, TreeNode> find(int val) {
        TreeNode temp = head.right;
        TreeNode parent = head;
        while (null != temp) {
            if (temp.val == val) {
                return Pair.of(temp, parent);
            }
            parent = temp;
            if (temp.val < val) {
                //在右子樹上
                temp = temp.right;
                continue;
            }
            temp = temp.left;
        }
        return null;
    }

刪除節(jié)點(diǎn)

刪除節(jié)點(diǎn)時(shí)候我們需要先找到刪除節(jié)點(diǎn)的位置,然后做對(duì)應(yīng)操作。有三種情況:

1.如果刪除的是葉子節(jié)點(diǎn)直接刪除

2.如果刪除的節(jié)點(diǎn)只有左子樹或者右子樹,則直接將左子樹或者右子樹節(jié)點(diǎn)放在刪除節(jié)點(diǎn)位置

3.如果刪除節(jié)點(diǎn)同時(shí)有左子樹和右子樹,則將右子樹節(jié)點(diǎn)放在原來節(jié)點(diǎn)位置,將左子樹放在右子樹最左邊節(jié)點(diǎn)左子樹上(反之將左子樹放在原來節(jié)點(diǎn)位置,右子樹放在左子樹最右邊節(jié)點(diǎn)右子樹上也可)

/**
     * 1.如果刪除的是葉子節(jié)點(diǎn)直接刪除,
     * 2.如果刪除的節(jié)點(diǎn)只有左子樹或者右子樹,則直接將左子樹或者右子樹節(jié)點(diǎn)放在刪除節(jié)點(diǎn)位置
     * 3.如果刪除節(jié)點(diǎn)同時(shí)右左子樹和右子樹,則將右子樹節(jié)點(diǎn)放在原來節(jié)點(diǎn)位置,將左子樹放在右子樹最左邊節(jié)點(diǎn)左子樹上
     * @param val
     */
    public void delete(int val) {
        //找到刪除節(jié)點(diǎn),刪除節(jié)點(diǎn)父節(jié)點(diǎn)
        Pair<TreeNode, TreeNode> curAndParent = this.find(val);
        TreeNode cur = curAndParent.getLeft();
        TreeNode parent = curAndParent.getRight();
        //記錄刪除當(dāng)前節(jié)點(diǎn)后,當(dāng)前節(jié)點(diǎn)位置放置哪個(gè)節(jié)點(diǎn)
        TreeNode changed;
        if (null == cur.left && null == cur.right) {
            changed = null;
        } else if (null != cur.left && null != cur.right) {
            TreeNode tempRight = cur.right;
            while (null != tempRight.left) {
                //找到最左側(cè)節(jié)點(diǎn)
                tempRight = tempRight.left;
            }
            tempRight.left = cur.left;
            changed = cur.right;
        } else if (null != cur.left) {
            changed = cur.left;
        } else {
            changed = cur.right;
        }
        if (parent.left == cur) {
            parent.left = changed;
            return;
        }
        parent.right = changed;
    }

最后

二叉搜索樹易于實(shí)現(xiàn),思想簡單,被廣泛應(yīng)用,平均查找,插入,刪除時(shí)間均為O(logn),但是在刪除或者插入節(jié)點(diǎn)的過程中,可能因?yàn)閿?shù)據(jù)的特點(diǎn),使得二叉搜索樹極端情況下退化為一棵僅有左子樹或者右子樹的,這時(shí)候就跟普通順序查找無異,時(shí)間復(fù)雜度變?yōu)镺(n),因此后面出現(xiàn)了平衡二叉搜索樹,左右子樹高度相差不超過1,通過旋轉(zhuǎn)將二叉樹高度降低,使得查找、插入、刪除在平均和最壞情況下都是O(logn)。比如常見的AVL自平衡二叉搜索樹,紅黑樹等等。

到此這篇關(guān)于Java數(shù)據(jù)結(jié)構(gòu)之二叉搜索樹詳解的文章就介紹到這了,更多相關(guān)Java二叉搜索樹內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中使用異或運(yùn)算符實(shí)現(xiàn)加密字符串

    Java中使用異或運(yùn)算符實(shí)現(xiàn)加密字符串

    這篇文章主要介紹了Java中使用異或運(yùn)算符實(shí)現(xiàn)加密字符串,本文直接給出實(shí)現(xiàn)代碼,以及運(yùn)算結(jié)果加密實(shí)例,需要的朋友可以參考下
    2015-06-06
  • java N皇后實(shí)現(xiàn)問題解析

    java N皇后實(shí)現(xiàn)問題解析

    將 n 個(gè)皇后擺放在一個(gè) n x n 的棋盤上,使得每一個(gè)皇后都無法攻擊到其他皇后,N皇后問題是一個(gè)典型的約束求解問題,利用遞歸機(jī)制,可以很快的得到結(jié)果,本文將詳細(xì)介紹,需要了解的朋友可以參考下
    2012-11-11
  • java發(fā)起http請(qǐng)求調(diào)用post與get接口的方法實(shí)例

    java發(fā)起http請(qǐng)求調(diào)用post與get接口的方法實(shí)例

    在實(shí)際開發(fā)過程中,我們經(jīng)常需要調(diào)用對(duì)方提供的接口或測試自己寫的接口是否合適,下面這篇文章主要給大家介紹了關(guān)于java發(fā)起http請(qǐng)求調(diào)用post與get接口的相關(guān)資料,需要的朋友可以參考下
    2022-08-08
  • Mybatis引入與使用的圖文步驟

    Mybatis引入與使用的圖文步驟

    本文主要介紹了Mybatis引入與使用的圖文步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-09-09
  • Java8新特性之重復(fù)注解(repeating annotations)淺析

    Java8新特性之重復(fù)注解(repeating annotations)淺析

    這篇文章主要介紹了Java8新特性之重復(fù)注解(repeating annotations)淺析,這個(gè)新特性只是修改了程序的可讀性,是比較小的一個(gè)改動(dòng),需要的朋友可以參考下
    2014-06-06
  • springmvc+ajax+formdata上傳圖片代碼實(shí)例

    springmvc+ajax+formdata上傳圖片代碼實(shí)例

    這篇文章主要介紹了springmvc+ajax+formdata上傳圖片代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • MyBatis Oracle 自增序列的實(shí)現(xiàn)方法

    MyBatis Oracle 自增序列的實(shí)現(xiàn)方法

    這篇文章給大家分享MyBatis Oracle 自增序列的實(shí)現(xiàn)方法及mybatis配置oracle的主鍵自增長的方法,非常不錯(cuò)具有一定的參考借鑒價(jià)值,感興趣的朋友一起看看吧
    2016-11-11
  • ArrayList及HashMap的擴(kuò)容規(guī)則講解

    ArrayList及HashMap的擴(kuò)容規(guī)則講解

    今天小編就為大家分享一篇關(guān)于ArrayList及HashMap的擴(kuò)容規(guī)則講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • Swing常用組件之單選按鈕和復(fù)選框

    Swing常用組件之單選按鈕和復(fù)選框

    Swing是一個(gè)用于開發(fā)Java應(yīng)用程序用戶界面的開發(fā)工具包,這篇文章主要介紹了Swing常用組件之單選按鈕和復(fù)選框,感興趣的朋友可以參考一下
    2016-05-05
  • idea maven 構(gòu)建本地jar包及pom文件的過程

    idea maven 構(gòu)建本地jar包及pom文件的過程

    這篇文章主要介紹了idea maven 構(gòu)建本地jar包及pom文件的過程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-11-11

最新評(píng)論