二叉树【数据结构与算法java】

二叉树【数据结构与算法java】

LeetCode

TreeNode

LeetCode的结点类

package leetcode;

import java.util.LinkedList;
import java.util.Queue;

/**
 * @author CSDN@日星月云
 * @date 2022/10/28 00:25
 */
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    public TreeNode() {
        //无参数构造函数
    }
    public TreeNode(int val) {
        this.val = val;
    }
    public TreeNode(int val,TreeNode left,TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }


    @Override
    public String toString() {
        return "TreeNode{" +
                "val=" + val +
                ", left=" + left +
                ", right=" + right +
                '}';
    }


}


BiTree

二叉树的实现

package leetcode;

import java.util.*;

/**
 * @author CSDN@日星月云
 * @date 2022/10/25 23:09
 */
public class BiTree {
    TreeNode root;
    BiTree(){
            root=null;
    }

    //用扩展先序遍历序列创建二叉链表
    //依靠队列,当队首元素分配了左右孩子就出队
    public TreeNode setTree(Integer[] data)//data为传入的形参数组,如Integer[] nums = {1,2,null,4,null,5}
    {
        root = new TreeNode(data[0]);
        Queue<TreeNode> queue = new LinkedList<>();//先入先出,构造子树
        queue.offer(root);
        int i = 1;//从第二个元素开始入列
        while(i<data.length)
        {
            TreeNode node = queue.poll();//弹出队列中的树节点
            if(data[i] != null)//当实参的元素不为null时,添加左节点
            {
                node.left = new TreeNode(data[i]);
                queue.offer(node.left);
            }
            i++;//不管实参(传入Integer[] data的Integer数组)的元素是不是null,均需要后移一位
            if(data[i] != null)//当实参的元素不为null时,添加右节点
            {
                node.right = new TreeNode(data[i]);
                queue.offer(node.right);
            }
            i++;
        }
        return root;//返回根节点
    }


    //访问
    void visit(int n){
        System.out.print(n+" ");
    }

    // 递归 先序
    void preOrder(TreeNode root){
        //先序遍历二叉树,root为根节点的指针
        if (root!=null){
            visit(root.val);
            preOrder(root.left);
            preOrder(root.right);
        }
    }



    public static void main(String[] args) {
        BiTree biTree=new BiTree();
        Integer[] nodes=new Integer[]{
          1,2,3,null,null,null,null
        };
        biTree.setTree(nodes);
        System.out.println(biTree.root.toString());
        biTree.preOrder(biTree.root);
    }

}

完整源代码

Node 节点类

package tree;

/**
 * @author CSDN@日星月云
 * @date 2022/10/25 23:18
 * iData来判断插入到左还是右
 */
class Node{
        public int iData;// data item (key)  主键 用来实现二叉排序树
        public double dData;// data item     信息
        public Node leftChild;// this node's left child
        public Node rightChild;// this node 's right child
        public void displayNode(){// display ourself
                System.out.print ('{');
                System.out.print (iData) ;
                System.out.print(",");
                System.out.print (dData);
                System.out.print("}");
        }
}


Tree 树类

package tree;

import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Stack;

/**
 * @author CSDN@日星月云
 * @date 2022/10/25 23:25
 * Tree 类
 * 还需要有一个表示树本身的类,由这个类实例化的对象含有所有的节点,这个类是Tree类。它. 只有一个数据字段:一个表示根的Node变量。它不需要包含其他节点的数据字段,因为其他节点 都可以从根开始访问到。
 * Tree类有很多方法。它们用来査询、插入和删除节点;进行各种不同的遍历;显示树。下面是 这个类的骨架:
 */
public class Tree {
    public Node root;//first node of tree

    // ---------------------------------------
    public Tree() { // constructor
        root = null;// no nodes in tree yet
    }

