Java面试13|算法

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值