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

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

java實現(xiàn)線索化二叉樹的前序、中序、后續(xù)的遍歷(完整代碼)

java實現(xiàn)線索化二叉樹的前序、中序、后續(xù)的遍歷

比如創(chuàng)建一個二叉樹

創(chuàng)新互聯(lián)公司是一家專注于成都網(wǎng)站設計、成都網(wǎng)站制作與策劃設計,井研網(wǎng)站建設哪家好?創(chuàng)新互聯(lián)公司做網(wǎng)站,專注于網(wǎng)站建設10余年,網(wǎng)設計領域的專業(yè)建站公司;建站業(yè)務涵蓋:井研等地區(qū)。井研做網(wǎng)站價格咨詢:18980820575

           1
       /       \
      3        6      
     / \         /       
    8  10  14
  • 線索化二叉樹幾個概念

    • n個節(jié)點的二叉鏈表中含有n+1
      【公式2n-(n-1)=n+1】個空指針域。利用二叉鏈表中的空指針域,存放指向該節(jié)點在某種遍歷次序下的前驅(qū)和后繼節(jié)點的指針(這種附加指針成為線索)。
      如下面的就是6+1=7個空指針域 (8,10,14各有連個指針沒有指向 6有一個)
    • 加上了線索的二叉鏈表稱為線索鏈表,相應的二叉樹稱為線索二叉樹。分為前序線索二叉樹、中序線索二叉樹、后序線索二叉樹
    • 一個節(jié)點的前一個節(jié)點,稱為前驅(qū)節(jié)點
    • 一個節(jié)點的后一個節(jié)點,稱為后繼節(jié)點
    • 線索化后的二叉樹,節(jié)點可能指向的是前驅(qū)或者后繼節(jié)點,也有可能指向的是本身的二叉樹的節(jié)點
  • 前序、中序、后序線索化和遍歷
//創(chuàng)建樹的節(jié)點
/**
 * 〈節(jié)點定義〉
 *
 * @author nick
 * @create 2019/9/17
 * @since 1.0.0
 */
@Data
public class HeroNode {
    private int no;
    private String name;
    /**
     * //默認null
     */
    private HeroNode left;
    /**
     * //默認null
     */
    private HeroNode right;

    /**
     * //父節(jié)點的指針(為了后序線索化使用)
     */
    private HeroNode parent;

    /**
     * //說明
     * //1. 如果leftType == 0 表示指向的是左子樹, 如果 1 則表示指向前驅(qū)結(jié)點
     * //2. 如果rightType == 0 表示指向是右子樹, 如果 1表示指向后繼結(jié)點
     */
    private int leftType;
    private int rightType;

    public HeroNode(int no, String name) {
        this.no = no;
        this.name = name;
    }

    @Override
    public String toString() {
        return "HeroNode [no=" + no + ", name=" + name + "]";
    }

}
/**
 * 〈線索化二叉樹〉
 * 1
 * /   \
 * 3     6
 * / \   /
 * 8  10 14
 *
 * @author nick
 * @create 2019/9/17
 * @since 1.0.0
 */
public class ThreadedBinaryTree {
    private HeroNode root;

    /**
     * 為了實現(xiàn)線索化,需要創(chuàng)建要給指向當前結(jié)點的前驅(qū)結(jié)點的指針
     * 在遞歸進行線索化時,pre 總是保留前一個結(jié)點
     */
    private HeroNode pre = null;

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

    /**
     * 重載一把threadedNodes方法
     */
    public void threadedNodes() {
        this.threadedNodes(root);
    }

    /**
     * 重載一把threadedNodesPre方法
     */
    public void threadedNodesPre() {
        this.threadedNodesPre(root);
    }

    /**
     * 重載一把threadedNodesAfter方法
     */
    public void threadedNodesAfter() {
        this.threadedNodesAfter(root);
    }

    /***********************遍歷線索化二叉樹開始**********************/