    /**
     * 从根开始。(它只能这样做,因为只有根节点可以直接访问。)因此,开始把current设为根。
     * 之后,在while循环中,将要查找的值,key与当前节点的iData字段的值(关键字字段)做比
     * 较。如果key小于这个数据域的值,current设为此节点的左子节点。如果key大于(或等于)节点
     * iData字段的值,current设为此节点的右子节点。
     * 找不到节点
     * 如果current等于null,在查找序列中找不到下一个子节点;到达序列的末端而没有找到要找的
     * 节点,表明了它不存在。返回null来指岀这个情况。
     * 找到节点
     * 如果while循环的条件不满足,从循环的末端退出来,current的iData字段和key相等:这就
     * 是说找到该节点了。返回这个节点,调用find。方法的程序可以访问节点的任何字段。
     * @param key
     * @return
     */
    //按主键找结点
    public Node find(int key) { //find node with given key (assumes non-empty tree)
        Node current = root;// start at root
        while (current.iData != key) {// while no match,
            if (key < current.iData)// go left
                current = current.leftChild;
            else// or go right?
                current = current.rightChild;
            if (current == null)// if no child
                return null; // didn't find it
        }
        return current;// found it
    }// end find( )

    // ---------------------------------------

    /**
     *
     * @param id
     * @param dd
     */
    //插入二叉排序树
    public void insert(int id, double dd) {
        Node newNode = new Node();
        //make new node
        newNode.iData = id;//insert data
        newNode.dData = dd;
        if (root == null)// no node in root
            root = newNode;
        else { // root occupied
            Node current = root; // start at root
            Node parent;
            //迭代 知道cur==null parent是上次循环也就是当前cur的父结点
            while (true) {//(exits internally)
                parent = current;
                if (id < current.iData) {// go left?
                    current = current.leftChild;
                    if (current == null) {// if end of the line,
                        // insert on left
                        parent.leftChild = newNode;
                        return;
                    }
                }// end if go left
                else {// or go right?
                    current = current.rightChild;
                    if (current == null) {// if end of the line
                        // insert on right
                        parent.rightChild = newNode;
                        return;
                    }
                } // end else go right
            } // end while
        }// end else not root
    }// end insert

    //删除结点
    //二叉排序树的删除
    public boolean delete(int key) {        //delete node with given key
        // (assumes non-empty list)
        Node current = root;
        Node parent = root;
        boolean isLeftChild = true;//待删结点是左孩子
        //情况1:删除没有子节点的节点
        //找不到该结点 返回false
        // delete()方法的第一部分和find()和insert()方法很像。它査找要删除的节点。和insert()一样,需
        // 要保存要删节点的父节点,这样就可以修改它的子字段的值了。如果找到节点了,就从while循环
        // 中跳出,parent保存要删除的节点。如果找不到要删除的节点,就从delete。方法返回false。
        while (current.iData != key) {// search for node
            parent = current;
            if (key < current.iData) { // go left?
                isLeftChild = true;
                current = current.leftChild;
            } else {
                // or go right?
                isLeftChild = false;
                current = current.rightChild;
            }
            if (current == null)// end of the line,
                return false; // didn't find it
        } // end while

        // 找到节点后,先要检查它是不是真的没有子节点。如果它没有子节点,还需要检査它是不是根。
        // 如果它是根的话,只需要把它置为null;这样就清空了整棵树。否则,就把父节点的leftChild或
        // rightChild字段置为null,断开父节点和那个要删除节点的连接。
        // 找到待删结点
        // found node to delete
        // if no children, simply delete it
        // 如果没有孩子,直接删掉
        if (current.leftChild == null && current.rightChild == null) {
            if (current == root)// if root,
                root = null;// tree is empty
            else if (isLeftChild)
                parent.leftChild = null;// disconnect
            else// from parent
                parent.rightChild = null;
        }
        //情况2:删除有一个子节点的节点
        // if no right child, replace with left subtree
        else if (current.rightChild == null) {
            if (current == root) root = current.leftChild;
            else if (isLeftChild)
                parent.leftChild = current.leftChild;
            else
                parent.rightChild = current.leftChild;
        }

        // if no left child, replace with right subtree
        else if (current.leftChild == null) {
            if (current == root)
                root = current.rightChild;
            else if (isLeftChild) parent.leftChild = current.rightChild;
            else
                parent.rightChild = current.rightChild;
        } else {// two children, so replace with inorder successor
            // get successor of node to delete (current)
            Node successor = getSuccessor(current);

            // connect parent of current to successor instead
            if (current == root)
                root = successor;
            else if (isLeftChild)
                parent.leftChild = successor;
            else
                parent.rightChild = successor;

            // connect successor to current's left child
            successor.leftChild = current.leftChild;
            // end else two children// (successor cannot have a left child)
        }
        return true; // success
    }// end delete()
    // returns node with next-highest value after delNode

