java代码片段

LinkedHashMap应用实现LRU

import java.util.LinkedHashMap;
import java.util.Collection;
import java.util.Map;
import java.util.ArrayList;

/**
* An LRU cache, based on <code>LinkedHashMap</code>.
*
* <p>
* This cache has a fixed maximum number of elements (<code>cacheSize</code>).
* If the cache is full and another entry is added, the LRU (least recently used) entry is dropped.
*
* <p>
* This class is thread-safe. All methods of this class are synchronized.
*
* <p>
* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>
* Multi-licensed: EPL / LGPL / GPL / AL / BSD.
*/
public class LRUCache<K,V> {

private static final float   hashTableLoadFactor = 0.75f;

private LinkedHashMap<K,V>   map;
private int                  cacheSize;

/**
* Creates a new LRU cache.
* @param cacheSize the maximum number of entries that will be kept in this cache.
*/
public LRUCache (int cacheSize) {
   this.cacheSize = cacheSize;
   int hashTableCapacity = (int)Math.ceil(cacheSize / hashTableLoadFactor) + 1;
   map = new LinkedHashMap<K,V>(hashTableCapacity, hashTableLoadFactor, true) {
      // (an anonymous inner class)
      private static final long serialVersionUID = 1;
      @Override protected boolean removeEldestEntry (Map.Entry<K,V> eldest) {
         return size() > LRUCache.this.cacheSize; }}; }

/**
* Retrieves an entry from the cache.<br>
* The retrieved entry becomes the MRU (most recently used) entry.
* @param key the key whose associated value is to be returned.
* @return    the value associated to this key, or null if no value with this key exists in the cache.
*/
public synchronized V get (K key) {
   return map.get(key); }

/**
* Adds an entry to this cache.
* The new entry becomes the MRU (most recently used) entry.
* If an entry with the specified key already exists in the cache, it is replaced by the new entry.
* If the cache is full, the LRU (least recently used) entry is removed from the cache.
* @param key    the key with which the specified value is to be associated.
* @param value  a value to be associated with the specified key.
*/
public synchronized void put (K key, V value) {
   map.put (key, value); }

/**
* Clears the cache.
*/
public synchronized void clear() {
   map.clear(); }

/**
* Returns the number of used entries in the cache.
* @return the number of entries currently in the cache.
*/
public synchronized int usedEntries() {
   return map.size(); }

/**
* Returns a <code>Collection</code> that contains a copy of all cache entries.
* @return a <code>Collection</code> with a copy of the cache content.
*/
public synchronized Collection<Map.Entry<K,V>> getAll() {
   return new ArrayList<Map.Entry<K,V>>(map.entrySet()); }

} // end class LRUCache

 

// Test routine for the LRUCache class.
public static void main (String[] args) {
   LRUCache<String,String> c = new LRUCache<String, String>(3);
   c.put ("1", "one");                           // 1
   c.put ("2", "two");                           // 2 1
   c.put ("3", "three");                         // 3 2 1
   c.put ("4", "four");                          // 4 3 2
   if (c.get("2") == null) throw new Error();    // 2 4 3
   c.put ("5", "five");                          // 5 2 4
   c.put ("4", "second four");                   // 4 5 2
   // Verify cache content.
   if (c.usedEntries() != 3)              throw new Error();
   if (!c.get("4").equals("second four")) throw new Error();
   if (!c.get("5").equals("five"))        throw new Error();
   if (!c.get("2").equals("two"))         throw new Error();
   // List cache content.
   for (Map.Entry<String, String> e : c.getAll())
      System.out.println (e.getKey() + " : " + e.getValue()); }

 

 

 双链表 + hashtable实现原理
public class LRUCache {  

      

    private int cacheSize;  

    private Hashtable nodes;//缓存容器  

    private int currentSize;  

    private Entry first;//链表头  

    private Entry last;//链表尾  

      

    public LRUCache(int i) {  

        currentSize = 0;  

        cacheSize = i;  

        nodes = new Hashtable(i);//缓存容器  

    }  

      

    /** 

     * 获取缓存中对象,并把它放在最前面 

     */  

    public Entry get(Object key) {  

        Entry node = nodes.get(key);  

        if (node != null) {  

            moveToHead(node);  

            return node;  

        } else {  

            return null;  

        }  

    }  

      

    /** 

     * 添加 entryhashtable, 并把entry  

     */  