    /**
     * 中序遍歷線索化二叉樹的方法
     * 

*/ public void threadedList() { //定義一個變量,存儲當前遍歷的結(jié)點,從root開始 HeroNode node = root; while ( node != null ) { //循環(huán)的找到leftType == 1的結(jié)點,第一個找到就是8結(jié)點 //后面隨著遍歷而變化,因為當leftType==1時,說明該結(jié)點是按照線索化 //處理后的有效結(jié)點 while ( node.getLeftType() == 0 ) { node = node.getLeft(); } //打印當前這個結(jié)點 System.out.println(node); //如果當前結(jié)點的右指針指向的是后繼結(jié)點,就一直輸出 while ( node.getRightType() == 1 ) { //獲取到當前結(jié)點的后繼結(jié)點 node = node.getRight(); System.out.println(node); } //替換這個遍歷的結(jié)點 node = node.getRight(); } } /** * 前序線索化二叉樹遍歷方法 * 1 * / \ * 3 6 * / \ / * 8 10 14 *

* {1,3,8,10,6,14} */ public void threadedListPre() { //定義一個變量,存儲當前遍歷的結(jié)點,從root開始 HeroNode node = root; while ( node != null ) { while ( node.getLeftType() == 0 ) { //如果是葉子節(jié)點,非前驅(qū)節(jié)點,打印當前這個結(jié)點 System.out.print(node + ","); node = node.getLeft(); } System.out.print(node + ","); //替換這個遍歷的結(jié)點 node = node.getRight(); } } /** * 后序線索化二叉樹遍歷方法 *

* 注意后序有點復雜,需要建立二叉樹的時候,將節(jié)點的parent進行賦值,否則不能遍歷成功 * 1 * / \ * 3 6 * / \ / * 8 10 14 *

* {8,10,3,1,14,6} * 1. 如果leftType == 0 表示指向的是左子樹, 如果 1 則表示指向前驅(qū)結(jié)點 * 2. 如果rightType == 0 表示指向是右子樹, 如果 1表示指向后繼結(jié)點 */ public void threadedListAfter() { //1、找后序遍歷方式開始的節(jié)點 HeroNode node = root; while ( node != null && node.getLeftType() == 0 ) { node = node.getLeft(); } while ( node != null ) { //右節(jié)點是線索 if (node.getRightType() == 1) { System.out.print(node + ", "); pre = node; node = node.getRight(); } else { //如果上個處理的節(jié)點是當前節(jié)點的右節(jié)點 if (node.getRight() == pre) { System.out.print(node + ", "); if (node == root) { return; } pre = node; node = node.getParent(); } else { //如果從左節(jié)點的進入則找到有子樹的最左節(jié)點 node = node.getRight(); while ( node != null && node.getLeftType() == 0 ) { node = node.getLeft(); } } } } } /***********************遍歷線索化二叉樹結(jié)束**********************/ /****************線索化二叉樹開始********************************/ /** * 中序線索化 * 得到的數(shù)組{8, 3, 10, 1, 14, 6} * 1 * / \ * 3 6 * / \ / * 8 10 14 * * @param node 就是當前需要線索化的結(jié)點 */ public void threadedNodes(HeroNode node) { //如果node==null, 不能線索化 if (node == null) { return; } //(一)先線索化左子樹 threadedNodes(node.getLeft()); //(二)線索化當前結(jié)點[有難度] //處理當前結(jié)點的前驅(qū)結(jié)點 //以8結(jié)點來理解 //8結(jié)點的.left = null , 8結(jié)點的.leftType = 1 if (null == node.getLeft()) { //讓當前結(jié)點的左指針指向前驅(qū)結(jié)點 node.setLeft(pre); //修改當前結(jié)點的左指針的類型,指向前驅(qū)結(jié)點 node.setLeftType(1); } //處理后繼結(jié)點,是下一次進行處理,有點不好理解 if (pre != null && pre.getRight() == null) { //讓前驅(qū)結(jié)點的右指針指向當前結(jié)點 pre.setRight(node); //修改前驅(qū)結(jié)點的右指針類型 pre.setRightType(1); } //!!! 每處理一個結(jié)點后,讓當前結(jié)點是下一個結(jié)點的前驅(qū)結(jié)點 pre = node; //(三)在線索化右子樹 threadedNodes(node.getRight()); } /** * 前序線索化 * 變成數(shù)組后{1,3,8,10,6,14} * 1 * / \ * 3 6 * / \ / * 8 10 14 * * @param node 就是當前需要線索化的結(jié)點 */ public void threadedNodesPre(HeroNode node) { //如果node==null, 不能線索化 if (node == null) { return; } //左指針為空,將左指針指向前驅(qū)節(jié)點 //8結(jié)點的.left = 上一個節(jié)點 , 8結(jié)點的.leftType = 1 if (node.getLeft() == null) { //讓當前結(jié)點的左指針指向前驅(qū)結(jié)點 node.setLeft(pre); //修改當前結(jié)點的左指針的類型,指向前驅(qū)結(jié)點 node.setLeftType(1); } //處理后繼結(jié)點,是下一次進行處理,有點不好理解 if (pre != null && pre.getRight() == null) { //讓前驅(qū)結(jié)點的右指針指向當前結(jié)點 pre.setRight(node); //修改前驅(qū)結(jié)點的右指針類型 pre.setRightType(1); } //!!! 每處理一個結(jié)點后,讓當前結(jié)點是下一個結(jié)點的前驅(qū)結(jié)點 pre = node; //(一)先線索化左子樹 if (node.getLeftType() != 1) { threadedNodesPre(node.getLeft()); } //(三)再線索化右子樹 if (node.getRightType() != 1) { threadedNodesPre(node.getRight()); } } /** * 后序線索化 * 變成數(shù)組后{8,10,3,1,14,6} * * @param node */ public void threadedNodesAfter(HeroNode node) { //如果node==null, 不能線索化 if (node == null) { return; } //(一)先線索化左子樹 threadedNodesAfter(node.getLeft()); //(三)再線索化右子樹 threadedNodesAfter(node.getRight()); //左指針為空,將左指針指向前驅(qū)節(jié)點 //8結(jié)點的.left = 上一個節(jié)點 , 8結(jié)點的.leftType = 1 if (node.getLeft() == null) { //讓當前結(jié)點的左指針指向前驅(qū)結(jié)點 node.setLeft(pre); //修改當前結(jié)點的左指針的類型,指向前驅(qū)結(jié)點 node.setLeftType(1); } //處理后繼結(jié)點,是下一次進行處理,有點不好理解 if (pre != null && pre.getRight() == null) { //讓前驅(qū)結(jié)點的右指針指向當前結(jié)點 pre.setRight(node); //修改前驅(qū)結(jié)點的右指針類型 pre.setRightType(1); } //!!! 每處理一個結(jié)點后,讓當前結(jié)點是下一個結(jié)點的前驅(qū)結(jié)點 pre = node; } /*********************線索化結(jié)束*********************************/ }

//測試二叉樹的遍歷

/**
 * 〈線索化二叉樹測試〉
 *
 * @author nick
 * @create 2019/9/17
 * @since 1.0.0
 */
public class ThreadedBinaryTreeTest extends Tester {
    @Test
    public void testPolandNotation() throws Exception {

        //測試一把中序線索二叉樹的功能 以數(shù)組{8, 3, 10, 1, 14, 6}為例

        /**
         *          1
         *        /   \
         *       3     6
         *      / \   /
         *     8  10 14
         */

        HeroNode root = new HeroNode(1, "java");
        HeroNode node2 = new HeroNode(3, "C#");
        HeroNode node3 = new HeroNode(6, "Python");
        HeroNode node4 = new HeroNode(8, "C++");
        HeroNode node5 = new HeroNode(10, "GO");
        HeroNode node6 = new HeroNode(14, "Dephi");

        //二叉樹,后面我們要遞歸創(chuàng)建, 現(xiàn)在簡單處理使用手動創(chuàng)建
        root.setLeft(node2);
        root.setRight(node3);
        node2.setLeft(node4);
        node2.setRight(node5);
        node3.setLeft(node6);

        //*************測試中序線索化***************//

        System.out.println("==========中序線索化開始=============");
        System.out.println("{8, 3, 10, 1, 14, 6}");
        ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree();
        threadedBinaryTree.setRoot(root);
        threadedBinaryTree.threadedNodes();

        //測試: 以10號節(jié)點測試
        HeroNode leftNode = node5.getLeft();
        HeroNode rightNode = node5.getRight();
        System.out.println("10號結(jié)點的前驅(qū)結(jié)點是 =" + leftNode); //3
        System.out.println("10號結(jié)點的后繼結(jié)點是=" + rightNode); //1

        //當線索化二叉樹后,能在使用原來的遍歷方法
        //threadedBinaryTree.infixOrder();
        System.out.println("中序使用線索化的方式遍歷 線索化二叉樹");
        threadedBinaryTree.threadedList(); // 8, 3, 10, 1, 14, 6
        //********************中序結(jié)束******************//

        //******************前序*****************//
        System.out.println("==========前序線索化開始=============");
        System.out.println("{1,3,8,10,6,14}");

        //前序:{1,3,8,10,6,14}
        ThreadedBinaryTree threadedBinaryTreePre = new ThreadedBinaryTree();
        threadedBinaryTreePre.setRoot(root);
        threadedBinaryTreePre.threadedNodesPre();

        //測試: 以10號節(jié)點測試
        HeroNode leftNodePre = node4.getLeft();
        HeroNode rightNodePre = node4.getRight();
        System.out.println("8號結(jié)點的前驅(qū)結(jié)點是 =" + leftNodePre); //3
        System.out.println("8號結(jié)點的后繼結(jié)點是=" + rightNodePre); //10

        HeroNode leftNodetenPre = node5.getLeft();
        HeroNode rightNodetenPre = node5.getRight();
        System.out.println("10號結(jié)點的前驅(qū)結(jié)點是 =" + leftNodetenPre); //8
        System.out.println("10號結(jié)點的后繼結(jié)點是=" + rightNodetenPre); //6

        System.out.println("前序使用線索化的方式遍歷 線索化二叉樹");
        threadedBinaryTreePre.threadedListPre();//{1,3,8,10,6,14}

        //******************前序結(jié)束*****************//

        //******************后序*****************//

        //如果是后序,需要創(chuàng)建二叉樹的時候,將parent進行保存。這個是用于后續(xù)二叉樹的遍歷的

        node2.setParent(root);
        node3.setParent(root);
        node4.setParent(node2);
        node5.setParent(node2);
        node6.setParent(node3);

        System.out.println("==========后序線索化開始=============");
        System.out.println("{8,10,3,14,6,1}");
        //后序:{8,10,3,14,6,1}
        ThreadedBinaryTree threadedBinaryTreeAfter = new ThreadedBinaryTree();
        threadedBinaryTreeAfter.setRoot(root);
        threadedBinaryTreeAfter.threadedNodesAfter();

        HeroNode leftNodeAfter = node4.getLeft();
        HeroNode rightNodeAfter = node4.getRight();
        System.out.println("8號結(jié)點的前驅(qū)結(jié)點是 =" + leftNodeAfter); //null
        System.out.println("8號結(jié)點的后繼結(jié)點是=" + rightNodeAfter); //10

        HeroNode leftNodetenAfter = node5.getLeft();
        HeroNode rightNodetenAfter = node5.getRight();
        System.out.println("10號結(jié)點的前驅(qū)結(jié)點是 =" + leftNodetenAfter); //8
        System.out.println("10號結(jié)點的后繼結(jié)點是=" + rightNodetenAfter); //3

        System.out.println("后序使用線索化的方式遍歷 線索化二叉樹");
        threadedBinaryTreeAfter.threadedListAfter();//{8,10,3,14,6,1}

    }
}
  • 前序和中序差不多,比較好理解。后序比較難以理解。不過結(jié)合代碼后,斷點執(zhí)行,看一下過程,對理解有好處。特別注意是后序遍歷要在二叉樹創(chuàng)建的時候,將parent進行保存設置。

當前名稱:java實現(xiàn)線索化二叉樹的前序、中序、后續(xù)的遍歷(完整代碼)
網(wǎng)站網(wǎng)址:http://weahome.cn/article/pgdeid.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部