• 【数据结构与算法】六、手动实现树结构代码示例


    上一篇【数据结构与算法】五、树结构-从二叉树到B+Tree

    1、二叉树:

    /**
     * 二叉树:
     *      就是单向链表中的节点中持有两个
     *      指向下一个引用的变量,且下一个
     *      引用不能去指向原有树中出现过的
     *      元素。
     *      二叉树的每个节点最多只能有两个子节点。
     *      如果有往回指向的子节点引用那么在查询时就会往回检索,
     *      那么这个数据结构就是图。
     *      增加、删除、修改的时间复杂度均为O(1),
     *      查询的时间复杂度为O(n),完全和链表一样
     * 
     * 二叉搜索树:
     *      在二叉树定义的基础上,附加一条对所有节点其
     *      左子树所有的节点必须小于根节点,右子树
     *      所有的节点必须大于根节点。
     *      
     *      因为其在增加删除、修改的时候都需要先查询一次应该存放的位置,
     *      所以其增加、删除、修改和查询的时间复杂度均为O(log(n))
     */
    public class BinarySearchTree {
        
        /*
         * 二叉树搜索树的根节点
         */
        private BinarySearchTreeNode<Integer> root;
        
        
        
        /**
         * 递归添加节点方法
         * @param root   根节点
         * @param item      值
         * @return  添加后的根节点
         */
        private BinarySearchTreeNode<Integer> addRecursive(BinarySearchTreeNode<Integer> root, int item) {
            //如果根节点为空,创建一个节点返回
            if (root == null) {
                return new BinarySearchTreeNode<Integer>(item);
            }
            //如果要添加的节点小于根节点则放到左子树中
            if (item < root.item) {
                root.left = addRecursive(root.left, item);
            } else if (item > root.item) {//如果要添加的节点大于根节点则放到右子树中
                root.right = addRecursive(root.right, item);
            } else {
                //如果要添加的节点等于根节点则返回根节点
                return root;
            }
         
            return root;
        }
        
        /**
         * 递归查询是否包含方法
         * @param root      根节点
         * @param item  需要查询的值
         * @return      是否包含
         */
        private boolean containsNodeRecursive(BinarySearchTreeNode<Integer> root, int item) {
            //如果根节点为空直接返回false
            if (root == null) {
                return false;
            } 
            //如果要查询的值就是根节点那么直接返回true
            if (item == root.item) {
                return true;
            } 
            //递归寻找:如果当前值小于等于根则递归左边,否则递归右边
            return item <= root.item
              ? containsNodeRecursive(root.left, item)
              : containsNodeRecursive(root.right, item);
        }
        
        
        
        /**
         * 对外暴露添加节点的方法
         * @param item  需要添加的元素
         */
        public void add(int item){
            this.root = addRecursive(root, item);
        }
        
        /**
         * 对外暴露是否包含节点的方法
         * @param item
         * @return
         */
        public boolean contains(int item){
            return containsNodeRecursive(root, item);
        }
        
        /**
         * 对外提供一个删除的方法
        * @param item		要删除的元素
        * @return		返回删除是否成功
         */
        public boolean remove(int item){
        	//将根节点设置为删除后的返回值
        	root = removeRecursive(root, item);
        	return true;
        }
        
        
        /**
         * 递归删除节点方法
        * @param current		需要删除的节点
        * @param item 	要删除的元素
        * @return		被删除的节点
         */
        private BinarySearchTreeNode<Integer> removeRecursive(
        				BinarySearchTreeNode<Integer> current,int item){
        	
        	//校验入参
        	if(current == null){
        		return null;
        	}
        	
        	//如果当前节点是要删除的节点就执行删除
        	if(current.item == item){
        		/*
            	 * 那么删除节点就需要分为三种情况:
            	 * 1、要删除的节点是叶子节点(无子节点的节点)
            	 * 2、有一个子节点的非叶子节点
            	 * 3、有两个子节点的非叶子节点
            	 */
            	//如果是叶子节点那么只需将父节点的引用断掉即可
            	if(current.left == null && current.right == null){
            		//这里在上层是将父节点赋值为返回值所以直接返回null
            		return null;
            	}
            	
            	//如果左边节点为空表示子节点是右边节点,就返回右节点
            	if(current.left == null){
            		return current.right;
            	}
            	//如果右边节点为空表示子节点是左边节点,就返回左节点
            	if(current.right == null){
            		return current.left;
            	}
            	
            	/*
            	 * 如果有两个节点,那么必须先找到删除后代替
            	 * 被删除节点位置的节点然后再执行删除,
            	 * 这里我是取右子树中大于被删除节点的最小的节点
            	 */
            	Integer smallestItem = findSmallestItem(current.right);
            	//用其右子树中大于被删除节点的最小节点代替
            	current.item = smallestItem;
            	//递归删除掉右子树
            	current.right = removeRecursive(current.right, smallestItem);
            	//然后返回当前节点
            	return current;
        	}
        	//如果需要删除的值小于当前节点的值那么就递归左边
        	if(item < current.item){
        		current.left = removeRecursive(current.left, item);
        		//然后返回当前节点即返回已经被删除节点的父节点
        		return current;
        	}
        	//如果果需要删除的值大于当前节点的值那么就递归右边
        	current.right = removeRecursive(current.right, item);
        	//然后返回当前节点即返回已经被删除节点的父节点
        	return current;
        }
        
        /**
         * 找到右子树中最小的大于根节点的节点
        * @param root	根节点
        * @return	找到的结果
         */
        private <E> E  findSmallestItem(BinarySearchTreeNode<E> root){
        	/*
        	 * 这里又需要递归,如果root.left == null说明找到了
        	 * 否则就继续递归寻找左子树知道找到为止
        	 */
        	return	root.left == null ? root.item : findSmallestItem(root.left);
        }
        
        
        
        
        /**
         * 一个私有的静态内部类作为二叉树的元素
         * 这里由于后面的算法题中需要使用到这个
         * 静态内部类,所以把其写成public的,并
         * 把其成员变量也写成public的
         * @author Peter
         */
        public static class BinarySearchTreeNode<E>{
            
            /*
             * 左边的子节点
             */
            public BinarySearchTreeNode<E>  left;
            
            /*
             * 右边的子节点
             */
            public BinarySearchTreeNode<E>  right;
            
            
            public  E item;
            
            public BinarySearchTreeNode(){
                
            }
            
            public BinarySearchTreeNode(E e){
                this.item=e;
            }
            
             @Override
             public String toString() {
                 if (item == null) {
                     return "null";
                 }
                 return item.toString();
             }
        }
    
    	public static void main(String[] args) {
    		
    	    
    	    
    
    	}
    	
    	
    
        public BinarySearchTreeNode<Integer> getRoot() {
            return root;
        }
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238

    2、跳表结构的实现

    /**
     * 跳表结构的实现
     * 为了方便不做泛型了直接用Integer
     * 
     * 跳表结构的特点:
     * 1、有多个层的数据;
     * 2、有多少层是由一个随机算法决定的;
     * 3、最底层包含整个跳表的所有元素;
     * 4、是采用空间换时间的思想实现的。
     * @author Peter
     */
    public class SkipList {
        
        private  static final byte HEAD_NODE=(byte)-1;
        
        private  static final byte ELEMENT_NODE=(byte)0;
        
        private  static final byte TAIL_NODE=(byte)1;
        
        
        private Node head;
        
        private Node tail;
        
        private int size;
        
        private int height=1;
        
        private Random random;
        
        public SkipList() {
            this.head=new Node(null,HEAD_NODE);
            this.tail=new Node(null,TAIL_NODE);
            head.right=tail;
            tail.left=head;
            this.random=new Random();
        }
        
        
        
        public int size(){
            return this.size;
        }
        
        public boolean contains(Integer e){
            //首先先寻找
            Node foundNode = this.find(e);
            /*
             * 如果找到的和我们要判断是否存在的
             * 相等,那么说明集合中包含这个元素。
             */
            return foundNode.item.equals(e);
        }
        
        
        public void add(Integer e){
            //首先找到应该添加的临近的节点
            Node nearNode = this.find(e);
            //然后创建一个要添加的节点
            Node toAddNode=new Node(e);
            //将要添加的节点的左边设置为原有的附近的节点
            toAddNode.left=nearNode;
            //将要添加的节点的右边设置为原有的附近的节点的右边
            toAddNode.right=nearNode.right;
            //将原有的附近的节点的右边节点的左边设置为要添加的节点
            nearNode.right.left=toAddNode;
            //将原有的附近的节点的右边设置为要添加的节点
            nearNode.right=toAddNode;
            
            //决定该放在哪一层
            int currentLayer=1;
            //用随机数决定是否需要提高层次    1 、2 、3、4
            while(random.nextInt(4)+1>2){
                
                //如果超过原有的层高了
                if(currentLayer>=this.height){
                    height++;
                    Node dummyHead=new Node(null, HEAD_NODE);
                    Node dummyTail=new Node(null, TAIL_NODE);
                    
                    dummyHead.right=dummyTail;
                    dummyHead.down=head;
                    head.up=dummyHead;
                    
                    dummyTail.left=dummyHead;
                    dummyTail.down=tail;
                    tail.up=dummyTail;
                    
                    head=dummyHead;
                    tail=dummyTail;
                }
                
                //这里说明还需要往左挪位置
                while(nearNode!=null && nearNode.up==null){
                    nearNode=nearNode.left;
                }
                nearNode=nearNode.up;
                
                //创建一个要添加节点的上层节点
                Node upToAddNode=new Node(e);
                //设置上层节点的链表关系
                upToAddNode.left=nearNode;
                upToAddNode.right=nearNode.right;
                upToAddNode.down=toAddNode;
                
                //设置临近节点的关系
                nearNode.right.left=upToAddNode;
                nearNode.right=upToAddNode;
                
                //设置要添加节点的关系
                toAddNode.up=upToAddNode;
                //可能循环提高层高所以
                toAddNode=upToAddNode;
                
                currentLayer++;
                
            }
            size++;
            
        }
        
        public void flushSkipList(){
            Node tempNode=head;
            //从最高层一层一层往下刷新
            for(int i=height;i>0;i--){
                System.out.print("总共:"+height+"层,当前层数:"+i);
                Node toFlushNode=tempNode.right;
                while(toFlushNode.type==ELEMENT_NODE){
                    System.out.print("-->"+toFlushNode.item);
                    toFlushNode=toFlushNode.right;
                }
                //本层打印完就换行
                System.out.println();
                tempNode=tempNode.down;
            }
            System.out.println("--------------------打印完毕-----------------------");
        }
        
        
        private Node find(Integer e){
            Node current=head;
            while(true){
                /*
                 * 如果当前元素的右边节点不是末尾节点,
                 * 且要添加的元素比当前节点右边的节点大,
                 * 那么就进行交换,将当前节点变为
                 * 当前节点的右边节点
                 * 此过程为一直在同层中往右走寻找大于等于自己的元素,直到找到为止
                 */
                while(current.right.type!=TAIL_NODE  && e>=current.right.item){
                    current=current.right;
                }
                
                /*
                 * 如果是在最底层说明不用再找了
                 * 已经找到位置了直接跳出循环
                 */
                if(current.down==null){
                    break;
                }
                //如果不是最底层又继续往下层找
                current=current.down;
            }
            /*
             * 如果要寻找的元素存在于本集合中,那么
             * 这里可以确定要寻找的元素>=current
             * 且<=current.right
             */
            return current;
        }
        
        private  static class Node{
            
            private Integer item;
            
            private Node up,down,left,right;
            
            private byte type;
            
            public Node(Integer e){
                this(e,ELEMENT_NODE);
            }
            
            public Node(Integer e,byte type){
                this.item=e;
                this.type=type;
            }
            
        }
        
        
    
    	public static void main(String[] args) {
    		
    	    SkipList mySkipList=new SkipList();
            mySkipList.add(10);
            mySkipList.flushSkipList();
    //      mySkipList.add(5);
    //      mySkipList.flushSkipList();
            //添加100个小于1000的随机数
            Random random=new Random();
            for(int i=0;i<100;i++){
                mySkipList.add(random.nextInt(1000));
            }
            mySkipList.flushSkipList();
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208

    3、中序遍历递归写法

    /**
     * 
     * 
     * https://leetcode-cn.com/problems/binary-tree-inorder-traversal/
     * 中序遍历递归写法
     */
    public class LeeCodeTest01 {
    	
    	private List<Integer> treeNodeList = new ArrayList<>();
    	
    	/**
    	 * 递归写法
    	 * @param root
    	 * @return
    	 */
        public List<Integer> inorderTraversal1(TreeNode root) {
    
            
            if(root == null){
                return treeNodeList;
            }
            
            //递归左边
            inorderTraversal1(root.left);
            treeNodeList.add(root.val);
            //递归右边
            inorderTraversal1(root.right);
    
            return treeNodeList;
        }
        
        
        private static class TreeNode{
        	
        	private TreeNode left;
        	
        	private TreeNode right;
        	
        	private int val;
        	
        }
    
    	public static void main(String[] args) {
    		
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    4、中序遍历递归写法

    /**
     * 
     * https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
     * 前序遍历递归写法
     */
    public class LeeCodeTest02 {
    	
    	private List<Integer> treeNodeList = new ArrayList<>();
        
    	/**
    	 * 递归的方式
    	 * @param root
    	 * @return
    	 */
        public List<Integer> preorderTraversal1(TreeNode root) {
    
            
            if(root == null){
                return treeNodeList;
            }
            
            treeNodeList.add(root.val);
            //递归左边
            preorderTraversal1(root.left);
            //递归右边
            preorderTraversal1(root.right);
    
            return treeNodeList;
        }
        
        
        
        private static class TreeNode{
        	
        	private TreeNode left;
        	
        	private TreeNode right;
        	
        	private int val;
        	
        }
    
    	public static void main(String[] args) {
    
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    5、树的各种遍历方式:

    /**
     * 树的各种遍历方式:
     * 前序遍历:根 --> 左子树 --> 右子树
     * 中序遍历:左子树 --> 根 --> 右子树
     * 后序遍历:左子树 --> 右子树 --> 根
     * https://www.cnblogs.com/zhi-leaf/p/10813048.html
     */
    public class TreeErgodicTest {
    
    	public static void main(String[] args) {
    		//准备数据
    	    BinarySearchTree binarySearchTree = new BinarySearchTree();
            binarySearchTree.add(39);
            binarySearchTree.add(20);
            binarySearchTree.add(69);
            
            binarySearchTree.add(11);
            binarySearchTree.add(27);
            binarySearchTree.add(23);
            
            binarySearchTree.add(50);
            binarySearchTree.add(87);
    //        binarySearchTree.remove(69);
            
            
    //      System.out.println(binarySearchTree.contains(23));
            
            BinarySearchTreeNode<Integer> root = binarySearchTree.getRoot();
            System.out.println("根节点是:"+root);
            
    //        prePrint1(root);
    //        prePrint2(root);
            
    //        middlePrint1(root);
    //        middlePrint2(root);
            
            postPrint1(root);
            postPrint2(root);
            
            
            levelPrint(root);
            
    
    	}
    	
    	
    	/**
    	 * O(2^n)
    	 * O(n)
         * 前序遍历打印二叉搜索树(递归的方式)
         * 根 --> 左子树 --> 右子树
         * @param root 二叉树的根节点
         */
        private static <E> void prePrint1(BinarySearchTreeNode<E> root){
            
            if(root == null){
                return;
            }
            
            System.out.print(root.item+"-->");
            //递归左边
            prePrint1(root.left);
            //递归右边
            prePrint1(root.right);
            
        }
        
        
        /**
         * 非递归的方式(使用栈的方式)
         * 1、弹栈并进行打印
         * 2、如果有右子节点,就将右子节点进行压栈
         * 3、如果有左子节点,就将左子节点进行压栈
         * 即:先根再右再左
         * 压完栈后执行弹栈操作,弹出时就进行打印
         * 然后重复2和3步骤
         * 
         * 时间复杂度为:O(n)
         * 空间复杂度为:O(?)
         * 前序遍历打印二叉搜索树
         * 根 --> 左子树 --> 右子树
         * @param root 二叉树的根节点
         */
        private static <E> void prePrint2(BinarySearchTreeNode<E> root){
            
            System.out.println();
            if(root == null){
                return;
            }
            //准备一个栈
            Stack<BinarySearchTreeNode<E>> stack = new Stack<>();
            //首先将根节点进行压栈
            stack.push(root);
            //如果栈不为空就一直执行
            while(!stack.isEmpty()){
                //进行弹栈,并替换掉根节点的值,弹出时就进行打印
                root = stack.pop();
                System.out.print(root.item+"-->");//invoke method
                //如果有右子节点,就将右子节点进行压栈
                if(root.right != null){
                    stack.push(root.right);
                }
                //如果有左子节点,就将左子节点进行压栈
                if(root.left != null){
                    stack.push(root.left);
                }
            }
            
        }
        
        
        /**
         * 中序遍历打印二叉搜索树(中序遍历是有序的)
         * 左子树 --> 根 --> 右子树
         * @param root 二叉树的根节点
         */
        private static <E> void middlePrint1(BinarySearchTreeNode<E> root){
            
            if(root == null){
                return;
            }
            
            //递归左边
            middlePrint1(root.left);
            System.out.print(root.item+"-->");
            //递归右边
            middlePrint1(root.right);
            
        }
        
        
        /**
         * 中序遍历打印二叉搜索树(中序遍历是有序的)
         * 左子树 --> 根 --> 右子树
         * 
         * 1、将树的左边界的元素全部依次压入栈中
         * 2、弹栈并进行打印,然后去弹栈元素的右子树
         * 将其右子树的左边界全部依次压入栈中,重复此过程
         * 时间复杂度:O(n)
         * 空间复杂度:O(n)
         * @param root 二叉树的根节点
         */
        private static <E> void middlePrint2(BinarySearchTreeNode<E> root){
            
            System.out.println();
            if(root == null){
                return;
            }
            //准备一个栈
            Stack<BinarySearchTreeNode<E>> stack = new Stack<>();
            
            while(!stack.isEmpty() || root != null){
                //如果根节点不为空
                if(root != null){
                    //将根节点压入栈中
                    stack.push(root);
                    //根节点变为根节点的左子节点
                    root = root.left;
                    continue;
                }
              //如果根节点为空
              //根节点变为弹栈的元素
              root = stack.pop();
              //打印当前根节点
              System.out.print(root.item+"-->");
              //根节点变为根节点的右子节点
              root = root.right;
            }
        }
        
        
        /**
         * 后序遍历打印二叉搜索树
         * 左子树 --> 右子树 --> 根
         * @param root 二叉树的根节点
         */
        private static <E> void postPrint1(BinarySearchTreeNode<E> root){
            
            if(root == null){
                return;
            }
            
            //递归左边
            postPrint1(root.left);
            //递归右边
            postPrint1(root.right);
            System.out.print(root.item+"-->");
            
        }
        
        
        /**
         * 后序遍历打印二叉搜索树
         * 左子树 --> 右子树 --> 根
         * 
         *  非递归的方式(使用两个栈的方式)
         * 1、弹栈,然后将弹出元素压入另一个栈
         * 2、如果有左子节点,就将左子节点进行压栈
         * 3、如果有右子节点,就将右子节点进行压栈
         * 即:先根再左再右
         * 压完栈后执行弹栈操作,弹出后
         * 将弹出元素压入另一个栈
         * 然后重复2和3步骤
         * @param root 二叉树的根节点
         */
        private static <E> void postPrint2(BinarySearchTreeNode<E> root){
            
            System.out.println();
            
            if(root == null){
                return;
            }
            //准备两个栈
            Stack<BinarySearchTreeNode<E>> stack1 = new Stack<>();
            Stack<BinarySearchTreeNode<E>> stack2 = new Stack<>();
            //首先将根节点进行压栈
            stack1.push(root);
            //如果栈不为空就一直执行
            while(!stack1.isEmpty()){
                //进行弹栈,并替换掉根节点的值,弹出时不打印
                root = stack1.pop();
                //将弹栈的元素压入另一个栈
                stack2.push(root);
                //如果有左子节点,就将左子节点进行压栈
                if(root.left != null){
                    stack1.push(root.left);
                }
                //如果有右子节点,就将右子节点进行压栈
                if(root.right != null){
                    stack1.push(root.right);
                }
            }
            //等第一个栈的元素都弹栈完了,将第二个栈元素进行弹栈并打印
            while(!stack2.isEmpty()){
                System.out.print(stack2.pop().item+"-->");
            }
            
        }
        
        
        /**
         * 层次遍历打印二叉搜索树
         * 根节点那一层为第一层,第二层,第三层
         * 
         *  需要使用队列
         * 1、首先把根节点放入队列
         * 2、获取到队首元素并打印
         * 3、将其左子节点入队,将其右子节点入队
         * 4、重复2和3过程
         * @param root 二叉树的根节点
         */
        private static <E> void levelPrint(BinarySearchTreeNode<E> root){
            
            System.out.println();
            
            if(root == null){
                return;
            }
            //准备一个队列
            Queue<BinarySearchTreeNode<E>> queue = new LinkedList<>();
            //首先把根节点放入队列
            queue.offer(root);
            //如果队列不为空就一直执行
            while(!queue.isEmpty()){
                //获取到队首元素
                BinarySearchTreeNode<E> current = queue.poll();
                //出队后就打印
                System.out.print(current.item+"-->");
                //将其左子节点入队
                if(current.left != null){
                    queue.offer(current.left);
                }
                //将其右子节点入队
                if(current.right != null){
                    queue.offer(current.right);
                }
                //重复此过程直到没有子节点为止
            }
            
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
  • 相关阅读:
    js截取图片地址后面的参数和在路径中截取文件名或后缀名
    avue常用场景记录
    【雷达通信】基于matlab频控阵波束方向图特性仿真【含Matlab源码 2193期】
    用Python中的马尔科夫链模拟文本
    leetCode 1143.最长公共子序列 动态规划
    Hadoop3:HDFS-查看logs文件,排查NameNode故障原因。
    nginx 配置静态网页
    jvm概述
    算法通关村第十七关:白银挑战-贪心高频问题
    高端品牌如何利用软文抓住顾客的心?
  • 原文地址:https://blog.csdn.net/weixin_43333483/article/details/125629852