Hash Table

 
  1. /**
  2.  * filename: HashTable.java
  3.  * package: 
  4.  * author: Nick Ma
  5.  * email: nick.ma85@yahoo.com
  6.  * date: Nov 27, 2008
  7.  * description: this class implements a hash table data structure.
  8.  */
  9. import  java.util.*;
  10. public   class  HashTable<K,V>  implements  Map<K,V> {
  11.      /**
  12.      * the inner class of hash table to implement a key-value pair
  13.      */
  14.      public   static   class  Entry<K,V>  implements  Map.Entry<K,V> {
  15.         
  16.          // Data Field
  17.         
  18.          private  K key;  // the key
  19.          private  V value;  // the value
  20.          private  Entry<K,V> next;  // pointer to next entry with the same key
  21.         
  22.          /** this field is to store the hash code, for preventing from 
  23.          * frequently reading the code by calling hashCode() function.
  24.          */
  25.          private   int  hash;
  26.         
  27.          /**
  28.          * description: the default constructor
  29.          */
  30.          public  Entry() {
  31.              // TODO Auto-generated constructor stub
  32.              this ( nullnullnull );
  33.         }
  34.          /**
  35.          * description: the constructor with fields to create 
  36.          * a new key-value pair.
  37.          * @param key - the key
  38.          * @param value - the value
  39.          * @param next - the next entry
  40.          */
  41.          public  Entry(K key, V value, Entry<K,V> next) {
  42.              this .key = key;
  43.              this .value = value;
  44.              this .hash =  this .setHashCode();
  45.              this .next = next;
  46.         }
  47.          /* (non-Javadoc)
  48.          * @see java.util.Map.Entry#getKey()
  49.          */
  50.          @Override
  51.          public  K getKey() {
  52.              // TODO Auto-generated method stub
  53.              return   this .key;
  54.         }
  55.          /* (non-Javadoc)
  56.          * @see java.util.Map.Entry#getValue()
  57.          */
  58.          @Override
  59.          public  V getValue() {
  60.              // TODO Auto-generated method stub
  61.              return   this .value;
  62.         }
  63.          /* (non-Javadoc)
  64.          * @see java.util.Map.Entry#setValue(java.lang.Object)
  65.          */
  66.          @Override
  67.          public  V setValue(V object) {
  68.              // TODO Auto-generated method stub
  69.             V old =  this .value;
  70.              this .value = object;
  71.              this .hash =  this .setHashCode();
  72.              return  old;
  73.         }
  74.          /**
  75.          * @return the next
  76.          */
  77.          public  Entry<K, V> getNext() {
  78.              return  next;
  79.         }
  80.          /**
  81.          * @param next the next to set
  82.          */
  83.          public   void  setNext(Entry<K, V> next) {
  84.              this .next = next;
  85.         }
  86.          /* (non-Javadoc)
  87.          * @see java.lang.Object#clone()
  88.          */
  89.          @Override
  90.          protected  Object clone()  throws  CloneNotSupportedException {
  91.              // TODO Auto-generated method stub
  92.              return   new  Entry<K,V>( this .key,  this .value,  this .next);
  93.         }
  94.         
  95.          /* (non-Javadoc)
  96.          * @see java.lang.Object#hashCode()
  97.          */
  98.          @Override
  99.          public   int  hashCode() {
  100.              // TODO Auto-generated method stub
  101.              return   this .hash;
  102.         }
  103.          /* (non-Javadoc)
  104.          * @see java.lang.Object#equals(java.lang.Object)
  105.          */
  106.          @Override
  107.          public   boolean  equals(Object o) {
  108.              // TODO Auto-generated method stub
  109.             
  110.              //check for self-comparison
  111.              if ( this  == o){
  112.                  return   true ;
  113.             }
  114.              // check for class type
  115.              // here is an alternative:
  116.              // if(o == null || o.getClass() != this.getClass())
  117.              if (!(o  instanceof  Entry)) {
  118.                  return   false ;
  119.             }
  120.             
  121.              // cast to native object is now safe
  122.             Entry<K,V> entry = (Entry<K,V>)o;
  123.              // now a proper field-by-field evaluation can be made,
  124.              // and it has nothing to do with the field of next pointer,
  125.              // just comparing the pair, key and value.
  126.              return  entry.key.equals( this .key)
  127.                     && entry.value.equals( this .value)
  128.                     && entry.hash ==  this .hash;
  129.         }
  130.          /* (non-Javadoc)
  131.          * @see java.lang.Object#toString()
  132.          */
  133.          @Override
  134.          public  String toString() {
  135.              // TODO Auto-generated method stub
  136.              return  getKey() +  "="  + getValue();
  137.         }
  138.         
  139.          /**
  140.          * description: set the hash code
  141.          * @return - the hash code
  142.          */
  143.          private   int  setHashCode() {
  144.              return  ( this .key ==  null ) ?  0  :  this .key.hashCode();
  145.         }
  146.     }
  147.     
  148.      // Data Field
  149.     
  150.      /** a table to store data, which is resized as necessary */
  151.      private  Entry[] table;
  152.     
  153.      /** the number of key-value mappings contained in the table but not in the chain */
  154.      private   int  numOfEntries;
  155.     
  156.      /** the number of key-value mappings contained in the table */
  157.      private   int  numOfPairs;
  158.     
  159.      /** the number of deleted entries */
  160.      private   int  numOfDeletedEntries;
  161.     
  162.      /** the upper bound of load factor */
  163.      private   double  loadFactor;
  164.     
  165.      /** the default size of the table */
  166.      private   static   final   int  DEFAULT_SIZE =  16 ;
  167.     
  168.      /**
  169.      * the maximum capacity, used if a higher value is implicitly specified
  170.      * by either of the constructors with arguments.
  171.      */
  172.      private   static   final   int  MAXIMUM_SIZE =  1  <<  30 ;
  173.      /** the default load factor */
  174.      private   static   final   double  LOAD_FACTOR =  0.75 ;
  175.     
  176.      /** the deleted entry to reference */
  177.      private   final  Entry<K,V> DELETED_ENTRY =  new  Entry<K,V>();
  178.     
  179.      /** the table to store the possible hash table size */
  180.      private   int [] sizeTable =  new   int [ 30 ];
  181.     
  182.      /** the current index of size table */
  183.      private   int  currentSizeTableIndex;
  184.     
  185.      /** variables of statistics */
  186.      private   int  numOfCollision;  // the number of collisions during insertions 
  187.      private   int  totalChainLength;  // total chain length during all the insertion and look-up
  188.      private   int  avgChainLength;  // average chain length, totalChainLength/countChains
  189.      private   int  countChains;  // counter of insertion and look-up
  190.      private   int  maxChainLength;  // max chain length during an insertion or look-up
  191.      /**
  192.      * description: the default constructor
  193.      */
  194.      public  HashTable() {
  195.          // TODO Auto-generated constructor stub
  196.          this (HashTable.DEFAULT_SIZE, HashTable.LOAD_FACTOR);
  197.     }
  198.      /**
  199.      * description: the constructor to initialize the table with the given size
  200.      * @param size - the user-defined size of the table
  201.      */
  202.      public  HashTable( int  size) {
  203.          this (size, HashTable.LOAD_FACTOR);
  204.     }
  205.     
  206.      /**
  207.      * description: the constructor to initialize the table with the given size and load factor
  208.      * @param size - the user-defined size of the table
  209.      * @param loadFactor - the user-defined max load factor of this hash table
  210.      * @throws IllegalArgumentException - if the size and the load factor is illegal
  211.      */
  212.      public  HashTable( int  size,  double  loadFactor) {
  213.          if (size <  0 ) {
  214.              throw   new  IllegalArgumentException(
  215.                      "Illegal initial capacity: "  + size);
  216.         }
  217.          if (loadFactor <=  0  || Double.isNaN(loadFactor)) {
  218.              throw   new  IllegalArgumentException(
  219.                      "Illegal load factor: "  + loadFactor);
  220.         }
  221.         
  222.          // using power-of-two sizes to initialize the hash table
  223.         initializeSizeTable();
  224.         
  225.          // get the current size of entries from size table
  226.          for ( int  i =  0 ; i < sizeTable.length; i++) {
  227.              if (sizeTable[i] == size) {
  228.                  this .currentSizeTableIndex = i;
  229.             }
  230.         }
  231.         
  232.          // initialize the entries of the hash table
  233.          this .table =  new  Entry[ this .sizeTable[ this .currentSizeTableIndex]];
  234.          this .numOfEntries =  0 ;
  235.          this .numOfPairs =  0 ;
  236.          this .numOfDeletedEntries =  0 ;
  237.          this .loadFactor = loadFactor;
  238.          this .totalChainLength =  0 ;
  239.          this .maxChainLength =  0 ;
  240.          this .avgChainLength =  0 ;
  241.          this .numOfCollision =  0 ;
  242.          this .countChains =  0 ;
  243.     }
  244.      /* (non-Javadoc)
  245.      * @see java.util.Map#clear()
  246.      */
  247.      @Override
  248.      public   void  clear() {
  249.          // TODO Auto-generated method stub
  250.         Entry[] tab =  this .table;
  251.          for ( int  i =  0 ; i < tab.length; i++) {
  252.             tab[i] =  null ;
  253.         }
  254.          this .numOfEntries =  0 ;
  255.          this .numOfPairs =  0 ;
  256.          this .numOfDeletedEntries =  0 ;
  257.          this .totalChainLength =  0 ;
  258.          this .maxChainLength =  0 ;
  259.          this .avgChainLength =  0 ;
  260.          this .numOfCollision =  0 ;
  261.          this .countChains =  0 ;
  262.          this .loadFactor = HashTable.LOAD_FACTOR;
  263.     }
  264.      /* (non-Javadoc)
  265.      * @see java.util.Map#containsKey(java.lang.Object)
  266.      */
  267.      @Override
  268.      public   boolean  containsKey(Object arg0) {
  269.          // TODO Auto-generated method stub
  270.          return   this .getEntry((K)arg0) !=  null ;
  271.     }
  272.      /* (non-Javadoc)
  273.      * @see java.util.Map#containsValue(java.lang.Object)
  274.      */
  275.      @Override
  276.      public   boolean  containsValue(Object arg0) {
  277.          // TODO Auto-generated method stub
  278.          if (arg0 ==  null ) {
  279.             Entry[] tab =  this .table;
  280.              for ( int  i =  0 ; i < tab.length ; i++) {
  281.                  if (tab[i] !=  null ) {
  282.                     countChains++;   // increment the counter of totalChainLength
  283.                 }
  284.                  for (Entry<K,V> e = tab[i]; e !=  null ; e = e.next) {
  285.                      if (e.getValue() ==  null ) {
  286.                          return   true ;
  287.                     }
  288.                      this .totalChainLength++;
  289.                 }
  290.             }
  291.         }  else  {
  292.             Entry[] tab =  this .table;
  293.              for ( int  i =  0 ; i < tab.length ; i++) {
  294.                  if (tab[i] !=  null ) {
  295.                     countChains++;   // increment the counter of totalChainLength
  296.                 }
  297.                 
  298.                  for (Entry<K,V> e = tab[i]; e !=  null ; e = e.next) {
  299.                      if (e.getValue().equals((V)arg0)) {
  300.                          return   true ;
  301.                     }
  302.                      this .totalChainLength++;
  303.                 }
  304.             }
  305.         }
  306.          return   false ;
  307.     }
  308.      /* (non-Javadoc)
  309.      * @see java.util.Map#get(java.lang.Object)
  310.      */
  311.      @Override
  312.      public  V get(Object arg0) {
  313.          // TODO Auto-generated method stub
  314.          return   this .getEntry((K)arg0).getValue();
  315.     }
  316.      /* (non-Javadoc)
  317.      * @see java.util.Map#isEmpty()
  318.      */
  319.      @Override
  320.      public   boolean  isEmpty() {
  321.          // TODO Auto-generated method stub
  322.          return   this .numOfEntries ==  0 ;
  323.     }
  324.      /* (non-Javadoc)
  325.      * @see java.util.Map#put(java.lang.Object, java.lang.Object)
  326.      */
  327.      @Override
  328.      public  V put(K arg0, V arg1) {
  329.          // TODO Auto-generated method stub
  330.          int  hash = (arg0 ==  null ) ?  0  : hash(arg0.hashCode());
  331.          int  index =  this .indexFor(hash,  this .table.length);
  332.         Entry<K,V> entry =  this .table[index];
  333.         
  334.          if (entry !=  null  && ! this .isDeletedEntry(entry)) {
  335.             countChains++;   // increment the counter of totalChainLength
  336.             
  337.              for (Entry<K,V> e = entry;
  338.                 e !=  null ; e = e.getNext()) {
  339.                  if (e.hash == hash && (arg0 == e.getKey() || e.getKey().equals(arg0))) {
  340.                      return  e.setValue(arg1);
  341.                 }
  342.                  this .numOfCollision++;
  343.                  this .totalChainLength++;
  344.             
  345.                  if (e.getNext() ==  null ) {
  346.                      // add to the chain
  347.                     e.setNext( new  Entry<K,V>(arg0, arg1,  null ));
  348.                      break ;
  349.                 }
  350.             }
  351.             
  352.         }  else  {
  353.              // add to entry
  354.              this .table[index] =  new  Entry<K,V>(arg0, arg1,  null );
  355.              this .numOfEntries++;
  356.         }
  357.         
  358.          this .numOfPairs++;
  359.         
  360.          // make sure the load factor is less than or equal to the user-defined one
  361.          // and make sure the number of collisions is small enough
  362.          // (less than the length of the hash table)
  363.          // otherwise, increment the size of the current table
  364.          if ( this .numOfEntries >=  this .table.length *  this .loadFactor
  365.                 ||  this .numOfCollision >  this .table.length) {
  366.              this .resize();
  367.         }
  368.         
  369.          return   null ;
  370.     }
  371.      /* (non-Javadoc)
  372.      * @see java.util.Map#remove(java.lang.Object)
  373.      */
  374.      @Override
  375.      public  V remove(Object arg0) {
  376.          // TODO Auto-generated method stub
  377.          int  hash = (arg0 ==  null ) ?  0  : hash(((K)arg0).hashCode());
  378.          int  index =  this .indexFor(hash,  this .table.length);
  379.         Entry<K,V> prev =  this .table[index];
  380.         Entry<K,V> e = prev;
  381.         
  382.          if (e !=  null ) {
  383.             countChains++;   // increment the counter of totalChainLength
  384.         }
  385.         
  386.          while (e !=  null ) {
  387.              if (e.hash == hash && (e.getKey() == (K)arg0
  388.                     || (arg0 !=  null  && ((K)arg0).equals(e.getKey())))) {
  389.                  this .numOfPairs--;
  390.                 
  391.                  // if the entry which needs to be deleted is in the array
  392.                  if (prev == e) {
  393.                      if (e.getNext() !=  null ) {
  394.                         table[index] = e.getNext();
  395.                     }  else  {
  396.                         table[index] =  this .DELETED_ENTRY;
  397.                          this .numOfEntries--;
  398.                          this .numOfDeletedEntries++;
  399.                     }
  400.                 }  else  {
  401.                      // the entry which needs to be deleted is in the chain
  402.                     prev.setNext(e.getNext());
  403.                 }
  404.                  return  e.getValue();
  405.             }
  406.              this .totalChainLength++;
  407.             
  408.              // go to next entry
  409.             prev = e;
  410.             e = e.getNext();
  411.         }
  412.          return   null ;
  413.     }
  414.      /* (non-Javadoc)
  415.      * @see java.util.Map#size()
  416.      */
  417.      @Override
  418.      public   int  size() {
  419.          // TODO Auto-generated method stub
  420.          return   this .numOfEntries;
  421.     }
  422.      /* (non-Javadoc)
  423.      * @see java.lang.Object#toString()
  424.      */
  425.      @Override
  426.      public  String toString() {
  427.          // TODO Auto-generated method stub
  428.         StringBuilder sb =  new  StringBuilder();
  429.          //sb.append("no_entries: " + this.numOfEntries + "/n");
  430.          //sb.append("no_length: " + this.table.length + "/n");
  431.          //sb.append("no_pairs: " + this.numOfPairs + "/n");
  432.         sb.append( "no_collisions: "  +  this .getNumOfCollision() +  "/n" );
  433.         sb.append( "average_chain_length: "  +  this .getAvgChainLength() +  "/n" );
  434.         sb.append( "max_chain_length: "  +  this .getMaxChainLength() +  "/n" );
  435.         sb.append( "load_factor: "  +  this .getCurrentLoadFactor() +  "/n" );
  436.          return  sb.toString();
  437.     }
  438.      /**
  439.      * @return the current load factor
  440.      */
  441.      public   double  getCurrentLoadFactor() {
  442.          return  ( double ) this .numOfEntries / ( double ) this .table.length;
  443.     }
  444.      /**
  445.      * @return the numOfCollision
  446.      */
  447.      public   int  getNumOfCollision() {
  448.          return   this .numOfCollision;
  449.     }
  450.      /**
  451.      * @return the avgChainLength
  452.      */
  453.      public   int  getAvgChainLength() {
  454.          this .setAvgChainLength();
  455.          return   this .avgChainLength;
  456.     }
  457.      /**
  458.      * @return the maxChainLength
  459.      */
  460.      public   int  getMaxChainLength() {
  461.         Entry[] tab =  this .table;
  462.          int  maxLength =  0 ;
  463.          for ( int  i =  0 ; i < tab.length ; i++) {
  464.              for (Entry<K,V> e = tab[i];
  465.                 e !=  null  && ! this .isDeletedEntry(e); e = e.getNext()) {
  466.                 maxLength++;
  467.             }
  468.             
  469.              if (maxLength >  this .maxChainLength) {
  470.                  this .maxChainLength = maxLength;
  471.             }
  472.             maxLength =  0 ;
  473.         }
  474.          return   this .maxChainLength;
  475.     }
  476.      /* (non-Javadoc)
  477.      * @see java.util.Map#putAll(java.util.Map)
  478.      */
  479.      @Override
  480.      public   void  putAll(Map<?  extends  K, ?  extends  V> arg0) {
  481.          // TODO Auto-generated method stub
  482.         Iterator<?> iterator = arg0.entrySet().iterator();
  483.          while (iterator.hasNext()) {
  484.             Entry<K,V> entry = (Entry<K,V>)(iterator.next());
  485.              this .put(entry.getKey(), entry.getValue());
  486.         }
  487.     }
  488.     
  489.      /* (non-Javadoc)
  490.      * @see java.util.Map#values()
  491.      */
  492.      @Override
  493.      public  Collection<V> values() {
  494.          // TODO Auto-generated method stub
  495.         Collection<V> list =  new  ArrayList<V>();
  496.          for ( int  i =  0 ; i <  this .table.length; i++) {
  497.              for (Entry<K,V> e = table[i];
  498.                 e !=  null ; e = e.getNext()) {
  499.                 list.add(e.getValue());
  500.             }
  501.         }
  502.          return  list;
  503.     }
  504.      /* (non-Javadoc)
  505.      * @see java.util.Map#keySet()
  506.      */
  507.      @Override
  508.      public  Set<K> keySet() {
  509.          // TODO Auto-generated method stub
  510.         HashSet<K> set =  new  HashSet<K>();
  511.          for ( int  i =  0 ; i <  this .table.length; i++) {
  512.              for (Entry<K,V> e = table[i];
  513.                 e !=  null ; e = e.getNext()) {
  514.                 set.add(e.getKey());
  515.             }
  516.         }
  517.          return  set;
  518.     }
  519.      /* (non-Javadoc)
  520.      * @see java.util.Map#entrySet()
  521.      */
  522.      @Override
  523.      public  Set<java.util.Map.Entry<K, V>> entrySet() {
  524.          // TODO Auto-generated method stub
  525.         HashSet<java.util.Map.Entry<K, V>> set =  new  HashSet<java.util.Map.Entry<K, V>>();
  526.          for ( int  i =  0 ; i <  this .table.length; i++) {
  527.              for (Entry<K,V> e = table[i];
  528.                 e !=  null ; e = e.getNext()) {
  529.                 set.add(e);
  530.             }
  531.         }
  532.          return  set;
  533.     }
  534.     
  535.      /**
  536.      * description: return the index for a hash code
  537.      * @param hash - the hash code
  538.      * @param length - the length of the hash table
  539.      * @return - the index for the hash code
  540.      */
  541.      private   int  indexFor( int  hash,  int  length) {
  542.          // mapping the hash code to the index by mod operation
  543.          return  hash & (length -1);
  544.     }
  545.     
  546.      /**
  547.      * description: returns the entry associated with the specified key
  548.      * @param key - the key
  549.      * @return - the entry with the specified key
  550.      */
  551.      private  Entry<K,V> getEntry(K key) {
  552.         
  553.          // get the hash code
  554.          int  hash = (key ==  null ) ?  0  : hash(key.hashCode());
  555.         
  556.          // find the corresponding entry with the specified key by the hash code
  557.          // by iterating the hash table 
  558.         Entry<K,V> entry =  this .table[ this .indexFor(hash,  this .table.length)];
  559.          if (entry !=  null  && ! this .isDeletedEntry(entry)) {
  560.             countChains++;   // increment the counter of totalChainLength
  561.         }
  562.         
  563.          for (Entry<K,V> e = entry;
  564.             e !=  null  && ! this .isDeletedEntry(e); e = e.getNext()) {
  565.              if (key !=  null  && key.equals(e.getKey())) {
  566.                  return  e;
  567.             }
  568.              this .totalChainLength++;
  569.         }
  570.          return   null ;
  571.     }
  572.     
  573.      /**
  574.      * @param avgChainLength the avgChainLength to set
  575.      */
  576.      private   void  setAvgChainLength() {
  577.          if ( this .countChains ==  0 ) {
  578.              this .avgChainLength =  0 ;
  579.         }  else  {
  580.              double  avg = ( double ) this .totalChainLength / ( double ) this .countChains;
  581.              this .avgChainLength = ( int )Math.ceil(avg);
  582.         }
  583.     }
  584.     
  585.      /**
  586.      * description: transfers all entries from current table to newTable
  587.      * @param newTable - the new table
  588.      */
  589.      private   void  transfer(Entry[] newTable) {
  590.         Entry[] src =  this .table;
  591.         
  592.          for ( int  i =  0 ; i < src.length; i++) {
  593.             Entry<K,V> e = src[i];
  594.              if (e !=  null  && ! this .isDeletedEntry(e)) {
  595.                 src[i] =  null ;
  596.             }
  597.             
  598.              while (e !=  null  && ! this .isDeletedEntry(e)) {
  599.                  // get every single entry in the old table
  600.                  // then store it to the new table with new index
  601.                  int  index =  this .indexFor(hash(e.hashCode()), newTable.length);
  602.                 Entry<K,V> next = e.getNext();
  603.                 e.setNext( null );
  604.                  if (newTable[index] !=  null ) {
  605.                      for (Entry<K,V> entry = newTable[index];
  606.                         entry !=  null ; entry = entry.getNext()) {
  607.                          if (entry.getNext() ==  null ) {
  608.                             entry.setNext(e);
  609.                              break ;
  610.                         }
  611.                     }
  612.                 }  else  {
  613.                     newTable[index] = e;
  614.                 }
  615.                 e = next;
  616.             }
  617.         }
  618.     }
  619.     
  620.      /**
  621.      * description: resize the contents of this map into a new array 
  622.      * with a larger capacity.  This method is called automatically 
  623.      * when the number of keys in this map reaches its threshold.
  624.      */
  625.      private   void  resize() {
  626.          int  index = ++ this .currentSizeTableIndex;
  627.          int  newSize =  0 ;
  628.          if (index >=  this .sizeTable.length) {
  629.             newSize = HashTable.MAXIMUM_SIZE;
  630.         }  else  {
  631.              // get the new size from the size table
  632.             newSize =  this .sizeTable[ this .currentSizeTableIndex];
  633.         }
  634.         
  635.          //System.out.println(newSize);
  636.         Entry[] newTable =  new  Entry[newSize];
  637.          this .transfer(newTable);
  638.          this .table = newTable;
  639.     }
  640.     
  641.      /**
  642.      * description: determine if the entry's deleted entry
  643.      * @param entry - the entry
  644.      * @return - true if it is deleted entry
  645.      */
  646.      private   boolean  isDeletedEntry(Entry<K,V> entry) {
  647.          return  entry ==  this .DELETED_ENTRY;
  648.     }
  649.     
  650.      /**
  651.      * description: initialize the size table using power-of-two size
  652.      */
  653.      private   void  initializeSizeTable() {
  654.          int  init =  1 ;
  655.          for ( int  i =  0 ; i < sizeTable.length; i++) {
  656.             init = init <<  1 ;
  657.             sizeTable[i] = init;
  658.         }
  659.     }
  660.     
  661.      /**
  662.      * description: make sure the hash code isn't negative
  663.      * @param hashCode - the original hash code
  664.      * @return - the legal hash code
  665.      */
  666.      private   static   int  hash( int  hashCode) {
  667.          return  hashCode &  0x7FFFFFFF ;
  668.     }
  669. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值