    //找到二叉排序树中序遍历的后继结点
    // goes to right child, then right child's left descendents
    private Node getSuccessor(Node delNode) {
        Node successorParent = delNode;
        Node successor = delNode;
        Node current = delNode.rightChild;// go to right child
        while (current != null) {// until no more
            // left children,
            successorParent = successor;
            successor = current;// go to left child
            current = current.leftChild;
        }
        // if successor not
        if (successor != delNode.rightChild) {// right child,
            // make connections
            successorParent.leftChild = successor.rightChild;
            successor.rightChild = delNode.rightChild;
        }
        return successor;
    }

    //------------------------------------------------
    //遍历的程序接口
    public void traverse(int traverseType) {
        switch (traverseType) {
            case 1:
                System.out.print("Preorder traversal: ");
                preOrder(root);
                break;

            case 2:
                System.out.print("Inorder traversal: ");
                inOrder(root);
                break;
            case 3:
                System.out.print("Postorder traversal: ");
                postOrder(root);
                break;
        }
        System.out.println();
    }

    //------------------------------------------------
    //递归的前序遍历
    public void preOrder(Node localRoot) {
        if (localRoot != null) {
            System.out.print(localRoot.iData + " ");
            preOrder(localRoot.leftChild);
            preOrder(localRoot.rightChild);
        }
    }

    //------------------------------------------------
    //递归的中序遍历
    public void inOrder(Node localRoot) {
        if (localRoot != null) {
            inOrder(localRoot.leftChild);
            System.out.print(localRoot.iData + " ");
            inOrder(localRoot.rightChild);
        }
    }

    //------------------------------------------------
    //递归的后序遍历
    public void postOrder(Node localRoot) {
        if (localRoot != null){
            postOrder(localRoot.leftChild);
            postOrder(localRoot.rightChild);
            System.out.print(localRoot.iData + " ");
        }
    }
    //------------------------------------------------

    //层次遍历 null显示--
    public void displayTree() {
        Stack globalStack = new Stack();
        globalStack.push(root);
        int nBlanks = 32;
        boolean isRowEmpty = false;
        System.out.println("---------------------------------------------" +
                "--------------------------------");
        while (isRowEmpty == false) {
            Stack localStack = new Stack();
            isRowEmpty = true;
            for (int j = 0; j < nBlanks; j++)
                System.out.print(' ');
            while (globalStack.isEmpty() == false) {
                Node temp = (Node) globalStack.pop();
                if (temp != null) {
                    System.out.print(temp.iData);
                    localStack.push(temp.leftChild);
                    localStack.push(temp.rightChild);
                    if (temp.leftChild != null || temp.rightChild != null)
                        isRowEmpty = false;
                } else {
                    System.out.print("--");
                    localStack.push(null);
                    localStack.push(null);
                }
                for (int j = 0; j < nBlanks * 2 - 2; j++) {
                    System.out.print(' ');
                }// end while globalStack not empty

            }
            System.out.println();
            nBlanks /= 2;
            while (localStack.isEmpty() == false) {
                globalStack.push(localStack.pop());
            } // end while isRowEmpty is false
            System.out.println("--------------------------------" +
                    "--------------------------------------------");
        }
    }// end displayTree()



