二叉搜索樹的增刪查

import java.util.NoSuchElementException;
import java.util.Stack;

public class BinarySearchTree {

    private Node root;

    public void put(int item) {
        if (root == null) {
            root = new Node(item);
        } else {
            Node node = new Node(item);
            Node parent = searchNoChildNode(item);
            node.parent = parent;
            if (item > parent.item) {
                parent.rightChild = node;
            } else if (item < parent.item) {
                parent.leftChild = node;
            }
            // System.out.println("node=" + node);
            // System.out.println("parent=" + parent);
        }
    }

    /**
     * 尋找適合的沒有子節(jié)點(diǎn)的node
     * 
     * @param item
     * @return
     */
    private Node searchNoChildNode(int item) {
        Node node = root;
        while (node != null) {
            if (item < node.item) {
                if (node.leftChild == null)
                    return node;
                node = node.leftChild;
            } else {
                if (node.rightChild == null)
                    return node;
                node = node.rightChild;
            }
        }
        return node;
    }

    /**
     * 中序:左中右 思路:壓入當(dāng)前節(jié)點(diǎn)连锯,判斷左孩子是否為空住拭, 若為空,則彈出該節(jié)點(diǎn),并打印尸变,并以右孩子為當(dāng)前節(jié)點(diǎn),重復(fù)操作莉兰;
     * 若不為空,則以左孩子做當(dāng)前節(jié)點(diǎn)秦效,重復(fù)操作
     * 
     * 重復(fù)操作的意思是呢。涎嚼。阱州。就是壓入堆棧,判斷左孩子是否為空法梯。苔货。。
     */
    public void middleOrder() {
        Stack<Node> stack = new Stack<>();
        Node node = root;
        while (node != null || !stack.isEmpty()) {
            if (node != null) {
                stack.push(node);
                node = node.leftChild;
            } else {
                node = stack.pop();
                System.out.print(node.item + " ");
                node = node.rightChild;
            }
        }
        System.out.println();
    }

    /**
     * 移除一個(gè)數(shù)
     * 
     * @param data
     */
    public void remove(int item) {
        Node node = searchNode(item);
        System.out.println("刪除節(jié)點(diǎn):" + node);
        if (node == null)
            throw new NoSuchElementException();// 沒有當(dāng)前節(jié)點(diǎn)
        Node parent = node.parent;
        if (node.leftChild == null && node.rightChild == null) {// 沒有子節(jié)點(diǎn)立哑,直接刪除就行了
            if (parent == null) {// 沒有父節(jié)點(diǎn),說明是root節(jié)點(diǎn)
                root = null;// 直接將root置空
            } else {
                node.parent = null;
                if (parent.leftChild == node) {// 如果是父節(jié)點(diǎn)的左子節(jié)點(diǎn)夜惭,則設(shè)置父節(jié)點(diǎn)左子節(jié)點(diǎn)為空
                    parent.leftChild = null;
                } else {// 反之,設(shè)置右子節(jié)點(diǎn)為空
                    parent.rightChild = null;
                }
            }
        } else if (node.leftChild != null && node.rightChild == null) {// 有左子節(jié)點(diǎn)铛绰,沒有右子節(jié)點(diǎn)
            if (parent == null) {// root節(jié)點(diǎn)
                root = node.leftChild;// 將root節(jié)點(diǎn)設(shè)置為其左子節(jié)點(diǎn)
            } else {
                node.parent = null;
                if (parent.leftChild == node) {// 如果是父節(jié)點(diǎn)的左子節(jié)點(diǎn)滥嘴,則把自己的左子節(jié)點(diǎn)設(shè)置給父左子節(jié)點(diǎn)
                    parent.leftChild = node.leftChild;
                } else {// 反之,設(shè)置給父右子節(jié)點(diǎn)
                    parent.rightChild = node.leftChild;
                }
                node.leftChild.parent = parent;
            }
        } else if (node.leftChild == null && node.rightChild != null) {// 沒有左子節(jié)點(diǎn)至耻,有右子節(jié)點(diǎn)
            if (parent == null) {
                root = node.rightChild;
            } else {
                node.parent = null;
                if (parent.leftChild == node) {
                    parent.leftChild = node.rightChild;
                } else {
                    parent.rightChild = node.rightChild;
                }
                node.rightChild.parent = parent;
            }
        } else if (node.leftChild != null && node.rightChild != null) {// 有左子節(jié)點(diǎn)若皱,也有右子節(jié)點(diǎn)
            Node mostLeftNode = searchMostLeftNode(node.rightChild);// 搜索右子節(jié)點(diǎn)的最左子節(jié)點(diǎn)
            Node mostLeftNodeP = mostLeftNode.parent;// 最左子節(jié)點(diǎn)的父節(jié)點(diǎn)
            if (parent == null) {// 是root節(jié)點(diǎn)
                root = mostLeftNode;// 將root節(jié)點(diǎn)設(shè)置為右子節(jié)點(diǎn)的最左子節(jié)點(diǎn)
            } else {
                // 最左子節(jié)點(diǎn)替代刪除節(jié)點(diǎn)
                if (parent.leftChild == node) {
                    parent.leftChild = mostLeftNode;
                } else {
                    parent.rightChild = mostLeftNode;
                }
            }
            // 先處理最左子節(jié)點(diǎn)目前的父節(jié)點(diǎn)和右子節(jié)點(diǎn)的賦值
            // 最左子節(jié)點(diǎn)的父節(jié)點(diǎn)的左子節(jié)點(diǎn),設(shè)置為最左子節(jié)點(diǎn)的右子節(jié)點(diǎn)尘颓,因?yàn)樽钭笞庸?jié)點(diǎn)沒有左子節(jié)點(diǎn)
            mostLeftNodeP.leftChild = mostLeftNode.rightChild;
            if (mostLeftNode.rightChild != null) {
                mostLeftNode.rightChild.parent = mostLeftNodeP;
            }

            // 再給最左子節(jié)點(diǎn)的父節(jié)點(diǎn)和左右子節(jié)點(diǎn)賦上新值
            // 最左子節(jié)點(diǎn)替代了了刪除節(jié)點(diǎn)走触,所以其父節(jié)點(diǎn),孩子節(jié)點(diǎn)疤苹,都要等于刪除節(jié)點(diǎn)的父節(jié)點(diǎn)互广,孩子節(jié)點(diǎn)
            mostLeftNode.parent = parent;
            mostLeftNode.leftChild = node.leftChild;
            mostLeftNode.rightChild = node.rightChild;
            // 刪除節(jié)點(diǎn)的兩個(gè)子節(jié)點(diǎn)的父節(jié)點(diǎn),也要相應(yīng)的設(shè)置為最左子節(jié)點(diǎn)
            node.leftChild.parent = mostLeftNode;
            node.rightChild.parent = mostLeftNode;
        }
    }

