二叉樹和二叉搜索樹Java代碼示例

原理

后續(xù)原理妒穴,先上代碼

代碼

樹節(jié)點

package per.lihao.tree;

/**
 * @author : LiHao
 * @date : 2018/12/4 9:59
 */
public class TreeNode {
    /**
     * 關鍵字
     */
    private int data;

    /**
     * 左子樹節(jié)點
     */
    private TreeNode lnode;

    /**
     * 右子樹節(jié)點
     */
    private TreeNode rnode;

    /**
     * 父節(jié)點
     */
    private TreeNode parent;

    private boolean stackFirst = false;

    public TreeNode getParent() {
        return parent;
    }

    public void setParent(TreeNode parent) {
        this.parent = parent;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public TreeNode getLnode() {
        return lnode;
    }

    public void setLnode(TreeNode lnode) {
        this.lnode = lnode;
    }

    public TreeNode getRnode() {
        return rnode;
    }

    public void setRnode(TreeNode rnode) {
        this.rnode = rnode;
    }

    public boolean isStackFirst() {
        return stackFirst;
    }

    public void setStackFirst(boolean stackFirst) {
        this.stackFirst = stackFirst;
    }

    public TreeNode(){}

    public TreeNode(int k){
        data = k;
    }
}

二叉樹

package per.lihao.tree;

import java.util.Stack;

/**
 * 二叉樹
 * @author : LiHao
 * @date : 2018/12/26 10:41
 */
public class BinaryTree {
    /**
     * 根節(jié)點
     */
    protected TreeNode root;

    public BinaryTree(){}
    /**
     * 構造函數(shù)
     * @param node
     */
    public BinaryTree(TreeNode node){
        root = node;
    }

    public TreeNode getRoot() {
        return root;
    }

    public void setRoot(TreeNode root) {
        this.root = root;
    }

    /**
     * 遞歸
     * 中序遍歷根節(jié)點
     */
    public void inOrderTraversalRecursion(){
        inOrderTraversalRecursion(root);
        System.out.println();
    }

    /**
     * 遞歸
     * 中序遍歷
     * @param node
     */
    protected void inOrderTraversalRecursion(TreeNode node){
        if (node==null){
            return;
        }
        inOrderTraversalRecursion(node.getLnode());
        System.out.print(node.getData()+" ");
        inOrderTraversalRecursion(node.getRnode());
    }

    /**
     * 循環(huán)
     * 中序遍歷根節(jié)點
     */
    public void inOrderTraversalLoop(){
        inOrderTraversalLoop(root);
        System.out.println();
    }

    /**
     * 循環(huán)
     * 中序遍歷
     * @param node
     */
    protected void inOrderTraversalLoop(TreeNode node){
        Stack<TreeNode> stack = new Stack<>();
        TreeNode currentNode = node;
        TreeNode temp;
        // 一直往左找,同時沿線的節(jié)點放入棧借宵,直到最左邊的子節(jié)點為空
        // 出棧,并打印該節(jié)點,然后轉(zhuǎn)向該節(jié)點的右子節(jié)點
        while (currentNode!=null || !stack.isEmpty()){
            while (currentNode!=null){
                stack.push(currentNode);
                currentNode = currentNode.getLnode();
            }
            if (!stack.isEmpty()){
                temp = stack.pop();
                System.out.print(temp.getData() + " ");
                currentNode = temp.getRnode();
            }
        }
    }

    /**
     * 遞歸
     * 前序遍歷根節(jié)點
     */
    public void preOrderTraversalRecursion(){
        preOrderTraversalRecursion(root);
        System.out.println();
    }
    /**
     * 遞歸
     * 前序遍歷
     * @param node
     */
    protected void preOrderTraversalRecursion(TreeNode node){
        if (node==null){
            return;
        }
        System.out.print(node.getData() + " ");
        preOrderTraversalRecursion(node.getLnode());
        preOrderTraversalRecursion(node.getRnode());
    }

    /**
     * 循環(huán)
     * 前序遍歷根節(jié)點
     */
    public void preOrderTraversalLoop(){
        preOrderTraversalLoop(root);
        System.out.println();
    }

    /**
     * 循環(huán)
     * 前序遍歷
     * @param node
     */
    protected void preOrderTraversalLoop(TreeNode node){
        Stack<TreeNode> stack = new Stack<>();
        TreeNode currentNode = node;
        TreeNode temp;
        // 一直往左找了嚎,同時打印沿線的節(jié)點并放入棧,直到最左邊的子節(jié)點為空
        // 出棧,然后轉(zhuǎn)向該節(jié)點的右子節(jié)點
        while (currentNode!=null || !stack.isEmpty()){
            while (currentNode!=null){
                System.out.print(currentNode.getData() + " ");
                stack.push(currentNode);
                currentNode = currentNode.getLnode();
            }
            if (!stack.isEmpty()){
                temp = stack.pop();
                currentNode = temp.getRnode();
            }
        }
    }

