数据结构---------二叉树

一、数组和链表的介绍

  1. 数组:查找快,但插入和删除相对来说比较费时

    为什么?
    由于其结构是在连续的所以遍历时不像链表空间有间隔,所以相对会快,插入和删除时不仅要插入还要把之后的数据向后移动
  2. 链表:插入和删除相对较快,查找相对慢

    为什么?
    插入和删除只需要改变一个指引,相对数组查找慢是因为空间结构不是连接的。

二、二叉树

  1. 为什么存在?
    解决没有同时具备查找,删除和插入都快的数据结构。
  2. 优点:同时具备了数组查找快的有点和链表插入和删除快的优点。
  3. 什么是二叉树?
    每个节点最多只能有两个子节点的一种形式称为二叉树
    图解:
  4. 树的常用术语
    1. 路径:顺着节点的边从一个节点走到另一个节点,所经过的节点的顺序排列就称为“路径”
    2. :树顶端的节点称为根。一棵树只有一个根,如果要把一个节点和边的集合称为树,那么从根到其他任何一个节点都必须有且只有一条路径。A是根节点
    3. 父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;B是D的父节点
    4. 子节点:一个节点含有的子树的根节点称为该节点的子节点;D是B的子节点
    5. 兄弟节点:具有相同父节点的节点互称为兄弟节点;比如上图的D和E就互称为兄弟节点
    6. 页节点:没有子节点的节点称为叶节点,也叫叶子节点,比如上图的A、E、F、G都是叶子节点
    7. 子树:每个节点都可以作为子树的根,它和它所有的子节点、子节点的子节点等都包含在子树中
    8. 节点的层次:从根开始定义,根为第一层,根的子节点为第二层,以此类推
    9. 深度:对于任意节点n,n的深度为从根到n的唯一路径长,根的深度为0
    10. 高度:对于任意节点n,n的高度为从n到一片树叶的最长路径长,所有树叶的高度为0
  5. 二叉搜索树
    要求:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序

  6. 代码实现

①.定义一个Node.java

package com.lsl.tree;
 
public class Node {
    int data;   //节点数据
    Node leftChild; //左子节点的引用
    Node rightChild; //右子节点的引用
    boolean isDelete;//表示节点是否被删除
     
    public Node(int data){
        this.data = data;
    }
    //打印节点内容
    public void display(){
        System.out.println(data);
    }
 
}

②定义一个Tree.java

package com.lsl.tree;
 
public interface Tree {
    //查找节点
    public Node find(int key);
    //插入新节点
    public boolean insert(int data);
     
    //中序遍历
    public void infixOrder(Node current);
    //前序遍历
    public void preOrder(Node current);
    //后序遍历
    public void postOrder(Node current);
     
    //查找最大值
    public Node findMax();
    //查找最小值
    public Node findMin();
     
    //删除节点
    public boolean delete(int key);
     
    //Other Method......
}

③定义一个BinaryTree.java

package com.lsl.tree;
public class BinaryTree implements Tree {
    //表示根节点
    private Node root;
 
    //查找节点
    public Node find(int key) {
        Node current = root;
        while(current != null){
            if(current.data > key){//当前值比查找值大,搜索左子树
                current = current.leftChild;
            }else if(current.data < key){//当前值比查找值小,搜索右子树
                current = current.rightChild;
            }else{
                return current;
            }
        }
        return null;//遍历完整个树没找到,返回null
    }
 
    //插入节点
    public boolean insert(int data) {
        Node newNode = new Node(data);
        if(root == null){//当前树为空树,没有任何节点
            root = newNode;
            return true;
        }else{
            Node current = root;
            Node parentNode = null;
            while(current != null){
                parentNode = current;
                if(current.data > data){//当前值比插入值大,搜索左子节点
                    current = current.leftChild;
                    if(current == null){//左子节点为空,直接将新值插入到该节点
                        parentNode.leftChild = newNode;
                        return true;
                    }
                }else{
                    current = current.rightChild;
                    if(current == null){//右子节点为空,直接将新值插入到该节点
                        parentNode.rightChild = newNode;
                        return true;
                    }
                }
            }
        }
        return false;
    }
     
