关键字:算法之高级算法

高级算法包括:动态规划,贪心算法

(1)动态规划

动态规划算法是通过整合子问题来解决整个问题的,也就是说通过子问题的求解,可以得出次问题的解。

动态规划关键是找出问题求解方程,即找到子问题和问题解的关系。


例如:跳台阶问题
题目:一个台阶总共有n 级,如果一次可以跳1 级,也可以跳2 级,求总共有多少总跳法。

这是一道组合数学的题目,只要找到求解方程即可:

f( n )= f( n-1 ) + f( n-2 ) 并且 f(1)=1,f(2)=2

方程含义是说 n个台阶的走法=最后走1级的走法+最后走两级的走法

通过这个方程,可以很轻松的求解此问题,而这个问题就是典型的动态规划问题。



(2)贪心算法

贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。

例如背包问题:与0-1背包问题类似,所不同的是在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部装入背包,1 <= i <= n。这2类问题都具有最优子结构性质,极为相似,但背包问题可以用贪心算法求解,而0-1背包问题却不能用贪心算法求解。

基本步骤:

1、算每种物品单位重量的价值Vi/Wi

2、依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包

3、若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多的装入背包

4、依此策略一直地进行下去,直到背包装满为止



(3)回溯算法

5、hash算法大全


package test.hash; 


import java.io.UnsupportedEncodingException; 

import java.security.MessageDigest; 

import java.security.NoSuchAlgorithmException; 

import java.util.zip.CRC32; 



/** 

 * Known hashing algorithms for locating a server for a key. Note that all hash 

 * algorithms return 64-bits of hash, but only the lower 32-bits are 

 * significant. This allows a positive 32-bit number to be returned for all 

 * cases. 

 */ 

/** 

 * Hash算法核心类 

 * @author zhaoshijie 

 * 

 */ 

@SuppressWarnings("unused") 

public enum HashAlgorithm {//zsj 


 /** 

 * Native hash (String.hashCode()). 

 */ 

 NATIVE_HASH, 

 /** 

 * CRC32_HASH as used by the perl API. This will be more consistent both 

 * across multiple API users as well as java versions, but is mostly likely 

 * significantly slower. 

 */ 

 CRC32_HASH, 

 /** 

 * FNV hashes are designed to be fast while maintaining a low collision 

 * rate. The FNV speed allows one to quickly hash lots of data while 

 * maintaining a reasonable collision rate. 

 * 

 * @see http://www.isthe.com/chongo/tech/comp/fnv/ 

 * @see http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash 

 */ 

 FNV1_64_HASH, 

 /** 

 * Variation of FNV. 

 */ 

 FNV1A_64_HASH, 

 /** 

 * 32-bit FNV1. 

 */ 

 FNV1_32_HASH, 

 /** 

 * 32-bit FNV1a. 

 */ 

 FNV1A_32_HASH, 

 /** 

 * MD5-based hash algorithm used by ketama. 

 */ 

 KETAMA_HASH, 


 /** 

 * mysql Hash算法 

 * From mysql source 

 */ 

 MYSQL_HASH, 


 ELF_HASH, 


 RS_HASH, 


 /** 

 * From lua source,it is used for long key 

 */ 

 LUA_HASH, 


 ELECTION_HASH, 

 /** 

 * The Jenkins One-at-a-time hash ,please see 

 * http://www.burtleburtle.net/bob/hash/doobs.html 

 */ 

 ONE_AT_A_TIME; 


 private static final long FNV_64_INIT = 0xcbf29ce484222325L; 

 private static final long FNV_64_PRIME = 0x100000001b3L; 


 private static final long FNV_32_INIT = 2166136261L; 

 private static final long FNV_32_PRIME = 16777619; 


 /** 

 * Compute the hash for the given key. 

 * 

 * @return a positive integer hash 

 */ 

 public long hash(final String k) { 

 long rv = 0; 

 switch (this) { 

 case NATIVE_HASH: 

 rv = k.hashCode(); 

 break; 

 case CRC32_HASH: 

 // return (crc32(shift) >> 16) & 0x7fff; 

 CRC32 crc32 = new CRC32(); 

 crc32.update(getBytes(k)); 

 rv = crc32.getValue() >> 16 & 0x7fff; 

 break; 

 case FNV1_64_HASH: { 

 // Thanks to pierre@demartines.com for the pointer 

 rv = FNV_64_INIT; 

 int len = k.length(); 

 for (int i = 0; i < len; i++) { 

 rv *= FNV_64_PRIME; 

 rv ^= k.charAt(i); 

 } 

 } 

 break; 

 case FNV1A_64_HASH: { 

 rv = FNV_64_INIT; 

 int len = k.length(); 

 for (int i = 0; i < len; i++) { 

 rv ^= k.charAt(i); 

 rv *= FNV_64_PRIME; 

 } 

 } 

 break; 

 case FNV1_32_HASH: { 

 rv = FNV_32_INIT; 

 int len = k.length(); 

 for (int i = 0; i < len; i++) { 

 rv *= FNV_32_PRIME; 

 rv ^= k.charAt(i); 

 } 

 } 

 break; 

 case FNV1A_32_HASH: { 

 rv = FNV_32_INIT; 

 int len = k.length(); 

 for (int i = 0; i < len; i++) { 

 rv ^= k.charAt(i); 

 rv *= FNV_32_PRIME; 

 } 

 } 

 break; 

 case ELECTION_HASH: 

 case KETAMA_HASH: 

 byte[] bKey = computeMd5(k); 

 rv = (long) (bKey[3] & 0xFF) << 24 | (long) (bKey[2] & 0xFF) << 16 

 | (long) (bKey[1] & 0xFF) << 8 | bKey[0] & 0xFF; 

 break; 


 case MYSQL_HASH: 

 int nr2 = 4; 

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

 rv ^= ((rv & 63) + nr2) * k.charAt(i) + (rv << 8); 

 nr2 += 3; 

 } 

 break; 

 case ELF_HASH: 

 long x = 0; 

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

 rv = (rv << 4) + k.charAt(i); 

 if ((x = rv & 0xF0000000L) != 0) { 

 rv ^= x >> 24; 

 rv &= ~x; 

 } 

 } 