    /**
     * 搜索該節(jié)點(diǎn)的最左子節(jié)點(diǎn)
     * 
     * @param node
     * @return
     */
    private Node searchMostLeftNode(Node node) {
        Node leftNode = node;
        while (leftNode != null) {
            if (leftNode.leftChild == null)
                return leftNode;
            leftNode = leftNode.leftChild;
        }
        return leftNode;
    }

    /**
     * 查詢指定節(jié)點(diǎn)
     * 
     * @param item
     * @return
     */
    public Node searchNode(int item) {
        Node node = root;
        while (node != null) {
            if (item > node.item) {
                node = node.rightChild;
            } else if (item < node.item) {
                node = node.leftChild;
            } else {
                return node;
            }
        }
        return null;
    }

    private class Node {
        private int item;
        private Node parent;
        private Node leftChild;
        private Node rightChild;

        public Node(int item) {
            this.item = item;
        }

        @Override
        public String toString() {
            String p = null;
            if (parent != null) {
                p = String.valueOf(parent.item);
            }
            String l = null;
            if (leftChild != null) {
                l = String.valueOf(leftChild.item);
            }
            String r = null;
            if (rightChild != null) {
                r = String.valueOf(rightChild.item);
            }
            return "Node [item=" + item + ", parent=" + p + ", leftChild=" + l + ", rightChild=" + r + "]";
        }

    }

    public static void main(String[] args) {
        int[] items = { 20, 31, 10, 12, 54, 23, 11, 5, 100, 43, 26 };
        BinarySearchTree tree = new BinarySearchTree();
        for (int i : items) {
            tree.put(i);
        }
        System.out.println("初始節(jié)點(diǎn)");
        tree.middleOrder();

        Node n = tree.searchNode(54);
        System.out.println("查找節(jié)點(diǎn):" + n);

        tree.remove(20);
        tree.middleOrder();

        tree.remove(5);
        tree.middleOrder();

        tree.remove(100);
        tree.middleOrder();

        tree.remove(43);
        tree.middleOrder();

        tree.remove(23);
        tree.middleOrder();

        System.out.println("插入節(jié)點(diǎn):25");
        tree.put(25);
        tree.middleOrder();
    }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卧土,一起剝皮案震驚了整個(gè)濱河市惫皱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌尤莺,老刑警劉巖旅敷,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颤霎,居然都是意外死亡媳谁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進(jìn)店門友酱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晴音,“玉大人,你說我怎么就攤上這事缔杉〈冈辏” “怎么了?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵或详,是天一觀的道長系羞。 經(jīng)常有香客問我加缘,道長,這世上最難降的妖魔是什么觉啊? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮沈贝,結(jié)果婚禮上杠人,老公的妹妹穿的比我還像新娘。我一直安慰自己宋下,他們只是感情好嗡善,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著学歧,像睡著了一般罩引。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枝笨,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天袁铐,我揣著相機(jī)與錄音,去河邊找鬼横浑。 笑死剔桨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的徙融。 我是一名探鬼主播洒缀,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼欺冀!你這毒婦竟也來了树绩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤隐轩,失蹤者是張志新(化名)和其女友劉穎饺饭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體职车,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砰奕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了提鸟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片军援。...
    茶點(diǎn)故事閱讀 39,754評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖称勋,靈堂內(nèi)的尸體忽然破棺而出胸哥,到底是詐尸還是另有隱情,我是刑警寧澤赡鲜,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布空厌,位于F島的核電站庐船,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嘲更。R本人自食惡果不足惜筐钟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赋朦。 院中可真熱鬧篓冲,春花似錦、人聲如沸宠哄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毛嫉。三九已至诽俯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間承粤,已是汗流浹背暴区。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辛臊,地道東北人颜启。 一個(gè)月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像浪讳,于是被迫代替她去往敵國和親缰盏。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評論 2 354

推薦閱讀更多精彩內(nèi)容