    public void put(Object key, Object value) {  

        //先查看hashtable是否存在该entry, 如果存在,则只更新其value  

        Entry node = nodes.get(key);  

          

        if (node == null) {  

            //缓存容器是否已经超过大小.  

            if (currentSize >= cacheSize) {  

                nodes.remove(last.key);  

                removeLast();  

            } else {  

                currentSize++;  

            }             

            node = new Entry();  

        }  

        node.value = value;  

        //将最新使用的节点放到链表头,表示最新使用的.  

        moveToHead(node);  

        nodes.put(key, node);  

    }  

  

    /** 

     * entry删除注意:删除操作只有在cache满了才会被执行 

     */  

    public void remove(Object key) {  

        Entry node = nodes.get(key);  

        //在链表中删除  

        if (node != null) {  

            if (node.prev != null) {  

                node.prev.next = node.next;  

            }  

            if (node.next != null) {  

                node.next.prev = node.prev;  

            }  

            if (last == node)  

                last = node.prev;  

            if (first == node)  

                first = node.next;  

        }  

        //hashtable中删除  

        nodes.remove(key);  

    }  

  

    /** 

     * 删除链表尾部节点,即使用最后 使用的entry 

     */  

    private void removeLast() {  

        //链表尾不为空,则将链表尾指向null. 删除连表尾(删除最少使用的缓存对象)  

        if (last != null) {  

            if (last.prev != null)  

                last.prev.next = null;  

            else  

                first = null;  

            last = last.prev;  

        }  

    }  

      

    /** 

     * 移动到链表头,表示这个节点是最新使用过的 

     */  

    private void moveToHead(Entry node) {  

        if (node == first)  

            return;  

        if (node.prev != null)  

            node.prev.next = node.next;  

        if (node.next != null)  

            node.next.prev = node.prev;  

        if (last == node)  

            last = node.prev;  

        if (first != null) {  

            node.next = first;  

            first.prev = node;  

        }  

        first = node;  

        node.prev = null;  

        if (last == null)  

            last = first;  

    }  

    /* 

     * 清空缓存 

     */  

    public void clear() {  

        first = null;  

        last = null;  

        currentSize = 0;  

    }  

  

}  

  

class Entry {  

    Entry prev;//前一节点  

    Entry next;//后一节点  

    Object value;//值  

    Object key;//键  

}  

 

 

/**

* A ring buffer (circular buffer, FIFO) for bytes.

*

* <p>All methods of this class are non-blocking and not synchronized (not thread-safe).

*/