    //中序遍历
    public void infixOrder(Node current){
        if(current != null){
            infixOrder(current.leftChild);
            System.out.print(current.data+" ");
            infixOrder(current.rightChild);
        }
    }
     
    //前序遍历
    public void preOrder(Node current){
        if(current != null){
            System.out.print(current.data+" ");
            infixOrder(current.leftChild);
            infixOrder(current.rightChild);
        }
    }
     
    //后序遍历
    public void postOrder(Node current){
        if(current != null){
            infixOrder(current.leftChild);
            infixOrder(current.rightChild);
            System.out.print(current.data+" ");
        }
    }
    //找到最大值
    public Node findMax(){
        Node current = root;
        Node maxNode = current;
        while(current != null){
            maxNode = current;
            current = current.rightChild;
        }
        return maxNode;
    }
    //找到最小值
    public Node findMin(){
        Node current = root;
        Node minNode = current;
        while(current != null){
            minNode = current;
            current = current.leftChild;
        }
        return minNode;
    }
     
    @Override
    public boolean delete(int key) {
        Node current = root;
        Node parent = root;
        boolean isLeftChild = false;
        //查找删除值,找不到直接返回false
        while(current.data != key){
            parent = current;
            if(current.data > key){
                isLeftChild = true;
                current = current.leftChild;
            }else{
                isLeftChild = false;
                current = current.rightChild;
            }
            if(current == null){
                return false;
            }
        }
        //如果当前节点没有子节点
        if(current.leftChild == null && current.rightChild == null){
            if(current == root){
                root = null;
            }else if(isLeftChild){
                parent.leftChild = null;
            }else{
                parent.rightChild = null;
            }
            return true;
             
            //当前节点有一个子节点,右子节点
        }else if(current.leftChild == null && current.rightChild != null){
            if(current == root){
                root = current.rightChild;
            }else if(isLeftChild){
                parent.leftChild = current.rightChild;
            }else{
                parent.rightChild = current.rightChild;
            }
            return true;
            //当前节点有一个子节点,左子节点
        }else if(current.leftChild != null && current.rightChild == null){
            if(current == root){
                root = current.leftChild;
            }else if(isLeftChild){
                parent.leftChild = current.leftChild;
            }else{
                parent.rightChild = current.leftChild;
            }
            return true;
        }else{
            //当前节点存在两个子节点
            Node successor = getSuccessor(current);
            if(current == root){
                successor = root;
            }else if(isLeftChild){
                parent.leftChild = successor;
            }else{
                parent.rightChild = successor;
            }
            successor.leftChild = current.leftChild;
        }
        return false;
         
    }
 
    public Node getSuccessor(Node delNode){
        Node successorParent = delNode;
        Node successor = delNode;
        Node current = delNode.rightChild;
        while(current != null){
            successorParent = successor;
            successor = current;
            current = current.leftChild;
        }
        //后继节点不是删除节点的右子节点,将后继节点替换删除节点
        if(successor != delNode.rightChild){
            successorParent.leftChild = successor.rightChild;
            successor.rightChild = delNode.rightChild;
        }
         
        return successor;
    }
    public static void main(String[] args) {
        BinaryTree bt = new BinaryTree();
        bt.insert(45);
        bt.insert(30);
        bt.insert(70);
        bt.insert(50);
        bt.insert(40);
        bt.insert(60);
        bt.insert(80);
        bt.insert(25);
        bt.insert(90);
        bt.insert(105);
        bt.delete(30);
        bt.delete(40);
        bt.delete(80);//删除有两个子节点的节点
        System.out.println(bt.findMax().data);
        System.out.println(bt.findMin().data);
        System.out.println(bt.find(105));
         
    }
}

总:树是由边和节点构成,根节点是树最顶端的节点,它没有父节点;二叉树中,最多有两个子节点;某个节点的左子树每个节点都比该节点的关键字值小,右子树的每个节点都比该节点的关键字值大,那么这种树称为二叉搜索树,其查找、插入、删除的时间复杂度都为logN.
 

 

版权声明:本博客为记录本人自学感悟,内容大多从网上学习与整理所得,若侵权请告知!

https://mp.csdn.net/postedit/80365677

 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页