    /**
     * 遞歸
     * 后序遍歷根節(jié)點
     */
    public void postOrderTraversalRecursion(){
        postOrderTraversalRecursion(root);
        System.out.println();
    }

    /**
     * 遞歸
     * 后序遍歷
     * @param node
     */
    protected void postOrderTraversalRecursion(TreeNode node){
        if (node==null){
            return;
        }
        postOrderTraversalRecursion(node.getLnode());
        postOrderTraversalRecursion(node.getRnode());
        System.out.print(node.getData() + " ");
    }

    /**
     * 循環(huán)
     * 后序遍歷根節(jié)點
     */
    public void postOrderTraversalLoop(){
        postOrderTraversalLoop(root);
        System.out.println();
    }

    /**
     * 循環(huán)
     * 后續(xù)遍歷
     * @param node
     */
    public void postOrderTraversalLoop(TreeNode node){
        Stack<TreeNode> stack = new Stack<>();
        TreeNode currentNode = node;
        TreeNode temp;
        // 先一直往左找歪泳,沿線節(jié)點放入棧萝勤,且節(jié)點處的stackfirst=false
        // 當遇到左孩子為空時,取其右孩子繼續(xù)尋找呐伞,此時父節(jié)點的stackfirst=true
        // 為true時打印節(jié)點
        while (currentNode!=null || !stack.isEmpty()){
            while (currentNode!=null){
                stack.push(currentNode);
                currentNode = currentNode.getLnode();
            }
            if (!stack.isEmpty()){
                // 不取出節(jié)點敌卓,先判斷其stackfirst值
                temp = stack.peek();
                if (temp.isStackFirst()){
                    temp = stack.pop();
                    System.out.print(temp.getData() + " ");
                }else {
                    temp.setStackFirst(true);
                    currentNode = temp.getRnode();
                }
            }
        }
    }

    /**
     * 生成測試樹
     *         10
     *      /    \
     *    3      12
     *         /
     *       34
     *         \
     *         23
     * @return node
     */
    public static TreeNode makeTreeTest(){
        TreeNode root = new TreeNode(10);
        root.setLnode(new TreeNode(3));
        TreeNode node1 = new TreeNode(12);
        TreeNode node2 = new TreeNode(34);
        TreeNode node3 = new TreeNode(23);
        node1.setLnode(node2);
        node2.setRnode(node3);
        root.setRnode(node1);
        return root;
    }

}

二叉搜索樹

package per.lihao.tree;

/**
 * 二叉搜索樹/二叉排序樹
 * @author : LiHao
 * @date : 2018/12/24 15:21
 */
public class BinarySearchTree extends BinaryTree {

    /**
     * 插入數(shù)據(jù) 自動生成樹結(jié)構
     * @param k int
     */
    public void insert(int k){
        TreeNode node = new TreeNode(k);
        insertNode(node);
    }

    /**
     * 插入數(shù)據(jù)數(shù)組 自動生成樹結(jié)構
     * @param ks int[]
     */
    public void insert(int[] ks){
        for (int k:ks){
            insert(k);
        }
    }

    /**
     * 插入節(jié)點對象 構造BST樹
     * @param node
     */
    private void insertNode(TreeNode node){
        // 若根節(jié)點為空,則返回當前節(jié)點為根節(jié)點
        if (root==null){
            root = node;
            return;
        }
        TreeNode temp = root;
        while (true){
            if (node.getData()<=temp.getData()){
                //若有左子樹伶氢,說明還需繼續(xù)比較趟径,移動到左子樹的根節(jié)點
                if (temp.getLnode()!=null){
                    temp = temp.getLnode();
                }
                //若沒有左子樹,說明此node可以變作葉子節(jié)點
                else {
                    temp.setLnode(node);
                    node.setParent(temp);
                    return;
                }
            }else {
                //若有右子樹癣防,說明還需繼續(xù)比較蜗巧,移動到右子樹的根節(jié)點
                if (temp.getRnode()!=null){
                    temp = temp.getRnode();
                }else {
                    temp.setRnode(node);
                    node.setParent(temp);
                    return;
                }
            }
        }
    }

    /**
     * 查詢關鍵字節(jié)點,無則返回null
     * @param k 關鍵字
     * @return
     */
    public TreeNode search(int k){
        TreeNode temp = root;
        while (temp != null){
            if (temp.getData() == k){
                return temp;
            }else if (temp.getData()>=k){
                temp = temp.getLnode();
            }else{
                temp = temp.getRnode();
            }
        }
        return temp;
    }

