二叉树和堆排序

发布于 2020-07-12  370 次阅读


二叉树是树结构的一种,一种一对多的逻辑关系,

基本概念:父节点有且最多只有两个子节点

树的名词解释:

根节点:二叉树的顶层节点有且只有一个,如图中的1节点

父节点:相比较的概念的,如:2是5和4的父节点,1是2的父节点

子节点:和父节点一样也相对的 如:对于8和9而言它是4的子节点,而对于4它是2的子节点……

层:它来判断树的高度,如图中有4层

权:指每个节点的存储的值(数据),图中每个节点存储了数字这就是权

路径:指从当前节点到其他节点的路线,如:从2到5的路线就是路线,每个节点都有一个左右指向

叶子节点:没有子节点的节点,如:8,9,10,11,6,7都是叶子节点

子树:类比于一颗大树的树枝,如:2,4,5就叫一颗子树

树的高度:最大层数

------满二叉树和完全二叉树-------

满二叉树:所有的叶子节点都在最后一层,节点的总数=2^n-1(n为层数)

图中就是一个满二叉树,所有节点都在最后一层,它的节点总数=2^3-1为7个节点

完全二叉树:所有的叶子节点都在最后一层或者倒数第二层,最后一层向左连续,倒数第二层向右连续

假如5,6,7其中一个没有就不存在连续也就不完全二叉树

--------二叉树的实现-----------

在数据结构的分类中物理存储分两类:顺序存储和链式存储

在数据结构中每一个逻辑结构都依赖于物理存储结构,通过物理结构来实现逻辑结构

二叉数有两种实现方式,一种是链式存储二叉树,一个顺序存储二叉树(堆的实现依赖于顺序二叉树)

------------链式二叉树-------------

构建图中的二叉树:

public class chaintree {
    public static void main(String[] args) {
        //建立节点:定义6个节点
        predata a=new predata(1);
        predata b=new predata(2);
        predata c=new predata(3);
        predata d=new predata(4);
        predata e=new predata(5);
        predata f=new predata(6);
        //给他们建立关系
        //a点的左节点是b,a的右节点是c
        a.setLife(b);
        a.setRight(c);
        //b的左节点是d,右节点是e
        b.setLife(d);
        b.setRight(e);
        //c的右节点是f,没有左节点
        c.setRight(f);
        //将节点关系放进树里面
        tree wql=new tree(a);
        wql.front();//1,2,4,5,3,6
    }
}
//定义树把节点类的节点联系放进树
class tree{
    private predata treewql;
    public tree(predata treewql){
        this.treewql=treewql;
    }
    //从树类中调用遍历方法
    //前序遍历
    public void front(){
        if(treewql==null){
            System.out.println("树为空");
        }else{
            treewql.front();
        }
    }
    //中序遍历
    public void centre(){
        if(treewql==null){
            System.out.println("树为空");
        }else{
            treewql.centre();
        }
    }
    //后序遍历
    public void later(){
        if(treewql==null){
            System.out.println("树为空");
        }else{
            treewql.later();
        }
    }
}



//节点类
class predata{
    private predata life;//定义左子节点
    private predata right;//定义右子节点
    private int val;//给我树一个权值
    //初始化值
    public predata(int val){
        this.val=val;
    }
    //给当前节点设置它的左节点
    public void setLife(predata life) {
        this.life = life;
    }
    //给当前节点设置它左节点
    public void setRight(predata right) {
        this.right = right;
    }
    //toString方法
    @Override
    public String toString() {
        return "predata{" +
                "val=" + val +
                '}';
    }
    //前序遍历:先输出父节点,再输出左子节点,最后是右子节点
    public void front(){
        System.out.println(this);//前序遍历首先输当前节点也就是父节点

        if(this.life!=null){//输出左子节点,先判断左子节点是否为空,再递归输出左子节点
            this.life.front();
        }
        if(this.right!=null){//输出右子节点,先判断右子节点是否为空,再递归输出右子节点
            this.right.front();
        }
    }
    //中序遍历:先输出左子节点,再输出父节,最后是右子节点
    public void centre(){
        //中序遍历首先输当前节点也就是父节点
        if(this.life!=null){//输出左子节点,先判断左子节点是否为空,再递归输出左子节点
            this.life.centre();
        }
        //中间输出父节点
        System.out.println(this);
        if(this.right!=null){//输出右子节点,先判断右子节点是否为空,再递归输出右子节点
            this.right.centre();
        }
    }
    //后序遍历:先输出左子节点,再输出右子节点,最后是父节点
    public void later(){
        //中序遍历首先输当前节点也就是父节点
        if(this.life!=null){//输出左子节点,先判断左子节点是否为空,再递归输出左子节点
            this.life.later();
        }
        //中间输出右子节点
        if(this.right!=null){//输出右子节点,先判断右子节点是否为空,再递归输出右子节点
            this.right.later();
        }
        //最后输出父节点
        System.out.println(this);
    }
}

