真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

二叉查找樹的概念和實(shí)現(xiàn)方法

本篇內(nèi)容介紹了“二叉查找樹的概念和實(shí)現(xiàn)方法”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長期合作伙伴,公司提供的服務(wù)項(xiàng)目有:主機(jī)域名、網(wǎng)絡(luò)空間、營銷軟件、網(wǎng)站建設(shè)、金水網(wǎng)站維護(hù)、網(wǎng)站推廣。

二叉查找樹的概念和實(shí)現(xiàn)方法

二叉查找樹是將一組無序的數(shù)據(jù)構(gòu)建成一顆有序數(shù)據(jù)的樹,其設(shè)計(jì)思想與二分法類似。很好的提高了海量數(shù)據(jù)查找效率,使得由從頭遍歷到尾的方式轉(zhuǎn)為二分查找的方式,時(shí)間復(fù)雜度從O(n)降低為O(log(n))。

概念

  1. 結(jié)點(diǎn):樹上的每個元素。

  2. 根結(jié)點(diǎn):沒有父結(jié)點(diǎn)的結(jié)點(diǎn)。

  3. 父結(jié)點(diǎn):結(jié)點(diǎn)的上一級結(jié)點(diǎn)。

  4. 子結(jié)點(diǎn):結(jié)點(diǎn)的下一級結(jié)點(diǎn)。

  5. 葉子結(jié)點(diǎn):沒有子結(jié)點(diǎn)的結(jié)點(diǎn)。

  6. 兄弟結(jié)點(diǎn):擁有同一父結(jié)點(diǎn)的相鄰結(jié)點(diǎn)。

  7. 結(jié)點(diǎn)的度:一個結(jié)點(diǎn)中擁有子結(jié)點(diǎn)的個數(shù)。

  8. 樹的度:樹上最大結(jié)點(diǎn)的度。

  9. 結(jié)點(diǎn)的層次:以根結(jié)點(diǎn)為1,每深入一個子結(jié)點(diǎn)層次加1。

  10. 樹的高度:樹中最大的結(jié)點(diǎn)的層次。

特性

  1. 左子樹所有的結(jié)點(diǎn)值均小于,等于根結(jié)點(diǎn)值或?yàn)榭铡?/p>

  2. 左子樹所有的結(jié)點(diǎn)值均大于,等于根結(jié)點(diǎn)值或?yàn)榭铡?/p>

  3. 左、右子樹也分別為二叉排序樹。

  4. 沒有鍵值相等的結(jié)點(diǎn)。

構(gòu)建

構(gòu)建二叉查找樹,主要把握幾條原則,小于當(dāng)前結(jié)點(diǎn)的在左邊,大于的在右邊,相等的不予處理。但是情況下結(jié)合實(shí)際業(yè)務(wù)需求,也可在相等時(shí)放在左結(jié)點(diǎn)或右結(jié)點(diǎn),但是必須統(tǒng)一規(guī)則,不能左右都存在相等的。 創(chuàng)建結(jié)點(diǎn)對象:

package com.ytao.bst;

/**
 * Created by YANGTAO on 2019/11/3 0003.
 */
public class Node {

    private Integer value;

    private Node leftChildren;

    private Node rightChildren;

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }

    public Node getLeftChildren() {
        return leftChildren;
    }

    public void setLeftChildren(Node leftChildren) {
        this.leftChildren = leftChildren;
    }

    public Node getRightChildren() {
        return rightChildren;
    }

    public void setRightChildren(Node rightChildren) {
        this.rightChildren = rightChildren;
    }

    public Node(Integer value) {
        this.value = value;
    }
}

創(chuàng)建樹的實(shí)現(xiàn):

package com.ytao.bst;

/**
 * Created by YANGTAO on 2019/11/3 0003.
 */
public class BuildBST {

    private Node rootNode = null;

    public Node build(int[] vals){
        // 遍歷所有數(shù)據(jù),每次都需從根結(jié)點(diǎn)開始尋找左或右子節(jié)點(diǎn)為空的位置添加
        for (int val : vals) {
            this.assemble(rootNode, val);
        }

        return rootNode;
    }

    private void assemble(Node node, int val){
        // 創(chuàng)建根結(jié)點(diǎn)
        if (node == null){
            rootNode = new Node(val);
        }else{
            // 根據(jù)左小右大特性判斷
            if (val < node.getValue()){
                Node leftNode = node.getLeftChildren();
                // 如果左子結(jié)點(diǎn)為空,就添加為當(dāng)前結(jié)點(diǎn)的左結(jié)點(diǎn),否則繼續(xù)遞歸下去
                if (leftNode == null){
                    node.setLeftChildren(new Node(val));
                }else{
                    this.assemble(node.getLeftChildren(), val);
                }
            }else{
                Node rightNode = node.getRightChildren();
                // 如果右子結(jié)點(diǎn)為空,就添加為當(dāng)前結(jié)點(diǎn)的右結(jié)點(diǎn),否則繼續(xù)遞歸下去
                if (rightNode == null){
                    node.setRightChildren(new Node(val));
                }else{
                    this.assemble(rightNode, val);
                }
            }

        }

    }

}

