TreeMap的讲解

本文转载自:http://blog.csdn.net/chenssy/article/details/26668941点击打开链接

   原文出自:http://cmsblogs.com/?p=1013。尊重作者的成果,转载请注明出处!   

       个人站点:http://cmsblogs.com

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

TreeMap的实现是红黑树算法的实现,所以要了解TreeMap就必须对红黑树有一定的了解,其实这篇博文的名字叫做:根据红黑树的算法来分析TreeMap的实现,但是为了与Java提高篇系列博文保持一致还是叫做TreeMap比较好。通过这篇博文你可以获得如下知识点:

       1、红黑树的基本概念。

       2、红黑树增加节点、删除节点的实现过程。

       3、红黑树左旋转、右旋转的复杂过程。

       4、Java 中TreeMap是如何通过put、deleteEntry两个来实现红黑树增加、删除节点的。

我想通过这篇博文你对TreeMap一定有了更深的认识。好了,下面先简单普及红黑树知识。


       一、红黑树简介

       红黑树又称红-黑二叉树,它首先是一颗二叉树,它具体二叉树所有的特性。同时红黑树更是一颗自平衡的排序二叉树。

       我们知道一颗基本的二叉树他们都需要满足一个基本性质--即树中的任何节点的值大于它的左子节点,且小于它的右子节点。按照这个基本性质使得树的检索效率大大提高。我们知道在生成二叉树的过程是非常容易失衡的,最坏的情况就是一边倒(只有右/左子树),这样势必会导致二叉树的检索效率大大降低(O(n)),所以为了维持二叉树的平衡,大牛们提出了各种实现的算法,如:AVL,SBT,伸展树,TREAP ,红黑树等等。

       平衡二叉树必须具备如下特性:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。也就是说该二叉树的任何一个等等子节点,其左右子树的高度都相近。


       红黑树顾名思义就是节点是红色或者黑色的平衡二叉树,它通过颜色的约束来维持着二叉树的平衡。对于一棵有效的红黑树二叉树而言我们必须增加如下规则:

       1、每个节点都只能是红色或者黑色

       2、根节点是黑色

       3、每个叶节点(NIL节点,空节点)是黑色的。

       4、如果一个结点是红的,则它两个子节点都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。

       5、从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

       这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这棵树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。所以红黑树它是复杂而高效的,其检索效率O(log n)。下图为一颗典型的红黑二叉树。


       对于红黑二叉树而言它主要包括三大基本操作:左旋、右旋、着色。


左旋                                   右旋