    //--------------------------另外补充--------------------------
    //非递归遍历的程序接口
    public void traverseN(int traverseType) {
        switch (traverseType) {
            case 1:
                System.out.print("PreorderN traversal: ");
                preOrderN(root);
                break;

            case 2:
                System.out.println("InorderN traversal: ");
                System.out.print("inOrderN1 traversal: ");
                inOrderN1(root);
                System.out.print("inOrderN2 traversal: ");
                inOrderN2(root);
                break;
            case 3:
                System.out.print("PostorderN traversal: ");
                postOrderN(root);
                break;
        }
        System.out.println();
    }

    //先序非递归
    public void preOrderN(Node localRoot){
        Stack<Node> stack=new Stack<>();
        Node cur=localRoot;
        while (cur!=null||!stack.isEmpty()){//当前结点指针及栈均空,则结束
            while (cur!=null){//访问根结点,根指针进栈,进入左子树
                System.out.print(cur.iData+" ");
                stack.push(cur);
                cur=cur.leftChild;
            }
            if (!stack.isEmpty()){
                cur = stack.pop();
                cur=cur.rightChild;//根指针退栈,进入其右子树
            }
        }
        System.out.println();
    }


    //中序非递归1
    public void inOrderN1(Node localRoot){
        Stack<Node> stack=new Stack<>();
        Node cur=localRoot;
        while (cur!=null||!stack.isEmpty()){//当前结点指针及栈均空,则结束
            while (cur!=null){//访问根结点,根指针进栈,进入左子树
                stack.push(cur);
                cur=cur.leftChild;
            }
            if (!stack.isEmpty()){
                cur = stack.pop();
                System.out.print(cur.iData+" ");
                cur=cur.rightChild;//根指针退栈,进入其右子树
            }
        }
        System.out.println();
    }

    //中序非递归2
    public void inOrderN2(Node localRoot){
        Stack<Node> stack=new Stack<>();
        Node cur=localRoot;
        while (cur!=null||!stack.isEmpty()){//当前结点指针及栈均空,则结束
            if (cur!=null){//访问根结点,根指针进栈,进入左子树
                stack.push(cur);
                cur=cur.leftChild;
            } else{
                cur = stack.pop();
                System.out.print(cur.iData+" ");
                cur=cur.rightChild;//根指针退栈,进入其右子树
            }
        }
        System.out.println();
    }


    //非递归 后序
    void postOrderN(Node localRoot){
        Stack<Node> stack=new Stack<>();
        Node cur=localRoot,next=null;
        while (cur!=null||!stack.isEmpty()){//当前结点指针及栈均空,则结束
            while (cur!=null){//访问根结点,根指针进栈,进入左子树
                stack.push(cur);
                cur=cur.leftChild;
            }
            if (!stack.isEmpty()){
                cur=stack.peek();//先要进行判断符合以下条件,再进行弹出
                //判断栈顶结点的右子树是否为空,右子树是否刚访问过
                if (cur.rightChild==null||cur.rightChild==next) {
                    cur= stack.pop();
                    System.out.print(cur.iData+" ");
                    next=cur;
                    cur=null;
                }else {
                    cur=cur.rightChild;
                }
            }
        }

    }


    //层序遍历
    //借助队列
    void levelOrder(Node localRoot){
        Queue<Node> queue= new ArrayDeque<>();
        Node cur;
        queue.add(localRoot);
        while (!queue.isEmpty()){
            cur=queue.remove();
            System.out.print(cur.iData+" ");
            if (cur.leftChild!=null){
                queue.add(cur.leftChild);
            }
            if (cur.rightChild!=null){
                queue.add(cur.rightChild);
            }
        }

        System.out.println();

    }

