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等手段来实现。