    /**
     * 查找關鍵字k的前驅(qū)節(jié)點蕾盯,若沒有 則返回null
     * @param k
     * @return
     */
    public TreeNode searchPredecessor(int k){
        TreeNode node = search(k);
        if (node==null){
            return node;
        }
        // 若有左子樹幕屹,則前驅(qū)為左子樹中最右邊的節(jié)點
        TreeNode temp = node.getLnode();
        while (temp!=null){
            if (temp.getRnode()!=null){
                temp = temp.getRnode();
            }else {
                return temp;
            }
        }
        // 若無左子樹,則需要尋找當前節(jié)點的第一個有右孩子且左孩子中沒有該節(jié)點的祖先
        if (temp==null){
            temp = node.getParent();
            while (temp!=null){
                // 左父母的左子樹如果為空级遭,則前驅(qū)就是左父母
                // 若是右父母望拖,需要找到其右父母的左父母
                if (temp.getLnode()==null){
                    break;
                }else {
                    if (temp.getLnode().getData()==k){
                        temp = temp.getParent();
                    }else {
                        break;
                    }
                }
            }
        }
        return temp;
    }

    /**
     * 查找關鍵字k的后繼節(jié)點,若沒有 則返回null
     * @param k 關鍵字
     * @return
     */
    public TreeNode searchSuccessor(int k){
        // 首先查找命中的節(jié)點
        TreeNode node = search(k);
        if (node==null){
            return null;
        }
        TreeNode temp = node.getRnode();
        while (temp!=null){
            if (temp.getLnode()!=null){
                temp = temp.getLnode();
            }else {
                return temp;
            }
        }
        if (temp==null){
            temp = node.getParent();
            while (temp!=null){
                if (temp.getRnode()==null){
                    break;
                }else {
                    if (temp.getRnode().getData()==k){
                        temp = temp.getParent();
                    }else {
                        break;
                    }
                }
            }
        }
        return temp;
    }

    /**
     * 刪除某節(jié)點
     * @param k
     */
    public void delete(int k){
        // 首先查找k 不存在則返回
        TreeNode node = search(k);
        if (node==null){
            return;
        }

        if (node.getLnode()!=null && node.getRnode()!=null){
            // 查詢其前驅(qū)節(jié)點
            TreeNode pre = searchPredecessor(k);
            node.setData(pre.getData());
            if (pre.getParent()==node){
                if (pre.getLnode()!=null){
                    TreeNode preLnode = pre.getLnode();
                    preLnode.setParent(node);
                }
                node.setLnode(pre.getLnode());
            }else {
                TreeNode preParent = pre.getParent();
                preParent.setRnode(pre.getLnode());
                if (pre.getLnode()!=null){
                    TreeNode preLnode = pre.getLnode();
                    preLnode.setParent(preParent);
                }
            }
        }else if (node.getRnode()==null && node.getLnode()==null){
            TreeNode parent = node.getParent();
            if (node==parent.getLnode()){
                parent.setLnode(null);
            }else {
                parent.setRnode(null);
            }
            node.setParent(null);
        }else {
            TreeNode parent = node.getParent();
            TreeNode child = (node.getLnode()!=null)?node.getLnode():node.getRnode();
            if (node==parent.getLnode()){
                parent.setLnode(child);
            }else {
                parent.setRnode(child);
            }
            child.setParent(parent);
            node.setParent(null);
        }
    }

    public static void main(String[] args) {
        BinarySearchTree bst = new BinarySearchTree();
        int[] a = {39,27,49,20,38,41,45,48,43};
        bst.insert(a);
        bst.inOrderTraversalLoop();
        bst.delete(49);
        bst.inOrderTraversalLoop();
    }
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挫鸽,一起剝皮案震驚了整個濱河市说敏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌丢郊,老刑警劉巖盔沫,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蚂夕,居然都是意外死亡迅诬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門婿牍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侈贷,“玉大人,你說我怎么就攤上這事等脂∏温” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵上遥,是天一觀的道長搏屑。 經(jīng)常有香客問我,道長粉楚,這世上最難降的妖魔是什么辣恋? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任亮垫,我火速辦了婚禮,結(jié)果婚禮上伟骨,老公的妹妹穿的比我還像新娘饮潦。我一直安慰自己,他們只是感情好携狭,可當我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布继蜡。 她就那樣靜靜地躺著,像睡著了一般逛腿。 火紅的嫁衣襯著肌膚如雪稀并。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天单默,我揣著相機與錄音碘举,去河邊找鬼。 笑死雕凹,一個胖子當著我的面吹牛殴俱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播枚抵,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼明场!你這毒婦竟也來了汽摹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤苦锨,失蹤者是張志新(化名)和其女友劉穎逼泣,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舟舒,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡拉庶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了秃励。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氏仗。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖夺鲜,靈堂內(nèi)的尸體忽然破棺而出皆尔,到底是詐尸還是另有隱情,我是刑警寧澤币励,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布慷蠕,位于F島的核電站,受9級特大地震影響食呻,放射性物質(zhì)發(fā)生泄漏流炕。R本人自食惡果不足惜澎现,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望每辟。 院中可真熱鬧剑辫,春花似錦、人聲如沸影兽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽峻堰。三九已至讹开,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捐名,已是汗流浹背旦万。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留镶蹋,地道東北人成艘。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像贺归,于是被迫代替她去往敵國和親淆两。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,554評論 2 349

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