使用[7,5,9,2,11,6]測試是否滿足我們創(chuàng)建樹的要求:

public static void main(String[] args) {
    int[] vals = {7,5,9,2,11,6};
    Node node = new BuildBST().build(vals);
    System.out.println(new Gson().toJson(node));
}

測試結(jié)果滿足我們要求

{
    "value": 7,
    "leftChildren": {
        "value": 5,
        "leftChildren": {
            "value": 2
        },
        "rightChildren": {
            "value": 6
        }
    },
    "rightChildren": {
        "value": 9,
        "rightChildren": {
            "value": 11
        }
    }
}

查找

假設(shè)從一百萬個數(shù)字中獲取值為88的數(shù)據(jù),如果我們使用遍歷的方式,最糟的情況就是排在第一百萬個位置的時(shí)候,需要我們遍歷一百萬次才能獲取到數(shù)據(jù),這就是我們最不想遇到的情況。這時(shí)將一百萬個數(shù)據(jù)構(gòu)建成二叉查找樹,我們就可通過樹快速找到我們想要的數(shù)據(jù)。 由于設(shè)定一百萬個數(shù)據(jù)比較多,這里我們舉例當(dāng)前擁有數(shù)據(jù)[7,5,9,2,11,6],我們要找出其中的6。 使用循環(huán)遍歷所有數(shù)據(jù)的方法,我們需要6次遍歷 7->5->9->2->11->6。 使用二叉查找樹查找時(shí),首先構(gòu)建好的二叉查找樹的結(jié)構(gòu)如圖:

二叉查找樹的概念和實(shí)現(xiàn)方法

從根結(jié)點(diǎn)開始查找;

二叉查找樹的概念和實(shí)現(xiàn)方法

獲取根結(jié)點(diǎn)7,不等于6,且6<7,所以繼續(xù)找左子結(jié)點(diǎn);

二叉查找樹的概念和實(shí)現(xiàn)方法

獲取到結(jié)點(diǎn)5,不等于6,且6>5,所以繼續(xù)找右子節(jié)點(diǎn);

二叉查找樹的概念和實(shí)現(xiàn)方法

最終獲取到結(jié)點(diǎn)6,滿足我們需要的條件。所遍歷的數(shù)據(jù)為 7->5->6。 代碼實(shí)現(xiàn)查找:

package com.ytao.bst;

/**
 * Created by YANGTAO on 2019/11/3 0003.
 */
public class SearchBST {

    public Node search(Node node, int val){
        // 如果結(jié)點(diǎn)為空,說明是沒有了符合的結(jié)點(diǎn)
        if (node == null)
            return null;

        int nodeVal = node.getValue();

        // 如果結(jié)點(diǎn)上的鍵值相等,就是我們需要找的結(jié)點(diǎn)
        if (val == nodeVal){
            return node;
        }else if (val < nodeVal){ // 如果小于結(jié)點(diǎn)的值,那么一定在結(jié)點(diǎn)的左子樹中
            return this.search(node.getLeftChildren(), val);
        }else{
            return this.search(node.getRightChildren(), val);
        }

    }


}

插入

二叉查找樹的插入規(guī)則,必須是要插入后的結(jié)點(diǎn)是作為葉子結(jié)點(diǎn)?,F(xiàn)在向上面的樹中插入10,根據(jù)上面所分析到的規(guī)則,為確保二叉查找樹的完整性,最終的插入流程為7->9->11->10:

二叉查找樹的概念和實(shí)現(xiàn)方法

代碼實(shí)現(xiàn):

package com.ytao.bst;

/**
 * Created by YANGTAO on 2019/11/3 0003.
 */
public class InsertBST {

    public void inesrt(Node node, int newVal){
        // 當(dāng)結(jié)點(diǎn)為空是,說明是作為根結(jié)點(diǎn)
        if (node == null){
            node = new Node(newVal);
        }

        int nodeVal = node.getValue();

        // 如果小于結(jié)點(diǎn)的值,插入到左子樹中,大于就插入右子樹中
        if (newVal < nodeVal){
            Node leftNode = node.getLeftChildren();
            // 為空時(shí),說明為葉子結(jié)點(diǎn),可插入
            if (leftNode == null){
                node.setLeftChildren(new Node(newVal));
            }else {
                this.inesrt(leftNode, newVal);
            }
        }else if (newVal > nodeVal){
            Node  rightNode = node.getRightChildren();
            if (rightNode == null){
                node.setRightChildren(new Node(newVal));
            }else {
                this.inesrt(rightNode, newVal);
            }
        }else {
            // todo 相等時(shí),可根據(jù)具體業(yè)務(wù)處理,放棄,或在左右樹中選擇一個
        }

    }

}

