数据结构中的树存储结构

245 阅读4分钟

树的结点

  • 结点:使用树结构存储的每一个数据元素都被称为“结点”。
  • 树根结点(简称“根结点”):每一个非空树都有且只有一个被称为根的结点。
  • 树根的判断依据为:如果一个结点没有父结点,那么这个结点就是整棵树的根结点。
  • 叶子结点:如果结点没有任何子结点,那么此结点称为叶子结点(叶结点)。

子树和空树

  • 子树:整棵树的根结点为结点 A,而如果单看结点 B、E、F、K、L 组成的部分来说,也是棵树,而且节点 B 为这棵树的根结点。所以称 B、E、F、K、L 这几个结点组成的树为整棵树的子树;同样,结点 E、K、L 构成的也是一棵子树,根结点为 E。
  • 注意:单个结点也是一棵树,只不过根结点就是它本身。
  • 知道了子树的概念后,树也可以这样定义:树是由根结点和若干棵子树构成的。
  • 空树:如果集合本身为空,那么构成的树就被称为空树。空树中没有结点。
  • 补充:在树结构中,对于具有同一个根结点的各个子树,相互之间不能有交集。

有序树和无序树

  • 如果树中结点的子树从左到右看,谁在左边,谁在右边,是有规定的,这棵树称为有序树;反之称为无序树。
  • 在有序树中,一个结点最左边的子树称为"第一个孩子",最右边的称为"最后一个孩子"。
  • 如果是其本身是一棵有序树,则以结点 B 为根结点的子树为整棵树的第一个孩子,以结点 D 为根结点的子树为整棵树的最后一个孩子。

树结构代码如下:

//树
//重点理解的是 递归 引用 指针
class Node{
    constructor(element){
        this.element = element;
        this.left = null;
        this.right = null;
    }
}
// new Node()
class Tree{
    constructor(){
        this.root = null;
    }
    insert(element){
        //添加第一个节点
        let newNode = new Node(element);//创建新节点
        //newNode = {element:5,left=null,right=null}
        // console.log(newNode)
        if(this.root === null){//树中没有任何元素
            this.root = newNode
        }else{
            //递归
            this.insertNode(this.root,newNode)//11 5
        }
    }
    insertNode(node,newNode){//node=7 newNode=3
        if(newNode.element<node.element){//如果新节点的值小于根节点
            if(node.left === null){//说明下面没有值了
                node.left = newNode
            }else{//说明下面还有值
                this.insertNode(node.left,newNode)
            }
        }else{
            if(node.right === null){//说明下面没有值了
                node.right = newNode
            }else{//说明下面还有值
                this.insertNode(node.right,newNode)
            }
        }
    }
    preOrderTraverse(){//对调函数为了拼接遍历出来的值
        this.preOrderTraverseNode(this.root);
    }
    preOrderTraverseNode(node){
        if(node!=null){
            // callback(node.element);
            console.log(node.element);
            this.preOrderTraverseNode(node.left);
            this.preOrderTraverseNode(node.right);
        }
    }
    midOrderTraverse(){//对调函数为了拼接遍历出来的值
        this.midOrderTraverseNode(this.root);
    }
    midOrderTraverseNode(node){//11 7 5 3 null
        if(node!=null){
            this.midOrderTraverseNode(node.left);
            console.log(node.element);//3 5 6 7 9
            this.midOrderTraverseNode(node.right);
        }
    }
    postOrderTraverse(){//对调函数为了拼接遍历出来的值
        this.postOrderTraverseNode(this.root);
    }
    postOrderTraverseNode(node){
        if(node!=null){
            this.postOrderTraverseNode(node.left);
            this.postOrderTraverseNode(node.right);
            console.log(node.element);
        }
    }
    max(){//求最大值
        let current = this.root;
        while(current!=null&& current.right){
            current = current.right//current = current.next
        }
        return current
    }
    //方法四要素
    //方法功能,参数,返回值,方法何时调用
    search(element){//查询特定值 二分查找发 折半查找法
        return this.searchNode(this.root,element)
    }
    searchNode(node,element){
        if(node==null){
            return false//未查找到要寻找的值
        }
        if(node.element>element){
            return this.searchNode(node.left,element)
        }else if(node.element<element){
            return this.searchNode(node.right,element)
        }else{
            return true//查找到要寻找的值
        }
    }
    remove(element){
        return this.root = this.removeNode(this.root,element)
    }
    removeNode(node,element){//9 8;8 8 
        if(node===null){
            return null
        }
        if(node.element>element){
            node.left = this.removeNode(node.left,element)//null 8
            return node
        }else if(node.element<element){
            node.right = this.removeNode(node.right,element)
            return node
        }else{
            // 相等情况 node.element = element
            // 第一种情况 删除叶节点
            if(node.left === null && node.right === null){
                node = null;
                return node
            }
            //第二种情况 删除的节点又一个子节点
            if(node.left == null){
                node = node.right
                return node
            }else if(node.right == null){
                node = node.left
                return node
            }
            //第三种情况
            //传入的element=7   
            const childNode = this.minNode(node.right);
            //childNode=8
            node.element = childNode.element;//替换
            node.right = this.removeNode(node.right,childNode.element);
            return node
        }
    }
    min(){//求最小值
        this.minNode(this.root)
    }
    minNode(node){
        let current = node;
        while(current!=null&& current.left){
            current = current.left//current = current.next
        }
        return current
    }
}
let tree = new Tree();
tree.insert(7);
tree.insert(6);
tree.insert(10);
tree.insert(4);

总结

树型存储结构类似于家族的族谱,各个结点之间也同样可能具有父子、兄弟、表兄弟的关系。本节中,要重点理解树的根结点和子树的定义,同时要会计算树中各个结点的度和层次,以及树的深度。