 rv = rv & 0x7FFFFFFF; 

 break; 

 case RS_HASH: 

 long b = 378551; 

 long a = 63689; 

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

 rv = rv * a + k.charAt(i); 

 a *= b; 

 } 

 rv = rv & 0x7FFFFFFF; 

 break; 

 case LUA_HASH: 

 int step = (k.length() >> 5) + 1; 

 rv = k.length(); 

 for (int len = k.length(); len >= step; len -= step) { 

 rv = rv ^ (rv << 5) + (rv >> 2) + k.charAt(len - 1); 

 } 

 case ONE_AT_A_TIME: 

 try { 

 int hash = 0; 

 for (byte bt : k.getBytes("utf-8")) { 

 hash += (bt & 0xFF); 

 hash += (hash << 10); 

 hash ^= (hash >>> 6); 

 } 

 hash += (hash << 3); 

 hash ^= (hash >>> 11); 

 hash += (hash << 15); 

 return hash; 

 } catch (UnsupportedEncodingException e) { 

 throw new IllegalStateException("Hash function error", e); 

 } 

 default: 

 assert false; 

 } 


 return rv & 0xffffffffL; /* Truncate to 32-bits */ 

 } 


 private static ThreadLocal<MessageDigest> md5Local = new ThreadLocal<MessageDigest>(); 


 /** 

 * Get the md5 of the given key. 

 */ 

 public static byte[] computeMd5(String k) { 

 MessageDigest md5 = md5Local.get(); 

 if (md5 == null) { 

 try { 

 md5 = MessageDigest.getInstance("MD5"); 

 md5Local.set(md5); 

 } catch (NoSuchAlgorithmException e) { 

 throw new RuntimeException("MD5 not supported", e); 

 } 

 } 

 md5.reset(); 

 md5.update(getBytes(k)); 

 return md5.digest(); 

 } 


 private static final byte[] getBytes(String k) { 

 if (k == null || k.length() == 0) { 

 throw new IllegalArgumentException("Key must not be blank"); 

 } 

 try { 

 return k.getBytes("utf-8"); 

 } catch (UnsupportedEncodingException e) { 

 throw new RuntimeException(e); 

 } 

 } 


 /** 

 * 测试算法性能 

 * @param alg:指定算法 

 */ 

 public static void test(HashAlgorithm alg){ 

 long h=0; 

 long start=System.currentTimeMillis(); 

 for(int i=0;i<100000;i++)//计算10万次 

 h=alg.hash("MYSQL_HASH"); 

 System.out.println(System.currentTimeMillis()-start+"毫秒"); 

 } 


 public static void main(String[] args) { 


 test(HashAlgorithm.CRC32_HASH); 


 //此乃传说中的 一致性hash 

// test(HashAlgorithm.KETAMA_HASH); 

 } 

} 



package test.hash; 


/** 

 * 各种Hash算法工具类 

 * @author zhaoshijie 

 * 

 */ 

public class HashCodeUtils { 


 private HashAlgorithm hashAlgorighm; 


 /** 

 * 默认使用的算法 

 */ 

 public HashCodeUtils() { 

 this.hashAlgorighm = HashAlgorithm.CRC32_HASH; 

 } 

 /** 

 * 使用指定的算法 

 * @param hashAlgorighm 

 */ 

 public HashCodeUtils(HashAlgorithm hashAlgorighm) { 

 this.hashAlgorighm = hashAlgorighm; 

 } 


 /** 

 * 设置算法 

 * @param hashAlgorighm 

 */ 

 public final void setHashAlgorighm(HashAlgorithm hashAlgorighm) { 

 this.hashAlgorighm = hashAlgorighm; 

 } 


 public long hash(final String key) { 

 return this.hashAlgorighm.hash(key); 

 } 


 /** 

 * 取模运算(针对根据取模的算法,可以帮你计算某个Key应该放到哪里) 

 * @param size:几台服务器 

 * @param key:要计算的Key 

 * @return 

 */ 

 public final long getHash(int size, final String key) { 

 long hash = this.hashAlgorighm.hash(key); 

 return hash % size; 

 } 


 /** 

 * 测试方法 

 * @param args 

 */ 

 public static void main(String[] args) { 

 //此乃传说中的 一致性hash 

 HashCodeUtils util = new HashCodeUtils(HashAlgorithm.KETAMA_HASH); 


 //计算Hash 

 long hash = util.hash("testHash dd"); 


 System.out.println(hash); 


 //取摸算法,看看此KEY应该放到10台服务器的那一台 

 long w = util.getHash(10, "testHash"); 

 System.out.println(w); 

 long w2 = util.getHash(29, "testHash"); 

 System.out.println(w2); 

 } 


}