public class ByteRingBuffer {

 

private byte[]               rBuf;                         // ring buffer data

private int                  rBufSize;                     // ring buffer size

private int                  rBufPos;                      // position of first (oldest) data byte within the ring buffer

private int                  rBufUsed;                     // number of used data bytes within the ring buffer

 

/**

* Creates a ring buffer.

*/

public ByteRingBuffer (int size) {

   if (size <= 0) {

      throw new IllegalArgumentException(); }

   rBufSize = size;

   rBuf = new byte[rBufSize]; }

 

/**

* Resizes the ring buffer by preserving it's data.

*

* <p>If the new size is not enough to keep all used data in the ring buffer,

* the excess old data is discarded.

*/

public void resize (int newSize) {

   if (newSize <= 0) {

      throw new IllegalArgumentException(); }

   if (newSize < rBufUsed) {                               // if new buffer is too small to contain all data

      discard(rBufUsed - newSize); }                       // discard oldest data

   byte[] newBuf = new byte[newSize];

   int newBufUsed = read(newBuf, 0, newSize);              // transfer data to new buffer

   rBuf = newBuf;

   rBufSize = newSize;

   rBufPos = 0;

   rBufUsed = newBufUsed; }

 

/**

* Returns the size of the ring buffer.

*/

public int getSize() {

   return rBufSize; }

 

/**

* Returns the number of free bytes within the ring buffer.

*/

public int getFree() {

   return rBufSize - rBufUsed; }

 

/**

* Returns the number of used bytes within the ring buffer.

*/

public int getUsed() {

   return rBufUsed; }

 

/**

* Clears the ring buffer.

*/

public void clear() {

   rBufPos = 0;

   rBufUsed = 0; }

 

/**

* Discards the oldest <code>len</code> bytes within the ring buffer.

* This has the same effect as calling <code>read(new byte[len], 0, len)</code>.

*

* @param len

*    The number of bytes to be discarded.

*/

public void discard (int len) {

   if (len < 0) {

      throw new IllegalArgumentException(); }

   int trLen = Math.min(len, rBufUsed);

   rBufPos = clip(rBufPos + trLen);

   rBufUsed -= trLen; }

 

/**

* Writes data to the ring buffer.

*

* @return

*    The number of bytes written.

*    This is guaranteed to be <code>min(len, getFree())</code>.

*/

public int write (byte[] buf, int pos, int len) {

   if (len < 0) {

      throw new IllegalArgumentException(); }

   if (rBufUsed == 0) {

      rBufPos = 0; }                                       // (speed optimization)

   int p1 = rBufPos + rBufUsed;

   if (p1 < rBufSize) {                                    // free space in two pieces

      int trLen1 = Math.min(len, rBufSize - p1);

      append(buf, pos, trLen1);

      int trLen2 = Math.min(len - trLen1, rBufPos);

      append(buf, pos + trLen1, trLen2);

      return trLen1 + trLen2; }

    else {                                                 // free space in one piece

      int trLen = Math.min(len, rBufSize - rBufUsed);

      append(buf, pos, trLen);

      return trLen; }}

 

/**

* Writes data to the ring buffer.

*

* <p>Convenience method for: <code>write(buf, 0, buf.length)</code>

*/

public int write (byte[] buf) {

   return write(buf, 0, buf.length); }

 

private void append (byte[] buf, int pos, int len) {

   if (len == 0) {

      return; }

   if (len < 0) {

      throw new AssertionError(); }

   int p = clip(rBufPos + rBufUsed);

   System.arraycopy(buf, pos, rBuf, p, len);

   rBufUsed += len; }

 

/**

* Reads data from the ring buffer.

*

* @return

*    The number of bytes read.

*    This is guaranteed to be <code>min(len, getUsed())</code>.

*/

public int read (byte[] buf, int pos, int len) {

   if (len < 0) {

      throw new IllegalArgumentException(); }

   int trLen1 = Math.min(len, Math.min(rBufUsed, rBufSize - rBufPos));

   remove(buf, pos, trLen1);

   int trLen2 = Math.min(len - trLen1, rBufUsed);

   remove(buf, pos + trLen1, trLen2);

   return trLen1 + trLen2; }

 

/**

* Reads data from the ring buffer.

*

* <p>Convenience method for: <code>read(buf, 0, buf.length)</code>

*/

public int read (byte[] buf) {

   return read(buf, 0, buf.length); }

 

private void remove (byte[] buf, int pos, int len) {

   if (len == 0) {

      return; }

   if (len < 0) {

      throw new AssertionError(); }

   System.arraycopy(rBuf, rBufPos, buf, pos, len);

   rBufPos = clip(rBufPos + len);

   rBufUsed -= len; }

 

private int clip (int p) {

   return (p < rBufSize) ? p : (p - rBufSize); }

 

}

 

 

import java.io.IOException;

import java.io.InputStream;

import java.net.URL;

import java.nio.ByteBuffer;

import java.security.SecureClassLoader;

import java.util.Enumeration;

import java.util.Vector;

 

/**

* A class loader that combines multiple class loaders into one.<br>

* The classes loaded by this class loader are associated with this class loader,

* i.e. Class.getClassLoader() points to this class loader.

* <p>

* Author Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland, www.source-code.biz<br>

* License: LGPL, http://www.gnu.org/licenses/lgpl.html<br>

* Please contact the author if you need another license.

*/

