zoukankan      html  css  js  c++  java
  • 数据结构之平衡二叉树

    1.重新平衡2子树,体现了归纳思想,以及简单的建模思想。

    2.旋转名字不太好理解。自己觉得 “沿袭” 更恰当。自己为了进行沿袭这个动作。归纳了2个定理:

         1.父节点可垂直变为其左孩子或者左孩子的左孩子。左右同理。

         2.子树内部任意一支子树可代替原子树。

    有这2个定理。就可以不用理解书上的旋转了,用自己的沿袭就可以完成单旋转和双旋转。毕竟大部分书,都只是告诉你如何旋转,还不如自己建模,抽象,定义定理。来实现。

    3.重新计算树高度时,从变化的叶子开始要一直往父节点重新计算,所以很适合使用递归的方法,并保障从上往下时,是逐层往下,那么就可以保证插入和删除以后,会逐层检查子树高度,以及对比是否需要旋转

      而旋转后需要跟新子树的父节点。所以参考书上的方法是有返回节点的,一边递归回去的时候更新给父节点,而自己为了方便里面,没哟使用返回值,而是多加参数的方法,不简便,但好理解。

    归纳和抽象建模思想体现在哪里。第一步到第二步的转变侧重体现了归纳,抽象,建模等基本思想。  第二步到第三步更体现了为了解决实际问题,修改模型的能力。val是一个进行抽象思维的练习的好例子,非常值得复习

     采用了2中不同的函数来完成 add .一个带返回值,一个不带返回值,而是使用参数。

    package com.linson.datastrcture;
    
    
    
    
    
    //自己的插入在递归中,并没有和书上返回节点。自己感觉自己无返回值的更好理解,代替方案就是放入一个头节点的父节点。好理解,但也繁琐点。
    //递归返回根节点从代码的简洁上绝对更优,只是带参数的方法更容易理解。
    //avl这个例子很值得复习。1.递归时的问题模型的确定  2.平衡树时的建模思维。 3.树高的递归计算,递归影响。这个很不错。4.compareble的系统库接口使用。5.左小右大思路的利用。
    //6,删除时,需要平衡的时候会存在高的那一边的左右子树又一样高。比父节点的兄弟都高2级。
    
    public class MyAVL<T extends Comparable<T>>
    {
        public static class MyAVLNode<E extends Comparable<E>>
        {
            public E mElement;
            public MyAVLNode<E> mLeftNode;
            public MyAVLNode<E> mRightNode;
            public int mHeight;
            
            public MyAVLNode(E _value,MyAVLNode<E> left,MyAVLNode<E> right)
            {
                mElement=_value;
                mLeftNode=left;
                mRightNode=right;
                mHeight=1;
            }
            
            public int compareTo(E other)
            {
                return mElement.compareTo(other);
            }
        }
        
        public MyAVL()
        {
            mRootNode=null;
        }
        
        //问题:插入节点到树。组合:插入到节点,插入到左树,插入到右树. 基本值节点为空。可以插入。不需要再判断是否继续插入左或者右
        //节点高度默认是1,添加节点,必须逐层检测父节点:左右子树中最大值+1谁否大于现值? 大于要往上再检查,一直到某上层没变化。
        //所以返回值可以改为返回是否需要检查高度。但是想一下,又要增加返回值,又要判断是否需要检查,还不如每层都检查,反正AVL的话,数据再大也不会很高。1024才11层。
        public void add(T element,MyAVLNode<T> subTreeNode,MyAVLNode<T> fatherNode,boolean isLeft)
        {
            if(subTreeNode==null)
            {
                MyAVLNode<T> TempNode=new MyAVLNode<T>(element, null, null);//节点和树的泛型都实现了对比接口。所以树的参数,可以直接放入到节点中
                if(fatherNode!=null)
                {
                    if(isLeft)
                    {
                        fatherNode.mLeftNode=TempNode;
                    }
                    else 
                    {
                        fatherNode.mRightNode=TempNode;
                    }
                }
                else 
                {
                    mRootNode=TempNode;
                }
            }
            else
            {
                boolean addIsBiger=subTreeNode.mElement.compareTo(element)<0;//泛型实现了对比接口
                if(addIsBiger)
                {
                    add(element,subTreeNode.mRightNode,subTreeNode,false);
                }
                else 
                {
                    add(element,subTreeNode.mLeftNode,subTreeNode,true);
                }
                RotationAndHeight(subTreeNode,fatherNode,isLeft);
            }
        }
        
        //问题:匹配一个树,组合:匹配根,匹配左树,匹配右树。基本问题:节点就是。
        //空:直接删,副节点设空。 有单子树。修改数据。左右树都有,找高度更高的换数据。 被换节点一定是叶子,删除叶子,父节点设空。
        //旋转和高度问题。要求
        //1.传过来的根节点参数的左右子树高度是正确的。那么RotationAndHeight函数就就可以往上递归正确的计算高度和进行修正。
        //2.remove函数往下递归时,保证是逐层进行的。那么才能保证RotationAndHeight会逐层往上。
        public void remove(T element,MyAVLNode<T> subTreeNode,MyAVLNode<T> fatherNode,boolean isLeft)
        {
            if(subTreeNode==null)
            {
                return;
            }
            int compareRet=subTreeNode.mElement.compareTo(element);
            if(compareRet==0)
            {
                if(subTreeNode.mLeftNode==null && subTreeNode.mRightNode==null)
                {
                    if(fatherNode!=null)
                        if(isLeft)
                        {
                            fatherNode.mLeftNode=null;
                        }
                        else 
                        {
                            fatherNode.mRightNode=null;
                        }
                    else 
                    {
                        mRootNode=null;
                    }
                }
                else if(subTreeNode.mLeftNode==null || subTreeNode.mRightNode==null)
                {
                    if(fatherNode!=null)
                    {
                        if(isLeft)
                        {
                            fatherNode.mLeftNode=subTreeNode.mLeftNode==null?subTreeNode.mRightNode:subTreeNode.mLeftNode;
                        }
                        else 
                        {
                            fatherNode.mRightNode=subTreeNode.mLeftNode==null?subTreeNode.mRightNode:subTreeNode.mLeftNode;
                        }
                    }
                    else 
                    {
                        mRootNode=subTreeNode.mLeftNode==null?subTreeNode.mRightNode:subTreeNode.mLeftNode;
                    }
                }
                else 
                {
                    MyAVLNode<T> minnode= findMin(subTreeNode.mRightNode);
                    subTreeNode.mElement=minnode.mElement;
                    //可以确定是叶子,要效率高点。就可以新写个findMin,返回父节点。直接写代码删除。不需要这里一直递归。但对于修正平衡就没有办法往上递归了。
                    remove(minnode.mElement, subTreeNode.mRightNode, subTreeNode, false);
                    RotationAndHeight(subTreeNode,fatherNode,isLeft);
                }
            }
            else if(compareRet>0)//根节点更大。
            {
                remove(element, subTreeNode.mLeftNode,subTreeNode, true);
                RotationAndHeight(subTreeNode,fatherNode,isLeft);
            }
            else 
            {
                remove(element, subTreeNode.mRightNode,subTreeNode, false);
                RotationAndHeight(subTreeNode,fatherNode,isLeft);
            }
            
            
        }
        
        public MyAVLNode<T> findMax(MyAVLNode<T> subTreeNode)
        {
    
            MyAVLNode<T> tempRet=subTreeNode;
            while(tempRet!=null && tempRet.mRightNode!=null)
            {
                tempRet=tempRet.mRightNode;
            }
            return tempRet;
        }
        
        public MyAVLNode<T> findMin(MyAVLNode<T> subTreeNode)
        {
    
            MyAVLNode<T> tempRet=subTreeNode;
            while(tempRet!=null && tempRet.mLeftNode!=null)
            {
                tempRet=tempRet.mLeftNode;
            }
            return tempRet;
        }
        
        private void RotationAndHeight(MyAVLNode<T> subTreeNode,MyAVLNode<T> fatherNode,boolean isLeft)
        {
            //高度差=2 旋转,重新计算高度。
            //高度差<2. 根节点是否需要更新高度。
            //高度差>2 .错误。
            //断言对于快速开发和测试非常重要,而且减少正式版的编译代码和速度。不过如果有必要后期还是要写入到日志中.
            int leftHeight=subTreeNode.mLeftNode==null?0:subTreeNode.mLeftNode.mHeight;
            int rightHeight=subTreeNode.mRightNode==null?0:subTreeNode.mRightNode.mHeight;
            int maxSubTreeHeight=Math.max(leftHeight, rightHeight);
            
            assert(Math.abs(leftHeight-rightHeight)<=2) : "why .left compare to right is error";
            if(Math.abs(leftHeight-rightHeight)==2)
            {
                int ll=0,lr=0,rl=0,rr=0;
                int treetype=0;
                if(leftHeight-rightHeight==2)
                {
                    assert(subTreeNode.mLeftNode!=null):"no way";
                    ll=subTreeNode.mLeftNode.mLeftNode==null?0:subTreeNode.mLeftNode.mLeftNode.mHeight;
                    lr=subTreeNode.mLeftNode.mRightNode==null?0:subTreeNode.mLeftNode.mRightNode.mHeight;
                    if(ll>=lr)//这里用等号的话,删除的时候,可以用更简单的单转。
                    {
                        MyAVLNode<T> newRoot= subTreeNode.mLeftNode;
                        subTreeNode.mLeftNode=newRoot.mRightNode;
                        newRoot.mRightNode=subTreeNode;
                        newRoot.mRightNode.mHeight=newRoot.mRightNode.mHeight-1;
                        if(isLeft && fatherNode!=null)
                        {
                            fatherNode.mLeftNode=newRoot;
                        }
                        else if (!isLeft && fatherNode!=null) {
                            fatherNode.mRightNode=newRoot;
                        }
                        else {
                            mRootNode=newRoot;
                        }
                    }
                    else 
                    {
                        MyAVLNode<T> newRoot= subTreeNode.mLeftNode.mRightNode;
                        subTreeNode.mLeftNode.mRightNode=newRoot.mLeftNode;
                        newRoot.mLeftNode= subTreeNode.mLeftNode;
                        subTreeNode.mLeftNode=newRoot.mRightNode;
                        newRoot.mRightNode=subTreeNode;
                        newRoot.mHeight++;
                        newRoot.mLeftNode.mHeight--;
                        newRoot.mRightNode.mHeight--;
                        if(isLeft && fatherNode!=null)
                        {
                            fatherNode.mLeftNode=newRoot;
                        }
                        else if (!isLeft && fatherNode!=null) {
                            fatherNode.mRightNode=newRoot;
                        }
                        else {
                            mRootNode=newRoot;
                        }
                    }
                }
                else 
                {
                    assert(subTreeNode.mRightNode!=null):"no way";
                    rl=subTreeNode.mRightNode.mLeftNode==null?0:subTreeNode.mRightNode.mLeftNode.mHeight;
                    rr=subTreeNode.mRightNode.mLeftNode==null?0:subTreeNode.mRightNode.mLeftNode.mHeight;
                    if(rr>=rl)//这里用等号的话,删除的时候,可以用更简单的单转。
                    {
                        MyAVLNode<T> newRoot= subTreeNode.mRightNode;
                        subTreeNode.mRightNode=newRoot.mLeftNode;
                        newRoot.mLeftNode=subTreeNode;
                        newRoot.mLeftNode.mHeight=newRoot.mLeftNode.mHeight-1;
                        if(isLeft && fatherNode!=null)
                        {
                            fatherNode.mLeftNode=newRoot;
                        }
                        else if (!isLeft && fatherNode!=null) {
                            fatherNode.mRightNode=newRoot;
                        }
                        else {
                            mRootNode=newRoot;
                        }
                    }
                    else 
                    {
                        MyAVLNode<T> newRoot= subTreeNode.mRightNode.mLeftNode;
                        subTreeNode.mRightNode.mLeftNode=newRoot.mRightNode;
                        newRoot.mRightNode= subTreeNode.mRightNode;
                        subTreeNode.mRightNode=newRoot.mLeftNode;
                        newRoot.mLeftNode=subTreeNode;
                        newRoot.mHeight++;
                        newRoot.mRightNode.mHeight--;
                        newRoot.mLeftNode.mHeight--;
                        if(isLeft && fatherNode!=null)
                        {
                            fatherNode.mLeftNode=newRoot;
                        }
                        else if (!isLeft && fatherNode!=null) {
                            fatherNode.mRightNode=newRoot;
                        }
                        else {
                            mRootNode=newRoot;
                        }
                    }
                }
            }
            else if(Math.abs(leftHeight-rightHeight)==1)
            {
                
                assert((subTreeNode.mHeight-maxSubTreeHeight==0 || subTreeNode.mHeight-maxSubTreeHeight==1)) : "top node's height was wrong compare with left and right substree"; 
                if(subTreeNode.mHeight-maxSubTreeHeight==0)
                {
                    subTreeNode.mHeight++;
                }
            }
        }
        
        
        
        
        //add:主要是4个问题。1,正确插入位置。2,更新新插入点的父节点数据。3.更新新插入点的父节点数据的高度,4.新插入点的父节点是否平衡
        //                   1,一般处理。2,采用递归+方法带返回值:新节点,那么当递归返回上层时,可给返回的新插入点赋予正确的父节点。
        //   3.4,保证递归方法是逐层进行,并保证新插入点的左右子树高度正确。那么递归回来,会保证新插入点及其所有父节点左右子树高度正确以及都检测旋转。
        public MyAVLNode<T> add(T element,MyAVLNode<T> addToThisNode)
        {
            MyAVLNode<T> ret=null;
            if(addToThisNode==null)//某条件下,成了基本问题
            {
                ret= new MyAVLNode<T>(element, null, null);
            }
            else//其他条件下,用更小规模问题来组合
            {
                int addIsBigger=element.compareTo(addToThisNode.mElement);
                if(addIsBigger<0)
                {
                    addToThisNode.mLeftNode= add(element, addToThisNode.mLeftNode);
                }
                else 
                {
                    addToThisNode.mRightNode=add(element, addToThisNode.mRightNode);
                }
                ret=addToThisNode;
    
            }
            //检查高度,检查是否需要旋转。
            ret=reHeightAndBalance(ret);
            if(addToThisNode==mRootNode)
            {
                mRootNode=ret;
            }
            return ret;
        }
        
        //remove 和add基本思路一样。稍微复杂一点.
        //有目标点有3种情况,1,无左右子树,那么删除叶子,2,左右一个为空。那么跳过要删除点,和左右子树想相连。
        //3.左右都不为空,本质和1是一样。删除右子树的最小值节点,也就是一个叶子。并把叶子的数据给目标点。
        //返回当前子树最高顶点。
        public MyAVLNode<T> remove(T element,MyAVLNode<T> removeThisNode)
        {
            MyAVLNode<T> ret=null;
            if(removeThisNode==null)
            {
                //空树或者没找到要删除的点,什么都不做,并返回null,因为本来就是null,返回给这个节点的父节点NULL,等于什么都没做。
                ret=null;
            }
            else 
            {
                int removeIsBigger=element.compareTo(removeThisNode.mElement);
                if(removeIsBigger==0)////某条件下,成了基本问题
                {
                    if(removeThisNode.mLeftNode==null && removeThisNode.mRightNode==null)
                    {
                        removeThisNode=null;//其实这句没用,栈内的一个变量赋值为空而已,也没达到手动释放的堆内存,而且是java了。没必要劳心内存问题。
                        ret=null;
                    }
                    else if(removeThisNode.mLeftNode==null || removeThisNode.mRightNode==null)//不可以写成 != || != .因为会包含 != && !=.而现在这样写,额外包含的,在上面已经被排除了.
                    {
                        ret =removeThisNode.mLeftNode==null?removeThisNode.mRightNode:removeThisNode.mLeftNode;
                    }
                    else
                    {
                        MyAVLNode<T> minNode= findMin(removeThisNode.mRightNode);
                        removeThisNode.mElement= minNode.mElement;
                        removeThisNode.mRightNode=remove(minNode.mElement, removeThisNode.mRightNode);
                        ret=removeThisNode;
                        //return remove(minNode.mElement, removeThisNode.mRightNode);//原写代码 严重错误。
                    }
                }
                else if(removeIsBigger<0)
                {
                    removeThisNode.mLeftNode= remove(element, removeThisNode.mLeftNode);
                    ret=removeThisNode;
                }
                else 
                {
                    removeThisNode.mRightNode= remove(element, removeThisNode.mRightNode);
                    ret=removeThisNode;
                }
            }
            ret=reHeightAndBalance(ret);
            if(removeThisNode==mRootNode)
            {
                mRootNode=ret;
            }
            return ret;
        }
        
        
        //rotation: add .可从新加入点算起,add方法已经是逐步升入,那么会原路返回
        //remove:1. 双枝或空枝,逐步过来,最低点有null情况。返回nlll就好。 2.单枝情况,还好, 检查返回值的高度和平衡。再重新返回.
        private MyAVLNode<T> reHeightAndBalance(MyAVLNode<T> subTreeNode)
        {
            MyAVLNode<T> ret=subTreeNode;
            //null:返回 。 要平衡:平衡。算高度。
            if(subTreeNode==null)
            {
                ret=null;
            }
            else 
            {
                int leftHeight=subTreeNode.mLeftNode==null?0:subTreeNode.mLeftNode.mHeight;
                int rightHeight=subTreeNode.mRightNode==null?0:subTreeNode.mRightNode.mHeight;
                int maxSubTreeHeight=Math.max(leftHeight, rightHeight);
                
                assert(Math.abs(leftHeight-rightHeight)<=2) : "why .left compare to right is error";
                if(Math.abs(leftHeight-rightHeight)==2)
                {
                    int ll=0,lr=0,rl=0,rr=0;
                    int treetype=0;
                    if(leftHeight-rightHeight==2)
                    {
                        assert(subTreeNode.mLeftNode!=null):"no way";
                        ll=subTreeNode.mLeftNode.mLeftNode==null?0:subTreeNode.mLeftNode.mLeftNode.mHeight;
                        lr=subTreeNode.mLeftNode.mRightNode==null?0:subTreeNode.mLeftNode.mRightNode.mHeight;
                        if(ll>=lr)//这里用等号的话,删除的时候,可以用更简单的单转。
                        {
                            MyAVLNode<T> newRoot= subTreeNode.mLeftNode;
                            subTreeNode.mLeftNode=newRoot.mRightNode;
                            newRoot.mRightNode=subTreeNode;
                            newRoot.mRightNode.mHeight=newRoot.mRightNode.mHeight-1;
                            ret=newRoot;
                        }
                        else 
                        {
                            MyAVLNode<T> newRoot= subTreeNode.mLeftNode.mRightNode;
                            subTreeNode.mLeftNode.mRightNode=newRoot.mLeftNode;
                            newRoot.mLeftNode= subTreeNode.mLeftNode;
                            subTreeNode.mLeftNode=newRoot.mRightNode;
                            newRoot.mRightNode=subTreeNode;
                            newRoot.mHeight++;
                            newRoot.mLeftNode.mHeight--;
                            newRoot.mRightNode.mHeight--;
                            ret=newRoot;
                        }
                    }
                    else 
                    {
                        assert(subTreeNode.mRightNode!=null):"no way";
                        rl=subTreeNode.mRightNode.mLeftNode==null?0:subTreeNode.mRightNode.mLeftNode.mHeight;
                        rr=subTreeNode.mRightNode.mLeftNode==null?0:subTreeNode.mRightNode.mLeftNode.mHeight;
                        if(rr>=rl)//这里用等号的话,删除的时候,可以用更简单的单转。
                        {
                            MyAVLNode<T> newRoot= subTreeNode.mRightNode;
                            subTreeNode.mRightNode=newRoot.mLeftNode;
                            newRoot.mLeftNode=subTreeNode;
                            newRoot.mLeftNode.mHeight=newRoot.mLeftNode.mHeight-1;
                            ret=newRoot;
                        }
                        else 
                        {
                            MyAVLNode<T> newRoot= subTreeNode.mRightNode.mLeftNode;
                            subTreeNode.mRightNode.mLeftNode=newRoot.mRightNode;
                            newRoot.mRightNode= subTreeNode.mRightNode;
                            subTreeNode.mRightNode=newRoot.mLeftNode;
                            newRoot.mLeftNode=subTreeNode;
                            newRoot.mHeight++;
                            newRoot.mRightNode.mHeight--;
                            newRoot.mLeftNode.mHeight--;
                            ret=newRoot;
                        }
                    }
                }
                else if(Math.abs(leftHeight-rightHeight)==1)
                {
                    assert((subTreeNode.mHeight-maxSubTreeHeight==0 || subTreeNode.mHeight-maxSubTreeHeight==1)) : "top node's height was wrong compare with left and right substree"; 
                    if(subTreeNode.mHeight-maxSubTreeHeight==0)
                    {
                        subTreeNode.mHeight++;
                    }
                    ret=subTreeNode;
                }
            }
            
            return ret;
        }
    
        //type:0:first print parent node .1 left children ,parent, right children. 2:left children ,right children parent.
        public void printTree(int type)
        {
            printTree(mRootNode, type,"");
        }
        
        //打印树:组合:打印左树,打印节点,打印右树。基本情况:叶子。
        private void printTree(MyAVLNode<T> node,int type,String space)
        {
            if(node==null)
            {
                System.out.println("");
                return;
            }
            
            String leafInfo=space+node.mElement.toString()+"["+node.mHeight+"]";
            String newSpace=space+"     ";
            
            if(node.mLeftNode==null && node.mRightNode==null)
            {
                System.out.println(leafInfo);
            }
            else
            {
                
                if(type==0)
                {
                    System.out.println(leafInfo);
                    if(node.mLeftNode!=null)
                    {
                        printTree(node.mLeftNode, type,newSpace);
                    }
                    if(node.mRightNode!=null)
                    {
                        printTree(node.mRightNode, type,newSpace);
                    }
                }
                
                if(type==1)
                {
                    
                    if(node.mLeftNode!=null)
                    {
                        printTree(node.mLeftNode, type,newSpace);
                    }
                    System.out.println(leafInfo);
                    if(node.mRightNode!=null)
                    {
                        printTree(node.mRightNode, type,newSpace);
                    }
                }
                
                if(type==2)
                {
                    if(node.mLeftNode!=null)
                    {
                        printTree(node.mLeftNode, type,newSpace);
                    }
                    if(node.mRightNode!=null)
                    {
                        printTree(node.mRightNode, type,newSpace);
                    }
                    System.out.println(leafInfo);
                }
                if(type==3)
                {
                    if(node.mRightNode!=null)
                    {
                        printTree(node.mRightNode, type,newSpace);
                    }
                    System.out.println(leafInfo);
                    if(node.mLeftNode!=null)
                    {
                        printTree(node.mLeftNode, type,newSpace);
                    }
                    
                    
                    
                }
            }
        }
        
        
        public MyAVLNode<T> mRootNode=null;
    }

    测试代码

    public static class AVL
        {
            public static void test()
            {
                MyAVL<Integer> mytreeAvl=new MyAVL<Integer>();
    //            mytreeAvl.add(20, mytreeAvl.mRootNode,null,true);
    //            mytreeAvl.add(7, mytreeAvl.mRootNode,null,true);
    //            //mytreeAvl.add(56, mytreeAvl.mRootNode,null,true);
    //            //mytreeAvl.add(5, mytreeAvl.mRootNode,null,true);
    //            //mytreeAvl.add(9, mytreeAvl.mRootNode,null,true);
    //            //mytreeAvl.add(3, mytreeAvl.mRootNode,null,true);
    ////            mytreeAvl.add(12, mytreeAvl.mRootNode,null,true);
    ////            mytreeAvl.add(64, mytreeAvl.mRootNode,null,true);
    ////            mytreeAvl.add(33, mytreeAvl.mRootNode,null,true);
    ////            mytreeAvl.add(15, mytreeAvl.mRootNode,null,true);
                
                
                mytreeAvl.add(20, mytreeAvl.mRootNode);
                mytreeAvl.add(7, mytreeAvl.mRootNode);
                mytreeAvl.add(56, mytreeAvl.mRootNode);
                mytreeAvl.add(5, mytreeAvl.mRootNode);
                mytreeAvl.add(9, mytreeAvl.mRootNode);
                mytreeAvl.add(3, mytreeAvl.mRootNode);
                mytreeAvl.add(12, mytreeAvl.mRootNode);
    //            mytreeAvl.add(64, mytreeAvl.mRootNode,null,true);
    //            mytreeAvl.add(33, mytreeAvl.mRootNode,null,true);
    //            mytreeAvl.add(15, mytreeAvl.mRootNode,null,true);
                
                
                //mytreeAvl.remove(20, mytreeAvl.mRootNode, null, true);
                //mytreeAvl.remove(5, mytreeAvl.mRootNode, null, true);
                
                mytreeAvl.printTree(3);
            }
        }
  • 相关阅读:
    mac os programming
    Rejecting Good Engineers?
    Do Undergrads in MIT Struggle to Obtain Good Grades?
    Go to industry?
    LaTex Tricks
    Convert jupyter notebooks to python files
    How to get gradients with respect to the inputs in pytorch
    Uninstall cuda 9.1 and install cuda 8.0
    How to edit codes on the server which runs jupyter notebook using your pc's bwroser
    Leetcode No.94 Binary Tree Inorder Traversal二叉树中序遍历(c++实现)
  • 原文地址:https://www.cnblogs.com/lsfv/p/10565535.html
Copyright © 2011-2022 走看看