Java写算法时常用的函数:
Stack
void push(E e):将给定元素”压入”栈中。存入的元素会在栈首。即:栈的第一个元素
E pop():将栈首元素删除并返回。
Queue
boolean offer(E e):将元素追加到队列末尾,若添加成功则返回true。
E poll():从队首删除并返回该元素。
E peek():返回队首元素,但是不删除
Deque是双端队列,有Stack和Queue的所有方法。
队首操作:
push、peek、pop
队尾操作:
add、offer、peekLast、popLast
字符串操作:
toCharArray()转换为char数组
charAt(index)取字符串中索引为index的字符
1、冒泡排序
for(int i=0;i<n;i++){
for(int j=0;j<n-1-i;j++){
if(temp[j]>temp[j+1]){
int t=temp[j];
temp[j]=temp[j+1];
temp[j+1]=t;
}
}
}
2、快速排序
public void quicksort(int[] array,int left,int right){
if(left<right){
int key = array[left];
int low = left;
int high = right;
while(low<high){
while(low<high && array[high]>=key){
high--;
}
array[low] = array[high];
while(low<high && array[low]<=key){
low++;
}
array[high] = array[low];
}
array[low] = key;
quicksort(array,left,low-1);
quicksort(array,low+1,right);
}
}
3、查找子字符串出现的第一个索引位置
类似于Java的indexof()方法的实现,如下:
static int indexOf(char[] source, char[] target) {
char first = target[0];
int max = (source.length - target.length);
for (int i = 0; i <= max; i++) {
/* Look for first character. */
if (source[i] != first) {
while (++i <= max && source[i] != first)
;
}
/* Found first character, now look at the rest of v2 */
if (i <= max) {
int j = i + 1;
int end = j + target.length - 1;
for (int k = 1; j < end && source[j] == target[k]; j++, k++)
;
if (j == end) {
/* Found whole string. */
return i;
}
}
}
return -1;
}
4、分层打印二叉树并在第一层输出换行
public void PrintFromTopToBottom(TreeNode root) {
TreeNode currentNode = root;
int first = 1;
int second = 0;
while (currentNode != null) {
if (currentNode.left != null) {
queue.add(currentNode.left);
second++;
}
if (currentNode.right != null) {
queue.add(currentNode.right);
second++;
}
first--;
System.out.print(currentNode.val + " ");
if (first == 0) {
System.out.println(" ");
first = second;
second = 0;
}
currentNode = queue.poll();
}
}
5、一致性hash
一致性hash算法可以解决容错性和扩展性的问题。
系统中增加更多的虚拟节点,可以更好的解负载均衡问题。
public class Shard<S> { // S类封装了机器节点的信息 ,如name、password、ip、port等
private TreeMap<Long, S> circle; // 将整个hash值空间组成一个虚拟的环
private List<S> shards; // 真实机器节点
private final int NODE_NUM = 100; // 每个机器节点关联的虚拟节点个数
private final HashFunction hashFunction; // 选择一个碰撞率低的hash()函数
public Shard(List<S> shards,HashFunction hashFunction) {
super();
this.shards = shards;
this.hashFunction = hashFunction;
init();
}
private void init() { // 初始化一致性hash环
circle = new TreeMap<Long, S>();
for (int i = 0; i<shards.size(); ++i) { // 每个真实机器节点都需要关联虚拟节点
final S shardInfo = shards.get(i);
add(shardInfo);
}
}
public void add(S node) {
for (int i = 0; i < NODE_NUM; i++) {
// 虚拟节点用一些特定的hash值来替代,这样形成了hash值到真实节点的映射
circle.put(hashFunction.hash(node.toString() + i), node);
}
}
public void remove(S node) {
for (int i = 0; i < NODE_NUM; i++) {
// 移除真实节点下对应的所有虚拟节点(特定的一些hash值)
circle.remove(hashFunction.hash(node.toString() + i));
}
}
public S getShardInfo(String key) {
// SortedMap<Long, S> tail = circle.tailMap(hash(key)); // 沿环的顺时针找到一个虚拟节点
// if (tail.size() == 0) {
// return circle.get(circle.firstKey());
// }
// return tail.get(tail.firstKey()); // 返回该虚拟节点对应的真实机器节点的信息
if (circle.isEmpty()) {
return null;
}
Long hash = hashFunction.hash(key);
// 如果当前hash值没有定位到虚拟节点
if (!circle.containsKey(hash)) {
SortedMap<Long, S> tailMap = circle.tailMap(hash);
hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
}
return circle.get(hash);
}
}
class Machine {
String ip;
String name;
public Machine(String ip, String name) {
this.ip = ip;
this.name = name;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test {
public static void main(String[] args) {
Machine a = new Machine("192.168.0.1", "a");
Machine b = new Machine("192.168.0.2", "b");
Machine c = new Machine("192.168.0.3", "c");
List<Machine> list = Arrays.asList(a, b, c);
Map<String, Integer> map = new HashMap<String, Integer>();
Shard<Machine> mcs = new Shard<Machine>(list, new HashFunction());
// 存储0到2000个数,看存储在各个机器上的数的数量是否大致均匀
for (int i = 0; i < 2000; i++) {
String key = i + "";
Machine m = mcs.getShardInfo(key);
if (map.get(m.getIp()) == null) {
map.put(m.getIp(), 0);
} else {
map.put(m.getIp(), (int) map.get(m.getIp()) + 1);
}
}
Iterator<Entry<String, Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Integer> entry = iterator.next();
System.out.println(entry.getKey() + "/" + entry.getValue());
}
}
}
某次运行后的结果如下:
192.168.0.2/599
192.168.0.1/698
192.168.0.3/700
6、LRU最近最少使用算法
要效率的话使用hash搜索,要实现最近最少的话就用双向链表
public class LRUCache {
private int cacheSize;
private HashMap<Object, Entry> nodes; // 缓存容器 ,为了提高查询速度需要这个结构
private int currentSize;
private Entry first; // 链表头
private Entry last; // 链表尾
static class Entry {
Entry prev;
Entry next;
Object key;
Object value;
}
public LRUCache(int i) {
currentSize = 0;
cacheSize = i;
nodes = new HashMap<Object, Entry>(i);
}
/**
* 获取缓存中对象,并把它放在最前面
*/
public Entry get(Object key) {
Entry node = nodes.get(key);
if (node != null) {
moveToHead(node);
return node;
} else {
return null;
}
}
/**
* 添加 entry到hashtable, 并把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;
}
}
7、生产者与消费者
public class ConsumerProducerByWaitNotify {
public Integer monitor = new Integer(1);
public static void main(String[] args) {
ConsumerProducerByWaitNotify instance = new ConsumerProducerByWaitNotify();
instance.bootstrap();
}
public void bootstrap(){
Godown godown = new Godown(30); // 必须操作同一个库的实例,否则不存在多线程的问题
Consumer c1 = new Consumer(20, godown);
Consumer c2 = new Consumer(20, godown);
Consumer c3 = new Consumer(30, godown);
Producer p1 = new Producer(10, godown);
Producer p2 = new Producer(10, godown);
Producer p3 = new Producer(10, godown);
Producer p4 = new Producer(10, godown);
Producer p5 = new Producer(10, godown);
Producer p6 = new Producer(10, godown);
Producer p7 = new Producer(10, godown);
c1.start();
c2.start();
c3.start();
p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
p6.start();
p7.start();
}
// 仓库
class Godown {
public static final int max_size = 100; // 最大库存量
public int curnum; // 当前库存量
Godown(int curnum) {
this.curnum = curnum;
}
// 生产指定数量的产品
public void produce(int neednum) {
synchronized (monitor) {
// 测试是否需要生产
while (neednum + curnum > max_size) {
System.out.println("要生产的产品数量" + neednum + "超过剩余库存量" + (max_size - curnum) + ",暂时不能执行生产任务!");
try {
// 当前的生产线程等待,并让出锁(注意,只有获取到锁,才有让锁的一说)
// 如果调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁),
// 因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 满足生产条件,则进行生产,这里简单的更改当前库存量
curnum += neednum;
System.out.println("已经生产了" + neednum + "个产品,现仓储量为" + curnum);
// 唤醒在此对象监视器上等待的所有线程
// 调用某个对象的notify()方法,当前线程也必须拥有这个对象的monitor,
// 因此调用notify()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。
monitor.notifyAll();
}
}
// 消费指定数量的产品
public void consume(int neednum) {
synchronized (monitor) {
// 测试是否可消费
while (curnum < neednum) {
try {
// 当前的消费线程等待,并让出锁
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 满足消费条件,则进行消费,这里简单的更改当前库存量
curnum -= neednum;
System.out.println("已经消费了" + neednum + "个产品,现仓储量为" + curnum);
// 唤醒在此对象监视器上等待的所有线程
monitor.notifyAll();
}
}
}
// 生产者
class Producer extends Thread {
private int neednum; // 生产产品的数量
private Godown godown; // 仓库
Producer(int neednum, Godown godown) {
this.neednum = neednum;
this.godown = godown;
}
@Override
public void run() {
// 生产指定数量的产品
godown.produce(neednum);
}
}
// 消费者
class Consumer extends Thread {
private int neednum; // 生产产品的数量
private Godown godown; // 仓库
Consumer(int neednum, Godown godown) {
this.neednum = neednum;
this.godown = godown;
}
@Override
public void run() {
// 消费指定数量的产品
godown.consume(neednum);
}
}
}
还可以使用阻塞队列、Semaphore等手段来实现。