【数据结构】:二叉树

二叉树

二叉树是一种特殊的树,每一个节点最多只能有两个子节点。html

二叉搜索树要求:

若它的左子树不空,则左子树上全部结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上全部结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树
image.pngspa

查找节点

查找节点从根节点开始遍历查找code

1 、查找值比当前节点值大,则搜索右子树;htm

二、 查找值等于当前节点值,中止搜索(终止条件);blog

三、查找值小于当前节点值,则搜索左子树;
image.png排序

插入节点

要插入节点,必须先找到插入的位置。与查找操做类似,因为二叉搜索树的特殊性,待插入的节点也须要从根节点开始进行比较,小于根节点则与根节点左子树比较,反之则与右子树比较,直到左子树为空或右子树为空,则插入到相应为空的位置,在比较的过程当中要注意保存父节点的信息 及 待插入的位置是父节点的左子树仍是右子树,才能插入到正确的位置递归

public boolean insert(int data) {
        count++;
        //若是第一个节点为空 设置第一个节点
        Node newNode = new Node(data);
        if (root == null) {
            root = newNode;
            return true;
        }
        Node current = root;
        Node parentNode = null;
 
        while (current != null) {
            parentNode = current;
            //当前值比新插入值大
            if (current.data > data) {
                current = current.leftNode;
                //若左节点为空 则直接插入便可
                if (current == null) {
                    parentNode.leftNode = newNode;
                    return true;
                }
            } else {
                //当前值小于新插入值
                current = current.rightNode;
                if (current == null) {
                    parentNode.rightNode = newNode;
                    return true;
                }
            }
        }
        return false;
    }

删除节点

删除节点相对于查询和删除稍微复杂点,主要是删除时考虑的状况多一点点。get

  • 删除节点没有子节点
    这种的话就直接删除当前节点就行了,只需将当前节点的父节点指向的节点置为null便可
//当前节点是否为左节点
        boolean isLeftNode = false;

// 1 第一种状况 此节点为叶子节点
        if (current.leftNode == null && current.rightNode == null) {
            if (current == root) {
                root = null;
            } else if (isLeftNode) {
                //若是要删除的节点为父节点的左节点 把父节点的左节点置为空
                parentNode.leftNode = null;
            } else {
                parentNode.rightNode = null;
            }
            return true;
        }
  • 删除节点有一个子节点
    删除有一个子节点的节点,咱们只须要将其父节点本来指向该节点的引用,改成指向该节点的子节点便可。
if (current.leftNode == null && current.rightNode != null) {
            if (root == current) {
                root = current.rightNode;
            } else if (isLeftNode) {
                parentNode.leftNode = current.rightNode;
            } else {
                parentNode.rightNode = current.rightNode;
            }
        } else if (current.leftNode != null && current.rightNode == null) {
            if (root == current) {
                root = current.leftNode;
            } else if (isLeftNode) {
                parentNode.leftNode = current.leftNode;
            } else {
                parentNode.rightNode = current.leftNode;
            }
        }
  • 删除节点有两个子节点
    当删除的节点存在两个子节点,那么删除以后,两个子节点的位置咱们就没办法处理了。既然处理不了,咱们就想到一种办法,用另外一个节点来代替被删除的节点,那么用哪个节点来代替呢?
    这实际上就是要找比删除节点关键值大的节点集合中最小的一个节点,只有这样代替删除节点后才能知足二叉搜索树的特性。
    程序找到删除节点的右节点,(注意这里前提是删除节点存在左右两个子节点,若是不存在则是删除状况的前面两种),而后转到该右节点的左子节点,依次顺着左子节点找下去,最后一个左子节点便是后继节点;若是该右节点没有左子节点,那么该右节点即是后继节点。
    二叉树it

    if(current.leftNode != null && current.rightNode != null){
              //获取删除节点的后继结点
              Node successor = getSuccessor(current);
              if (root == current) {
                  root = successor;
              } else if (isLeftNode) {
                  parentNode.leftNode = successor;
              } else {
                  parentNode.rightNode = successor;
              }
          }
          return false;
    public Node getSuccessor(Node delNode) {
     
          Node successorParent = delNode;
          Node successor = delNode;
          Node current = delNode.rightNode;
          while (current != null) {
              successorParent = successor;
              successor = current;
              current = current.leftNode;
          }
          if (successor != delNode.rightNode) {
              successorParent.leftNode = successor.rightNode;
              successor.leftNode= delNode.leftNode;
          }
          return successor;
      }

前序遍历

前序遍历:首先访问根结点,而后遍历左子树,最后遍历右子树(根->左->右)io

顺序:访问根节点->前序遍历左子树->前序遍历右子树

中序遍历

中序遍历:首先遍历左子树,而后访问根节点,最后遍历右子树(左->根->右)

顺序:中序遍历左子树->访问根节点->中序遍历右子树

后序遍历

后序遍历:首先遍历左子树,而后遍历右子树,最后访问根节点(左->右->根)

顺序:后序遍历左子树->后序遍历右子树->访问根节点

层序遍历;按层从左到右访问

前序中序后序
image.png
前序遍历:根->左->右:12473568
中序遍历:左->根->右:47215386
后序遍历:左->右->根:74258631

重构二叉树

image.png

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
   //前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
    public TreeNode reConstructBinaryTree(int[] pre, int[] in) {

        int len = pre.length;

        TreeNode root = new TreeNode(pre[0]);
        //说明只剩下一个了,表示叶子节点,递归能够退出了
        if (pre.length == 1) {
            root.left = null;
            root.right = null;
            return root;
        }

        //中间值 在{4,7,2,1,5,3,8,6} 这个中间值第一次应该是3
        int flag = 0;
        for (int i = 0; i < len; i++) {
            //在中序中找到
            if (pre[0] == in[i]) {
                flag = i;
                break;
            }
        }
        if (flag > 0) {
            //左子树的先序
            int[] leftPre = new int[flag];
            //左子树的中序
            int[] leftIn = new int[flag];
            for (int j = 0; j < flag; j++) {
                leftPre[j] = pre[j + 1];
            }
            for (int j = 0; j < flag; j++) {
                leftIn[j] = in[j];
            }
            //左子树递归
            root.left = reConstructBinaryTree(leftPre, leftIn);
        } else {
            root.left = null;
        }
        if (pre.length - flag - 1 > 0) {
            //右子树的先序,长度为 总-根-左子树
            int[] rightPre = new int[pre.length - 1 - flag];
            //右子树的中序
            int[] rightIn = new int[pre.length - 1 - flag];

            for (int j = flag + 1; j < len; j++) {
                //右子树中序,为何要j-flag-1呢 由于个人rightIn要从0开始 而j是k+1开始的 ,因此很尴尬,只能用j-flag-1
                rightIn[j - flag - 1] = in[j];

                rightPre[j - flag - 1] = pre[j];
            }

            root.right = reConstructBinaryTree(rightPre, rightIn);
        } else {
            root.right = null;
        }

        return root;

    }
 
}