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、冒泡排序
1
2
3
4
5
6
7
8
9
|
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、快速排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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()方法的实现,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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、分层打印二叉树并在第一层输出换行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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算法可以解决容错性和扩展性的问题。
系统中增加更多的虚拟节点,可以更好的解负载均衡问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
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); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
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()); } } } |
某次运行后的结果如下:
1
2
3
|
192.168 . 0.2 / 599 192.168 . 0.1 / 698 192.168 . 0.3 / 700 |
6、LRU最近最少使用算法
要效率的话使用hash搜索,要实现最近最少的话就用双向链表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
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、生产者与消费者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
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等手段来实现。