刪除

刪除結(jié)點(diǎn)分為多種情況,其中主要分析的:

葉子結(jié)點(diǎn)

刪除葉子結(jié)點(diǎn),將所要刪除的葉子結(jié)點(diǎn)直接刪除便可,比如刪除結(jié)點(diǎn)6。

二叉查找樹的概念和實(shí)現(xiàn)方法

單子結(jié)點(diǎn)的結(jié)點(diǎn)

被刪除結(jié)點(diǎn),如果只有一個子結(jié)點(diǎn),那么被刪除結(jié)點(diǎn)刪除后,該結(jié)點(diǎn)的子結(jié)點(diǎn)補(bǔ)上其位置,比如刪除結(jié)點(diǎn)9。

二叉查找樹的概念和實(shí)現(xiàn)方法

存在左右子結(jié)點(diǎn)的結(jié)點(diǎn)

為了更加清楚表達(dá)刪除存在左右結(jié)點(diǎn)的結(jié)點(diǎn),先向樹中多添加3個結(jié)點(diǎn)8,10,15。然后刪除結(jié)點(diǎn)9。 這里的解決方法就是,刪除9后,可以用前驅(qū)結(jié)點(diǎn)或后繼結(jié)點(diǎn)補(bǔ)上。前驅(qū)結(jié)點(diǎn)為左子樹中最大的結(jié)點(diǎn),后繼結(jié)點(diǎn)為右子樹中最小的結(jié)點(diǎn)。 現(xiàn)在以后繼結(jié)點(diǎn)補(bǔ)上的方案為:

二叉查找樹的概念和實(shí)現(xiàn)方法

后繼結(jié)點(diǎn)補(bǔ)上刪除后的結(jié)點(diǎn):

二叉查找樹的概念和實(shí)現(xiàn)方法

完成刪除,后繼結(jié)點(diǎn)補(bǔ)充上后:

二叉查找樹的概念和實(shí)現(xiàn)方法

代碼實(shí)現(xiàn):

package com.ytao.bst;

/**
 * Created by YANGTAO on 2019/11/3 0003.
 */
public class DeleteBST {


    public Node delete(Node node, int delVal) {
        // 為空時(shí),代表葉子結(jié)點(diǎn)
        if (node == null){
            return node;
        }

        int nodeVal = node.getValue();
        Node leftNode = node.getLeftChildren();
        Node rightNode = node.getRightChildren();

        // 刪除的結(jié)點(diǎn),與遍歷到的當(dāng)前結(jié)點(diǎn)做比較,小于,大于或等于
        if (delVal < nodeVal){
            Node tempLeftNode = delete(leftNode, delVal);
            node.setLeftChildren(tempLeftNode);
        } else if(delVal > nodeVal){
            Node tempRightNode = delete(rightNode, delVal);
            node.setRightChildren(tempRightNode);
        } else {
            // 刪除的結(jié)點(diǎn)與當(dāng)前遍歷到的結(jié)點(diǎn)相等時(shí)
            // 并且左結(jié)點(diǎn)為空時(shí),返回右結(jié)點(diǎn)去補(bǔ)上刪除的位置,反則返回左結(jié)點(diǎn)補(bǔ)上
            // 說明刪除結(jié)點(diǎn)為單子結(jié)點(diǎn)的情況
            if (leftNode == null){
                return rightNode;
            } else if (rightNode == null){
                return leftNode;
            }

            // 通過查詢最小右結(jié)點(diǎn),獲取后繼結(jié)點(diǎn)
            Node minNode = minNode(rightNode);
            int minNodeValue = minNode.getValue();
            node.setValue(minNodeValue);
            // 刪除后繼結(jié)點(diǎn)
            Node tempRightNode = delete(rightNode, minNodeValue);
            node.setRightChildren(tempRightNode);
        }
        return node;
    }

    private Node minNode(Node node) {
        // 一直尋找最小值,知道左子節(jié)點(diǎn)為空為止
        Node leftNode = node.getLeftChildren();
        if (leftNode != null)
            return minNode(leftNode);
        return node;
    }

}

至此上面三中情況都予滿足。

總結(jié)

上面對二叉查找樹的操作都已介紹,但是正真使用中,是要結(jié)合實(shí)際業(yè)務(wù)進(jìn)行相關(guān)調(diào)整來滿足自己的需求,不然,一切的優(yōu)化手段都是假把式。二叉查找樹雖然好用,但是它也是有一定要求,在數(shù)據(jù)量不大的情況下,使用遍歷的方式,更加符合我們的要求,所以它使用場景一般是在海量數(shù)據(jù)的查詢,用來提查詢效率。

“二叉查找樹的概念和實(shí)現(xiàn)方法”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!


當(dāng)前名稱:二叉查找樹的概念和實(shí)現(xiàn)方法
文章路徑:http://weahome.cn/article/pcjiid.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部