前序遍历,中序遍历,后序遍历的区别在于父节点输出的位置,前序就是父节最先输出,以此类推

前序:父节点 -> 左子节点 -> 右子节点

中序:左子节点 ->父节点 -> 右子节点

后序:左子节点 ->右子节点 -> 父节点

----------顺序存储二叉树---------

顺序存储二叉树与链式存储二叉树不同,它的节点是数组的一个个区间,数组中存储的值就是树的权

树的左节点=2*当前节点在数组中的索引+1

树的右节点=2*当前节点在数组中的索引+2

通过索引来计算左右树

如图中:

a的左节点=2*0+1(索引)

c的右节点=2*2+2(索引)

public class ordertree {
    public static void main(String[] args) {
        int[] WQL=new int[]{1,2,3,4,5,6};
        datawql a=new datawql(WQL);
        a.alter1(0);       //1,2,4,5,3,6
    }
}
class datawql{
    int[] datas;
    public datawql(int[] datas){
        this.datas=datas;
    }
    //前序遍历
    public void  front1(int index){//给出要遍历的起始节点的索引
        if(datas[index]!=0 && index<datas.length) {
            System.out.println(datas[index]);
        }
        if((index*2+1)<datas.length){
            front1(index*2+1);
        }
        if((index*2+2)<datas.length){
            front1(index*2+2);
        }
}

    //中序遍历
    public void  concre1(int index){//给出要遍历的起始节点的索引
        if((index*2+1)<datas.length){
            concre1(index*2+1);
        }
        if(datas[index]!=0 && index<datas.length) {
            System.out.println(datas[index]);
        }
        if((index*2+2)<datas.length){
            concre1(index*2+2);
        } }


    //中序遍历
    public void  alter1(int index){//给出要遍历的起始节点的索引
        if((index*2+1)<datas.length){//index大于数组长度就声明不存在
            alter1(index*2+1);
        }
        if(datas[index]!=0 && index<datas.length) {
            System.out.println(datas[index]);
        }
        if((index*2+2)<datas.length){
            alter1(index*2+2);
        } }
}

-----------堆排序-----------

堆排序是利用堆这个数据结构而设计的一种排序算法(是一种不稳定排序)

堆是一个完全二叉树它有两个特性:

大顶堆:父节点比子节点大(不比较叶子节点的大小)

小定堆:父节点比子节点小(不比较叶子节点的大小)

public class heapsort {
    public static void main(String[] args) {
int[] a=new int[]{2,3,1,6,4};
heap1 s=new heap1(a);

    }
}

//将堆进行排序
class hea1sort{
    heap1 c;
    public hea1sort(heap1 c){
        this.c=c;
    }
    public void sort(){
        for(int a=c.a.length/2-1;a>=0;a--){
            c.adjustheap(a);
        }
    }
}

//定义一个堆
class heap1{
    int[] a;
    public heap1(int[] a){
        this.a=a;
    }
    //将数组的二叉树转化成一个堆
    public void adjustheap(int i){//非叶子节点的索引
        int[] n=a;
        int temp=n[i];//保存当前节点的值
        for(int i1=i*2+1; i1>=0; i1=i*2+1){
            //接收当前节点得到左节点(i*2+1),判断左节点是否比右节点大,如果比右节点小就把左节点的索引改成右索引
            if(i1+1<n.length && n[i1+1] >n[i1]){
                i1++;
            }
            //判断当前非叶子节点的根节点是是否比子节点大,如果小就把子节点的值赋给当前节点也就是a[i]
            if(i1+1<n.length && n[i] < n[i1]){
                n[i]=n[i1];
                i=i1;//把i(当前的父节点索引)换成子节点索引
            }else {
                break;//这个方法只判断一个非叶子节点
            }
            n[i]=temp;//如果前后的if条件符号就把之前父节点的值再给子节点
        }
    }

}

 


路漫漫其修远兮,吾将上下而求索