    // 先序遍历统计二叉树的结点数
    int count=0;
    void countWithPreOrder(Node localRoot){
        //Count为统计结点数目的全局变量,调用前初始值为0
        if (localRoot!=null){
            count++;//统计结点数
            countWithPreOrder(localRoot.leftChild);//先序遍历左子树
            countWithPreOrder(localRoot.rightChild);//先序遍历右子树
        }
    }

    //  中序遍历输出二叉树的叶子结点
    void printTNWithInOrder(Node root){
        if(root!=null){
            printTNWithInOrder(root.leftChild);
            if(root.leftChild==null&&root.rightChild==null){
                System.out.print(root.iData+" ");
            }
            printTNWithInOrder(root.rightChild);
        }
//        System.out.println();
    }


    //  后序遍历输出二叉树的叶子结点数目
    int leaf(Node root){
        int nl,nr;
        if(root==null){
            return 0;
        }
        if((root.leftChild==null)&&(root.rightChild==null)){
            return 1;
        }
        nl=leaf(root.leftChild);//递归求左子树的叶子数
        nr=leaf(root.rightChild);//递归求右子树的叶子数
        return(nl+nr);
    }


    //全局变量法求二叉树的高度
    int depth=0;
    void treeDepth(Node root, int h){
        //h为root结点所在的层次,首次调用前初始值为1
        //depth为记录当前求得的最大层次的全局变量,调用前初始值为0

        if(root!=null){
            if(h>depth) {
                depth=h;//当前结点层大于depth,则更新
            }
            treeDepth(root.leftChild,h+1);//遍历左子树,子树根层次为h+1

            treeDepth(root.rightChild,h+1);//遍历右子树,子树根层次为h+1

        }
    }

    //求二叉树的高度
    int postTreeDepth(Node root){
        int hl,hr,h;
        if(root== null) return 0;
        else{
            hl = postTreeDepth(root.leftChild);//递归求左子树的高度
            hr= postTreeDepth(root.rightChild);//递归求右子树的高度
            h=(hl>hr? hl:hr)+1;				//计算树的高度
            return h;
        }
    }

    //求二叉树中某一结点的双亲
    Node parent( Node root, Node current){
        //在以root为根的二叉树中找结点current的双亲
        Node p;
        if(root == null) return null;
        if(root.leftChild== current||root.leftChild ==current)
            return root;		//root即为current的双亲

        p=parent(root.leftChild,current);//递归在左子树中找

        if (p!=null) return p;
        else return(parent (root.leftChild,current));//递归在右子树中找

    }

    //二叉树相似性判定
    int like(Node t1, Node t2){
        int like1, like2;
        if(t1==null && t2==null) return 1;//t1,t2均空,则相似
        if(t1==null||t2==null)return 0;//t1、t2仅一棵空,则不相似
        like1=like(t1.leftChild,t2.leftChild);//递归判左子树是否相似
        like2=like(t1.leftChild,t2.leftChild);//递归判右子树是否相似
        return (like1 * like2);
    }

    //按树状打印二叉树
    void printTree(Node root, int h){
        if(root == null) return;
        printTree(root.rightChild, h+8);  //先打印右子树
        int i;
        for(i=0;i<h;i++)
            System.out.print(" ");//层次决定结点的左右位置
        System.out.println(root.iData);//输出结点
        printTree(root.leftChild,h+8);  //后打印左子树
    }





}// end class Tree










TreeApp 测试类

package tree;
// tree.java
// demonstrates binary tree
// to run this program: C>java TreeApp
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author CSDN@日星月云
 * @date 2022/10/25 23:51
 */