public class JoinClassLoader extends ClassLoader {

 

private ClassLoader[] delegateClassLoaders;

 

public JoinClassLoader (ClassLoader parent, ClassLoader... delegateClassLoaders) {

   super (parent);

   this.delegateClassLoaders = delegateClassLoaders; }

 

protected Class<?> findClass (String name) throws ClassNotFoundException {

   // It would be easier to call the loadClass() methods of the delegateClassLoaders

   // here, but we have to load the class from the byte code ourselves, because we

   // need it to be associated with our class loader.

   String path = name.replace('.', '/') + ".class";

   URL url = findResource(path);

   if (url == null) {

      throw new ClassNotFoundException (name); }

   ByteBuffer byteCode;

   try {

      byteCode = loadResource(url); }

    catch (IOException e) {

      throw new ClassNotFoundException (name, e); }

   return defineClass(name, byteCode, null); }

 

private ByteBuffer loadResource (URL url) throws IOException {

   InputStream stream = null;

   try {

      stream = url.openStream();

      int initialBufferCapacity = Math.min(0x40000, stream.available() + 1);

      if (initialBufferCapacity <= 2)

         initialBufferCapacity = 0x10000;

       else

         initialBufferCapacity = Math.max(initialBufferCapacity, 0x200);

      ByteBuffer buf = ByteBuffer.allocate(initialBufferCapacity);

      while (true) {

         if (!buf.hasRemaining()) {

            ByteBuffer newBuf = ByteBuffer.allocate(2*buf.capacity());

            buf.flip();

            newBuf.put (buf);

            buf = newBuf; }

         int len = stream.read(buf.array(), buf.position(), buf.remaining());

         if (len <= 0) break;

         buf.position (buf.position()+len); }

      buf.flip();

      return buf; }

    finally {

      if (stream != null) stream.close(); }}

 

protected URL findResource (String name) {

   for (ClassLoader delegate : delegateClassLoaders) {

      URL resource = delegate.getResource(name);

      if (resource != null) return resource; }

   return null; }

 

protected Enumeration<URL> findResources (String name) throws IOException {

   Vector<URL> vector = new Vector<URL>();

   for (ClassLoader delegate : delegateClassLoaders) {

      Enumeration<URL> enumeration = delegate.getResources(name);

      while (enumeration.hasMoreElements()) {

         vector.add (enumeration.nextElement()); }}

   return vector.elements(); }

 

} // end class JoinClassLoader

 

 

How to convert a number to words (in Java)

 

// This snippet may be used freely, as long as the authorship note remains in the source code.

 