(图片来自:http://www.cnblogs.com/yangecnu/p/Introduce-Red-Black-Tree.html)


       本节参考文献:http://baike.baidu.com/view/133754.htm?fr=aladdin-----百度百科

       注:由于本文主要是讲解Java中TreeMap,所以并没有对红黑树进行非常深入的了解和研究,如果诸位想对其进行更加深入的研究Lz提供几篇较好的博文:

       1、红黑树系列集锦

       2、红黑树数据结构剖析

       3、红黑树 


       二、TreeMap数据结构

       >>>>>>回归主角:TreeMap<<<<<<

       TreeMap的定义如下:

public class TreeMap<K,V>extends AbstractMap<K,V>implements NavigableMap<K,V>, Cloneable, java.io.Serializable

       TreeMap继承AbstractMap,实现NavigableMap、Cloneable、Serializable三个接口。其中AbstractMap表明TreeMap为一个Map即支持key-value的集合, NavigableMap(更多)则意味着它支持一系列的导航方法,具备针对给定搜索目标返回最接近匹配项的导航方法 。

       TreeMap中同时也包含了如下几个重要的属性:

//比较器,因为TreeMap是有序的,通过comparator接口我们可以对TreeMap的内部排序进行精密的控制private final Comparator<? super K> comparator;//TreeMap红-黑节点,为TreeMap的内部类private transient Entry<K,V> root = null;//容器大小private transient int size = 0;//TreeMap修改次数private transient int modCount = 0;//红黑树的节点颜色--红色private static final boolean RED = false;//红黑树的节点颜色--黑色private static final boolean BLACK = true;

       对于叶子节点Entry是TreeMap的内部类,它有几个重要的属性:

//
        K key;//值
        V value;//左孩子Entry<K,V> left = null;//右孩子Entry<K,V> right = null;//父亲Entry<K,V> parent;//颜色boolean color = BLACK;

       注:前面只是开胃菜,下面是本篇博文的重中之重,在下面两节我将重点讲解treeMap的put()、delete()方法。通过这两个方法我们会了解红黑树增加、删除节点的核心算法。


       三、TreeMap put()方法

       在了解TreeMap的put()方法之前,我们先了解红黑树增加节点的算法。

       红黑树增加节点

       红黑树在新增节点过程中比较复杂,复杂归复杂它同样必须要依据上面提到的五点规范,同时由于规则1、2、3基本都会满足,下面我们主要讨论规则4、5。假设我们这里有一棵最简单的树,我们规定新增的节点为N、它的父节点为P、P的兄弟节点为U、P的父节点为G。


       对于新节点的插入有如下三个关键地方:

       1、插入新节点总是红色节点 。

       2、如果插入节点的父节点是黑色, 能维持性质 。

       3、如果插入节点的父节点是红色, 破坏了性质. 故插入算法就是通过重新着色或旋转, 来维持性质 。

       为了保证下面的阐述更加清晰和根据便于参考,我这里将红黑树的五点规定再贴一遍:

1、每个节点都只能是红色或者黑色

2、根节点是黑色

3、每个叶节点(NIL节点,空节点)是黑色的。

4、如果一个结点是红的,则它两个子节点都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。

5、从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。



  •        一、为跟节点
  •        若新插入的节点N没有父节点,则直接当做根据节点插入即可,同时将颜色设置为黑色。(如图一(1))

           二、父节点为黑色

           这种情况新节点N同样是直接插入,同时颜色为红色,由于根据规则四它会存在两个黑色的叶子节点,值为null。同时由于新增节点N为红色,所以通过它的子节点的路径依然会保存着相同的黑色节点数,同样满足规则5。(如图一(2))


    (图一)

           三、若父节点P和P的兄弟节点U都为红色

           对于这种情况若直接插入肯定会出现不平衡现象。怎么处理?P、U节点变黑、G节点变红。这时由于经过节点P、U的路径都必须经过G所以在这些路径上面的黑节点数目还是相同的。但是经过上面的处理,可能G节点的父节点也是红色,这个时候我们需要将G节点当做新增节点递归处理。


           四、若父节点P为红色,叔父节点U为黑色或者缺少,且新增节点N为P节点的右孩子

           对于这种情况我们对新增节点N、P进行一次左旋转。这里所产生的结果其实并没有完成,还不是平衡的(违反了规则四),这是我们需要进行情况5的操作。


  •        五、父节点P为红色,叔父节点U为黑色或者缺少,新增节点N为父节点P左孩子


  •        这种情况有可能是由于情况四而产生的,也有可能不是。对于这种情况先已P节点为中心进行右旋转,在旋转后产生的树中,节点P是节点N、G的父节点。但是这棵树并不规范,它违反了规则4,所以我们将P、G节点的颜色进行交换,使之其满足规范。开始时所有的路径都需要经过G其他们的黑色节点数一样,但是现在所有的路径改为经过P,且P为整棵树的唯一黑色节点,所以调整后的树同样满足规范5。


  •        上面展示了红黑树新增节点的五种情况,这五种情况涵盖了所有的新增可能,不管这棵红黑树多么复杂,都可以根据这五种情况来进行生成。下面就来分析Java中的TreeMap是如何来实现红黑树的。


  •        TreeMap put()方法实现分析

           在TreeMap的put()的实现方法中主要分为两个步骤,第一:构建排序二叉树,第二:平衡二叉树。

           对于排序二叉树的创建,其添加节点的过程如下:

  •        1、以根节点为初始节点进行检索。

  •        2、与当前节点进行比对,若新增节点值较大,则以当前节点的右子节点作为新的当前节点。否则以当前节点的左子节点作为新的当前节点。

  •        3、循环递归2步骤知道检索出合适的叶子节点为止。

  •        4、将新增节点与3步骤中找到的节点进行比对,如果新增节点较大,则添加为右子节点;否则添加为左子节点。

  •        按照这个步骤我们就可以将一个新增节点添加到排序二叉树中合适的位置。如下:


  • [html] view plaincopy
    print?在CODE上查看代码片派生到我的代码片
    1. public V put(K key, V value) {  
    2.            //用t表示二叉树的当前节点  
    3.             Entry<K,V> t = root;  
    4.             //t为null表示一个空树,即TreeMap中没有任何元素,直接插入  
    5.             if (t == null) {  
    6.                 //比较key值,个人觉得这句代码没有任何意义,空树还需要比较、排序?  
    7.                 compare(key, key); // type (and possibly null) check  
    8.                 //将新的key-value键值对创建为一个Entry节点,并将该节点赋予给root  
    9.                 root = new Entry<>(key, value, null);  
    10.                 //容器的size = 1,表示TreeMap集合中存在一个元素  
    11.                 size = 1;  
    12.                 //修改次数 + 1  
    13.                 modCount++;  
    14.                 return null;  
    15.             }  
    16.             int cmp;     //cmp表示key排序的返回结果  
    17.             Entry<K,V> parent;   //父节点  
    18.             // split comparator and comparable paths  
    19.             Comparator<? super K> cpr = comparator;    //指定的排序算法  
    20.             //如果cpr不为空,则采用既定的排序算法进行创建TreeMap集合  
    21.             if (cpr != null) {  
    22.                 do {  
    23.                     parent = t;      //parent指向上次循环后的t  
    24.                     //比较新增节点的key和当前节点key的大小  
    25.                     cmp = cpr.compare(key, t.key);  
    26.                     //cmp返回值小于0,表示新增节点的key小于当前节点的key,则以当前节点的左子节点作为新的当前节点  
    27.                     if (cmp < 0)  
    28.                         t = t.left;  
    29.                     //cmp返回值大于0,表示新增节点的key大于当前节点的key,则以当前节点的右子节点作为新的当前节点  
    30.                     else if (cmp > 0)  
    31.                         t = t.right;  
    32.                     //cmp返回值等于0,表示两个key值相等,则新值覆盖旧值,并返回新值  
    33.                     else  
    34.                         return t.setValue(value);  
    35.                 } while (t != null);  
    36.             }  
    37.             //如果cpr为空,则采用默认的排序算法进行创建TreeMap集合  
    38.             else {  
    39.                 if (key == null)     //key值为空抛出异常  
    40.                     throw new NullPointerException();  
    41.                 /* 下面处理过程和上面一样 */  
    42.                 Comparable<? super K> k = (Comparable<? super K>) key;  
    43.                 do {  
    44.                     parent = t;  
    45.                     cmp = k.compareTo(t.key);  
    46.                     if (cmp < 0)  
    47.                         t = t.left;  
    48.                     else if (cmp > 0)  
    49.                         t = t.right;  
    50.                     else  
    51.                         return t.setValue(value);  
    52.                 } while (t != null);  
    53.             }  
    54.             //将新增节点当做parent的子节点  
    55.             Entry<K,V> e = new Entry<>(key, value, parent);  
    56.             //如果新增节点的key小于parent的key,则当做左子节点  
    57.             if (cmp < 0)  
    58.                 parent.left = e;  
    59.           //如果新增节点的key大于parent的key,则当做右子节点  
    60.             else  
    61.                 parent.right = e;  
    62.             /*  
    63.              *  上面已经完成了排序二叉树的的构建,将新增节点插入该树中的合适位置  
    64.              *  下面fixAfterInsertion()方法就是对这棵树进行调整、平衡,具体过程参考上面的五种情况  
    65.              */  
    66.             fixAfterInsertion(e);  
    67.             //TreeMap元素数量 + 1  
    68.             size++;  
    69.             //TreeMap容器修改次数 + 1  
    70.             modCount++;  
    71.             return null;  
    72.         }  

  • 上面代码中do{}代码块是实现排序二叉树的核心算法,通过该算法我们可以确认新增节点在该树的正确位置。找到正确位置后将插入即可,这样做了其实还没有完成,因为我知道TreeMap的底层实现是红黑树,红黑树是一棵平衡排序二叉树,普通的排序二叉树可能会出现失衡的情况,所以下一步就是要进行调整。fixAfterInsertion(e); 调整的过程务必会涉及到红黑树的左旋、右旋、着色三个基本操作。代码如下:
  • [java] view plaincopy
    print?在CODE上查看代码片派生到我的代码片
    1. /** 
    2.      * 新增节点后的修复操作 
    3.      * x 表示新增节点 
    4.      */  
    5.      private void fixAfterInsertion(Entry<K,V> x) {  
    6.             x.color = RED;    //新增节点的颜色为红色  
    7.   
    8.             //循环 直到 x不是根节点,且x的父节点不为红色  
    9.             while (x != null && x != root && x.parent.color == RED) {  
    10.                 //如果X的父节点(P)是其父节点的父节点(G)的左节点  
    11.                 if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {  
    12.                     //获取X的叔节点(U)  
    13.                     Entry<K,V> y = rightOf(parentOf(parentOf(x)));  
    14.                     //如果X的叔节点(U) 为红色(情况三)  
    15.                     if (colorOf(y) == RED) {       
    16.                         //将X的父节点(P)设置为黑色  
    17.                         setColor(parentOf(x), BLACK);  
    18.                         //将X的叔节点(U)设置为黑色  
    19.                         setColor(y, BLACK);  
    20.                         //将X的父节点的父节点(G)设置红色  
    21.                         setColor(parentOf(parentOf(x)), RED);  
    22.                         x = parentOf(parentOf(x));  
    23.                     }  
    24.                     //如果X的叔节点(U为黑色);这里会存在两种情况(情况四、情况五)  
    25.                     else {     
    26.                         //如果X节点为其父节点(P)的右子树,则进行左旋转(情况四)  
    27.                         if (x == rightOf(parentOf(x))) {  
    28.                             //将X的父节点作为X  
    29.                             x = parentOf(x);  
    30.                             //右旋转  
    31.                             rotateLeft(x);  
    32.                         }  
    33.                         //(情况五)  
    34.                         //将X的父节点(P)设置为黑色  
    35.                         setColor(parentOf(x), BLACK);  
    36.                         //将X的父节点的父节点(G)设置红色  
    37.                         setColor(parentOf(parentOf(x)), RED);  
    38.                         //以X的父节点的父节点(G)为中心右旋转  
    39.                         rotateRight(parentOf(parentOf(x)));  
    40.                     }  
    41.                 }  
    42.                 //如果X的父节点(P)是其父节点的父节点(G)的右节点  
    43.                 else {  
    44.                     //获取X的叔节点(U)  
    45.                     Entry<K,V> y = leftOf(parentOf(parentOf(x)));  
    46.                   //如果X的叔节点(U) 为红色(情况三)  
    47.                     if (colorOf(y) == RED) {  
    48.                         //将X的父节点(P)设置为黑色  
    49.                         setColor(parentOf(x), BLACK);  
    50.                         //将X的叔节点(U)设置为黑色  
    51.                         setColor(y, BLACK);  
    52.                         //将X的父节点的父节点(G)设置红色  
    53.                         setColor(parentOf(parentOf(x)), RED);  
    54.                         x = parentOf(parentOf(x));  
    55.                     }  
    56.                   //如果X的叔节点(U为黑色);这里会存在两种情况(情况四、情况五)  
    57.                     else {  
    58.                         //如果X节点为其父节点(P)的右子树,则进行左旋转(情况四)  
    59.                         if (x == leftOf(parentOf(x))) {  
    60.                             //将X的父节点作为X  
    61.                             x = parentOf(x);  
    62.                            //右旋转  
    63.                             rotateRight(x);  
    64.                         }  
    65.                         //(情况五)  
    66.                         //将X的父节点(P)设置为黑色  
    67.                         setColor(parentOf(x), BLACK);  
    68.                         //将X的父节点的父节点(G)设置红色  
    69.                         setColor(parentOf(parentOf(x)), RED);  
    70.                         //以X的父节点的父节点(G)为中心右旋转  
    71.                         rotateLeft(parentOf(parentOf(x)));  
    72.                     }  
    73.                 }  
    74.             }  
    75.             //将根节点G强制设置为黑色  
    76.             root.color = BLACK;  
    77.         }  


  •        对这段代码的研究我们发现,其处理过程完全符合红黑树新增节点的处理过程。所以在看这段代码的过程一定要对红黑树的新增节点过程有了解。在这个代码中还包含几个重要的操作。左旋(rotateLeft())、右旋(rotateRight())、着色(setColor())。

    左旋:rotateLeft()

  •        所谓左旋转,就是将新增节点(N)当做其父节点(P),将其父节点P当做新增节点(N)的左子节点。即:G.left ---> N ,N.left ---> P。


  •        右旋:rotateRight()

    [java] view plaincopy
    print?在CODE上查看代码片派生到我的代码片
    1. private void rotateLeft(Entry<K,V> p) {  
    2.         if (p != null) {  
    3.             //获取P的右子节点,其实这里就相当于新增节点N(情况四而言)  
    4.             Entry<K,V> r = p.right;  
    5.             //将R的左子树设置为P的右子树  
    6.             p.right = r.left;  
    7.             //若R的左子树不为空,则将P设置为R左子树的父亲  
    8.             if (r.left != null)  
    9.                 r.left.parent = p;  
    10.             //将P的父亲设置R的父亲  
    11.             r.parent = p.parent;  
    12.             //如果P的父亲为空,则将R设置为跟节点  
    13.             if (p.parent == null)  
    14.                 root = r;  
    15.             //如果P为其父节点(G)的左子树,则将R设置为P父节点(G)左子树  
    16.             else if (p.parent.left == p)  
    17.                 p.parent.left = r;  
    18.             //否则R设置为P的父节点(G)的右子树  
    19.             else  
    20.                 p.parent.right = r;  
    21.             //将P设置为R的左子树  
    22.             r.left = p;  
    23.             //将R设置为P的父节点  
    24.             p.parent = r;  
    25.         }  
    26.     }  
  •        所谓右旋转即,P.right ---> G、G.parent ---> P。

  • [java] view plaincopy
    print?在CODE上查看代码片派生到我的代码片
    1. private void rotateRight(Entry<K,V> p) {  
    2.         if (p != null) {  
    3.             //将L设置为P的左子树  
    4.             Entry<K,V> l = p.left;  
    5.             //将L的右子树设置为P的左子树  
    6.             p.left = l.right;  
    7.             //若L的右子树不为空,则将P设置L的右子树的父节点  
    8.             if (l.right != null)   
    9.                 l.right.parent = p;  
    10.             //将P的父节点设置为L的父节点  
    11.             l.parent = p.parent;  
    12.             //如果P的父节点为空,则将L设置根节点  
    13.             if (p.parent == null)  
    14.                 root = l;  
    15.             //若P为其父节点的右子树,则将L设置为P的父节点的右子树  
    16.             else if (p.parent.right == p)  
    17.                 p.parent.right = l;  
    18.             //否则将L设置为P的父节点的左子树  
    19.             else   
    20.                 p.parent.left = l;  
    21.             //将P设置为L的右子树  
    22.             l.right = p;  
    23.             //将L设置为P的父节点  
    24.             p.parent = l;  
    25.         }  
    26.     }  
  •        左旋、右旋的示意图如下:


  • (左旋)                                         (右旋)

    (图片来自:http://www.cnblogs.com/yangecnu/p/Introduce-Red-Black-Tree.html)

           着色:setColor()

           着色就是改变该节点的颜色,在红黑树中,它是依靠节点的颜色来维持平衡的。

  • [java] view plaincopy
    print?在CODE上查看代码片派生到我的代码片
    1. private static <K,V> void setColor(Entry<K,V> p, boolean c) {  
    2.         if (p != null)  
    3.             p.color = c;  
    4.     }  

  •        四、TreeMap delete()方法

           红黑树删除节点

           针对于红黑树的增加节点而言,删除显得更加复杂,使原本就复杂的红黑树变得更加复杂。同时删除节点和增加节点一样,同样是找到删除的节点,删除之后调整红黑树。但是这里的删除节点并不是直接删除,而是通过走了“弯路”通过一种捷径来删除的:找到被删除的节点D的子节点C,用C来替代D,不是直接删除D,因为D被C替代了,直接删除C即可。所以这里就将删除父节点D的事情转变为了删除子节点C的事情,这样处理就将复杂的删除事件简单化了。子节点C的规则是:右分支最左边,或者 左分支最右边的。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/419413.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[国嵌笔记][036][关闭MMU和CACHE]

关闭MMU和CACHE 1.Cache是一种容量小&#xff0c;但存取速度非常快的存储器&#xff0c;它保存最近用到的存储器中数据的拷贝。按功能分为ICache&#xff08;指令Cache&#xff09;和DCache&#xff08;数据Cache&#xff09; 2.虚拟地址就是程序中使用的地址&#xff1b;物理地…

android蓝牙4.0使用方法

蓝牙介绍 Android 4.3(API Level 18)介绍了内置平台支持蓝牙低能量的核心作用,并提供了API,应用程序可以用它来发现设备,查询服务&#xff0c;和读写字符。与传统的蓝牙相比&#xff0c;Bluetooth Low Energy (BLE) 旨在提供显著降低功耗。这使得Android应用能够与具有BLE的低耗…

java基础面试题整理(BAT)

转载自&#xff1a;http://www.nowcoder.com/discuss/5949?type2&order0&pos23&page5点击打开链接 在阿里面试之前总结了一下内推同学的面经&#xff0c;把面试题总结到一块&#xff0c;并进行了分类。有些题目我也总结了一下答案&#xff0c;大家可以参考一下&am…

Android中设置输入法为数字输入

1.对于用XML布局的EditText 使用setInputType(EditorInfo.TYPE_CLASS_NUMBER); 2.对于用Java代码生成EditText 使用setInputType(EditorInfo.TYPE_CLASS_NUMBER); setKeyListener(new DigitsKeyListener(false,true));

n个数里找出前m个数(或者 从10亿个浮点数中找出最大的1万个)

转载自&#xff1a;http://blog.csdn.net/winsunxu/article/details/6219376点击打开链接 引子 每年十一月各大IT公司都不约而同、争后恐后地到各大高校进行全国巡回招聘。与此同时&#xff0c;网上也开始出现大量笔试面试题&#xff1b;网上流传的题目往往都很精巧&#xff0c…

poj_3977 折半枚举

题目大意 给定N&#xff08;N<35)个数字&#xff0c;每个数字都< 2^15. 其中一个或多个数字加和可以得到s&#xff0c;求出s的绝对值的最小值&#xff0c;并给出当s取绝对值最小值时&#xff0c;需要加和的数字的个数。 题目分析 需要枚举集合的所有情况&#xff0c;2^35…

Android 应用更新和在服务器下载android应用

下载android应用有两种表现形式&#xff1a;一种是交给Android系统的下载管理器;另一种是自己去监控下载。 1.使用Android下载管理器下载应用并安装 public class UpdateService extends Service {// 安卓系统下载管理类DownloadManager manager;// 接收下载完的广播DownloadCo…

Linux如何查看进程、杀死进程、启动进程等常用命令

转载自&#xff1a;http://blog.csdn.net/wojiaopanpan/article/details/7286430/ 关键字: linux 查进程、杀进程、起进程 1.查进程 ps命令查找与进程相关的PID号&#xff1a; ps a 显示现行终端机下的所有程序&#xff0c;包括其他用户的程序。 ps -A 显示所有程…

(原创)c#学习笔记06--函数02--变量的作用域01--其他结构中变量的作用域

6.2 变量的作用域 在上一节中&#xff0c;读者可能想知道为什么需要利用函数交换数据。原因是C#中的变量仅能从代码的本地作用域访问。给定的变量有一个作用域&#xff0c;访问该变量要通过这个作用域来实现。 在上一节中&#xff0c;读者可能想知道为什么需要利用函数交换数据…

禁用应用中Android系统的导航栏(特别是平板)

由于公司项目是在全屏下的&#xff0c;所有界面都是全屏&#xff0c;唯有弹出提示框的时候&#xff0c;会出现系统的导航栏&#xff0c;由于是平板&#xff0c;导航栏信息比较多&#xff0c;该项目属于永不让用户进入原系统的项目。所以有导航栏&#xff0c;就让用户有了机会进…

spring使用注解@Scheduled执行定时任务

最近做的项目中遇到了用spring中Schedule注解执行定时任务的功能&#xff0c;这里简单记录一下。 首先在applicationContext.xml中进行配置&#xff1a; xmlns 加下面的内容 xsi:schemaLocation加下面的内容 最后我们的task任务扫描注解 需要注意的几点&#xff1a; 1、spring的…

关于dialog的一点东西

今天开发一个上传照片的小功能&#xff0c;对弹出的Dialog的一些用法查找了下&#xff0c;记录下来以后备用。 1.设置dialog标题居中: 在style中配置如下代码 <style name"UploadDialog" parent"android:style/Theme.Dialog"> <item …

DIY Ruby CPU 分析 Part II

【编者按】作者 Emil Soman&#xff0c;Rubyist&#xff0c;除此之外竟然同时也是艺术家&#xff0c;吉他手&#xff0c;Garden City RubyConf 组织者。本文是 DIY Ruby CPU Profiling 的第二部分。本文系 OneAPM 工程师编译整理。 在第一部分中我们学习了 CPU 分析的含义和进行…

spring注解 @Scheduled(cron = 0 0 1 * * *)的使用来实现定时的执行任务

<span style"font-size:14px;">初次接触定时类的小程序&#xff0c;还是走了很多的弯路&#xff0c;如今终于搞定了&#xff0c;总结如下&#xff1a;</span> <span style"font-size:14px;">import com.activityvip.api.service.Securit…

在Oracle里,表的别名不能用as,列的别名可以用as

列的别名也可以不用as&#xff0c;如&#xff1a;select t.a xxx from table t在Oracle数据库中&#xff0c;数据表别名是不能加as的&#xff0c;例如&#xff1a; select a.appname from appinfo a;-- 正确 select a.appname from appinfo as a;-- 错误 注释&#xff1a;这…

Android自定义RadioButton

今天公司项目中需要完成一个效果&#xff0c;首先是要用自己的图片&#xff0c;然后文字在按钮图片的左边。 1.使文字在图片的左边&#xff0c;有两种方法&#xff1a; 第一种&#xff0c;设置radioButton的属性&#xff1a; <span style"font-size:24px;">a…

MySQL实现当前数据表的所有时间都增加或减少指定的时间间隔

做了一个简答的小项目&#xff0c;其中遇到了一些数据库的sql使用技巧总结如下&#xff1a; DATE_ADD() 函数向日期添加指定的时间间隔。 当前表所有数据都往后增加一天时间&#xff1a; UPDATE ACT_BlockNum SET CreateTime DATE_ADD(CreateTime, INTERVAL 1 DAY); 当前…