public class TreeApp {
    public static void main(String[] args) throws IOException {
        int value;
        Tree theTree = new Tree();
        theTree.insert(50, 1.5);
        theTree.insert(25, 1.2);
        theTree.insert(75, 1.7);
        theTree.insert(12, 1.5);
        theTree.insert(37, 1.2);
        theTree.insert(43, 1.7);
        theTree.insert(30, 1.5);
        theTree.insert(33, 1.2);
        theTree.insert(87, 1.7);
        theTree.insert(93, 1.5);
        theTree.insert(97, 1.5);

        while (true) {
            System.out.print("Enter 0 1 2: ");
            int choice = getInt();
            switch (choice){
                case 1:
                    app1(theTree);
                    break;
                case 2:
                    app2(theTree);
                    break;
                case 0:
                    return;
            }
        }



    }// end main()

    private static void app2(Tree theTree) throws IOException  {
        int value;
        while (true) {
            System.out.print("Enter first letter of ");
            System.out.println("traverseN,levelOrder,countWithPreOrder,printTNWithInOrder(f), break: ");
            System.out.println("leaf(n),treeDepth(d),postTreeDepth(h),parent,like(e),printTree(r) break: ");
            int choice = getChar();
            switch (choice) {
                case 't':
                    System.out.print("Enter type 1, 2 or 3: ");
                    value = getInt();
                    theTree.traverseN(value);
                    break;
                case 'l':
                    theTree.levelOrder(theTree.root);
                    break;
                case 'c':
                    theTree.countWithPreOrder(theTree.root);
                    System.out.println(theTree.count);
                    break;
                case 'f':
                    theTree.printTNWithInOrder(theTree.root);
                    System.out.println();
                    break;
                case 'n':
                    int leafNum = theTree.leaf(theTree.root);
                    System.out.println(leafNum);
                    break;
                case 'd':
                    int depth=1;//初始root的层次
                    theTree.treeDepth(theTree.root,depth);
                    System.out.println(theTree.depth);
                    break;
                case 'h':
                    int height = theTree.postTreeDepth(theTree.root);
                    System.out.println(height);
                    break;
                case 'p':
                    Node parent = theTree.parent(theTree.root, theTree.find(12));
                    System.out.println(parent.iData);
                    break;
                case 'e':
                    int like = theTree.like(theTree.root, theTree.root);
                    System.out.println(like);
                    break;
                case 'r':
                    theTree.printTree(theTree.root,8);
                    break;
                case 'b':
                    return;
                default:
                    System.out.print("Invalid entry\n");
            }
        }




    }

    private static void app1(Tree theTree) throws IOException {
        int value;
        while (true) {
            System.out.print("Enter first letter of ");
            System.out.print("show,insert, find, delete, or traverse, break: ");
            int choice = getChar();
            switch (choice) {
                case 's':
                    theTree.displayTree();
                    break;
                case 'i':
                    System.out.print("Enter value to insert:");
                    value = getInt();
                    theTree.insert(value, value + 0.9);
                    break;

                case 'f':
                    System.out.print("Enter value to find:");
                    value = getInt();
                    Node found = theTree.find(value);
                    if (found != null) {
                        System.out.print("Found: ");
                        found.displayNode();
                        System.out.print("\n");
                    } else
                        System.out.print("Could not find ");
                    System.out.print(value + '\n');
                    break;
                case 'd':
                    System.out.print("Enter value to delete: ");
                    value = getInt();
                    boolean didDelete = theTree.delete(value);
                    if (didDelete) {
                        System.out.print("Deleted " + value + '\n');
                    } else
                        System.out.print("Could not delete ");
                    System.out.print(value + '\n');
                    break;
                case 't':
                    System.out.print("Enter type 1, 2 or 3: ");
                    value = getInt();
                    theTree.traverse(value);
                    break;
                case 'b':
                    return;
                default:
                    System.out.print("Invalid entry\n");
            }// end switch

        }// end while
    }


    public static String getString() throws IOException {
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
        String s = br.readLine();
        return s;


    }

    public static char getChar() throws IOException {
        String s = getString();
        return s.charAt(0);
    }

    public static int getInt() throws IOException {
        String s = getString();
        return Integer.parseInt(s);
    }

}// end class TreeApp


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日星月云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值