private static final String[] lowNames = {

   "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",

   "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};

 

private static final String[] tensNames = {

   "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};

 

private static final String[] bigNames = {

   "thousand", "million", "billion"};

 

/**

* Converts an integer number into words (american english).

* @author Christian d'Heureuse, Inventec Informatik AG, Switzerland, www.source-code.biz

**/

public static String convertNumberToWords (int n) {

   if (n < 0) {

      return "minus " + convertNumberToWords(-n); }

   if (n <= 999) {

      return convert999(n); }

   String s = null;

   int t = 0;

   while (n > 0) {

      if (n % 1000 != 0) {

         String s2 = convert999(n % 1000);

         if (t > 0) {

            s2 = s2 + " " + bigNames[t-1]; }

         if (s == null) {

            s = s2; }

          else {

            s = s2 + ", " + s; }}

      n /= 1000;

      t++; }

   return s; }

 

// Range 0 to 999.

private static String convert999 (int n) {

   String s1 = lowNames[n / 100] + " hundred";

   String s2 = convert99(n % 100);

   if (n <= 99) {

      return s2; }

    else if (n % 100 == 0) {

      return s1; }

    else {

      return s1 + " " + s2; }}

 

// Range 0 to 99.

private static String convert99 (int n) {

   if (n < 20) {

      return lowNames[n]; }

   String s = tensNames[n / 10 - 2];

   if (n % 10 == 0) {

      return s; }

   return s + "-" + lowNames[n % 10]; }

 

 

/**

* Parses an URL query string and returns a map with the parameter values.

* The URL query string is the part in the URL after the first '?' character up

* to an optional '#' character. It has the format "name=value&name=value&...".

* The map has the same structure as the one returned by

* javax.servlet.ServletRequest.getParameterMap().

* A parameter name may occur multiple times within the query string.

* For each parameter name, the map contains a string array with the parameter values.

* @param  s  an URL query string.

* @return    a map containing parameter names as keys and parameter values as map values.

* @author    Christian d'Heureuse, Inventec Informatik AG, Switzerland, www.source-code.biz.

*/

public static Map<String, String[]> parseUrlQueryString (String s) {

   if (s == null) return new HashMap<String, String[]>(0);

   // In map1 we use strings and ArrayLists to collect the parameter values.

   HashMap<String, Object> map1 = new HashMap<String, Object>();

   int p = 0;

   while (p < s.length()) {

      int p0 = p;

      while (p < s.length() && s.charAt(p) != '=' && s.charAt(p) != '&') p++;

      String name = urlDecode(s.substring(p0, p));

      if (p < s.length() && s.charAt(p) == '=') p++;

      p0 = p;

      while (p < s.length() && s.charAt(p) != '&') p++;

      String value = urlDecode(s.substring(p0, p));

      if (p < s.length() && s.charAt(p) == '&') p++;

      Object x = map1.get(name);

      if (x == null) {

         // The first value of each name is added directly as a string to the map.

         map1.put (name, value); }

       else if (x instanceof String) {

         // For multiple values, we use an ArrayList.

         ArrayList<String> a = new ArrayList<String>();

         a.add ((String)x);

         a.add (value);

         map1.put (name, a); }

       else {

         @SuppressWarnings("unchecked")

            ArrayList<String> a = (ArrayList<String>)x;

         a.add (value); }}

   // Copy map1 to map2. Map2 uses string arrays to store the parameter values.

   HashMap<String, String[]> map2 = new HashMap<String, String[]>(map1.size());

   for (Map.Entry<String, Object> e : map1.entrySet()) {

      String name = e.getKey();

      Object x = e.getValue();

      String[] v;

      if (x instanceof String) {

         v = new String[]{(String)x}; }

       else {

         @SuppressWarnings("unchecked")

            ArrayList<String> a = (ArrayList<String>)x;

         v = new String[a.size()];

         v = a.toArray(v); }

      map2.put (name, v); }

   return map2; }

 

private static String urlDecode (String s) {

   try {

      return URLDecoder.decode(s, "UTF-8"); }

    catch (UnsupportedEncodingException e) {

      throw new RuntimeException("Error in urlDecode.", e); }}

 

 

// Illustrates how to decode a time value and add it to todays date.

public static void main (String args[]) throws Exception {

   int t = decodeTime("12:34:56");

   Date today = getTodaysDate();

   Date d = new Date(today.getTime()+t);

   System.out.println (d); }

 

// Decodes a time value in "hh:mm:ss" format and returns it as milliseconds since midnight.

public static synchronized int decodeTime (String s) throws Exception {

   SimpleDateFormat f = new SimpleDateFormat("HH:mm:ss");

   TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");

   f.setTimeZone (utcTimeZone);

   f.setLenient (false);

   ParsePosition p = new ParsePosition(0);

   Date d = f.parse(s,p);

   if (d == null || !isRestOfStringBlank(s,p.getIndex()))

      throw new Exception("Invalid time value (hh:mm:ss): \"" + s + "\".");

   return (int)d.getTime(); }

 

// Returns todays date without the time component.

public static Date getTodaysDate() {

   return truncateDate(new Date()); }

 

// Truncates the time component from a date/time value.

// (The default time zone is used to determine the begin of the day).

public static Date truncateDate (Date d) {

   GregorianCalendar gc1 = new GregorianCalendar();

   gc1.clear();

   gc1.setTime(d);

   int year = gc1.get(Calendar.YEAR), month = gc1.get(Calendar.MONTH), day = gc1.get(Calendar.DAY_OF_MONTH);

   GregorianCalendar gc2 = new GregorianCalendar(year,month,day);

   return gc2.getTime(); }

 

// Returns true if string s is blank from position p to the end.

public static boolean isRestOfStringBlank (String s, int p) {

   while (p < s.length() && Character.isWhitespace(s.charAt(p))) p++;

   return p >= s.length(); }

 

 

 

/**

* Reallocates an array with a new size, and copies the contents

* of the old array to the new array.

* @param oldArray  the old array, to be reallocated.

* @param newSize   the new array size.

* @return          A new array with the same contents.

*/

private static Object resizeArray (Object oldArray, int newSize) {

   int oldSize = java.lang.reflect.Array.getLength(oldArray);

   Class elementType = oldArray.getClass().getComponentType();

   Object newArray = java.lang.reflect.Array.newInstance(

         elementType, newSize);

   int preserveLength = Math.min(oldSize, newSize);

   if (preserveLength > 0)

      System.arraycopy(oldArray, 0, newArray, 0, preserveLength);

   return newArray; }

 

 

// Test routine for resizeArray().

public static void main (String[] args) {

   int[] a = {1, 2, 3};

   a = (int[])resizeArray(a, 5);

   a[3] = 4;

   a[4] = 5;

   for (int i=0; i<a.length; i++)

      System.out.println(a[i]); }

 

How to resize a two-dimensional array

 

Two-dimensional arrays in Java are arrays of arrays. To resize a two-dimensional array, the resizeArray function must be applied to the outer array and to all the nested arrays.

Example:

 

  int a[][] = new int[2][3];

  //...

  a = (int[][])resizeArray(a, 20);

    // new array is [20][3]

  for (int i=0; i<a.length; i++) {

     if (a[i] == null)

        a[i] = new int[30];

      else a[i] = (int[])resizeArray(a[i], 30); }

   // new array is [20][30]

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值