JAVA 模拟数据结构

模拟一些数据结构/容器

剑指 Offer 59 - II. 队列的最大值

难度中等

请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_valuepush_back 和 pop_front 的均摊时间复杂度都是O(1)。

若队列为空,pop_front 和 max_value 需要返回 -1

方法1 ;数组模拟

 

class MaxQueue {
   int que[]  =new int[20005];
   int sta=0,end=0;
    public MaxQueue() {
    }
    public int max_value() {
        
           int ans  =-1;
           for(int i=sta;i<end;i++)  ans=Math.max(ans,que[i]);
           return ans;
    }
    public void push_back(int value) {
              que[end++]  =value;
    }
    public int pop_front() {
        if(sta==end)  return -1;
             return que[sta++];
    }
}

/**
 * Your MaxQueue object will be instantiated and called as such:
 * MaxQueue obj = new MaxQueue();
 * int param_1 = obj.max_value();
 * obj.push_back(value);
 * int param_3 = obj.pop_front();
 */

 

 max_value() 的时间复杂度 O(n)

方法2 :链表模拟

class MaxQueue {
   class Node{
       int val;
       Node next;
       public Node (int val){
           this.val  =val;
       }
   }
    Node first,last,max;
    public MaxQueue() {
      
    }
    
    public int max_value() {
            if(first==null)  return -1;
            return max.val;
    }
    
    public void push_back(int value) {
           Node tmp   =new Node(value);
          if(first==null) {
              first  =tmp;
              max  = tmp;
              last  = tmp;
              return ;
          }
           last.next  =tmp;
           last  =tmp;
            if(tmp.val>max.val)  max  =tmp;
    }
    
    public int pop_front() {
            if(first==null) return -1;
            Node te  =first;       
            if(first.next==null){//最后一个
                last  =null;
                max=null;     
            }  
            if(first.next!=null&&first.val==max.val){//当前值为最大值,需要更新max
                Node  q  =first.next;
                max  = first.next;
                while(q!=null){
                                if(q.val>max.val){
                                        max  =q;
                                }
                                q  = q.next;
                            }
            }
            first  =first.next;
            return te.val;
    }
}

/**
 * Your MaxQueue object will be instantiated and called as such:
 * MaxQueue obj = new MaxQueue();
 * int param_1 = obj.max_value();
 * obj.push_back(value);
 * int param_3 = obj.pop_front();
 */

 

 

方法3:队列+双端队列

class MaxQueue {
  Queue<Integer>que;
  Deque<Integer>deque;
    public MaxQueue() {
           que  =new LinkedList();
           deque  =new LinkedList();
    }
    
    public int max_value() {
        if(deque.isEmpty())  return -1;
        return deque.peekFirst();
    }
    // 1 5 2 3
    // deque 5 3  5:que中5后面没有比5大的数,只要还没pop_front 5,5就是当前que中的最大值。3同理
    // que   5 2 3
    public void push_back(int value) {
           while(!deque.isEmpty()&&value>deque.peekLast()) deque.pollLast();
           deque.offerLast(value);
           que.offer(value);
    }
    
    public int pop_front() {
              if(que.isEmpty())  return -1;
              int ans  =que.peek();
              que.poll();
              if(ans==deque.peekFirst()) deque.pollFirst();
              return ans;
    }
}

/**
 * Your MaxQueue object will be instantiated and called as such:
 * MaxQueue obj = new MaxQueue();
 * int param_1 = obj.max_value();
 * obj.push_back(value);
 * int param_3 = obj.pop_front();
 */

146. LRU 缓存

难度中等
请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
  • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

 

 

//1 数组+双向链表
class LRUCache {
    class Node{
        int key,value;
        Node pre,next;
        public Node(){}
        public Node(int key,int value){
            this.key  =key;
            this.value  =value;
        }
    }
    Node map[];
    Node head,tail;
    int capacity,size;
    public LRUCache(int capacity) {
            map  = new Node[10005];
            head  =new Node();
            tail =new Node();
            head.next =  tail;
            tail.pre  =head;
            this.capacity  =capacity;
    }
    //只要访问该key(不包含逐出)就放到最前面,因此tail.pre就始终为最久未使用
    public int get(int key) {
           if(map[key]==null)  return -1;
           return add(remove(map[key])).value;//放到最前面,必须先删后添加
    } 
    public void put(int key, int value) {
            if(map[key]==null){
                map[key]  =add(new Node(key,value));
                if(++size>capacity){
                    map[remove(tail.pre).key]=null;//不仅删除节点,还要在map中删除,因为get时通过Map判断key是否存在
                }
            }
            add(remove(map[key])).value  =value;
    }
    public Node add(Node node){
        Node tmp  =head.next;
        head.next  = node;
        node.pre =head;
        tmp.pre  =node;
        node.next  =tmp;
        return node;
    }
    public Node remove(Node node){
      node.pre.next  = node.next;
      node.next.pre  =node.pre;
        return node;
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

 2 数组模拟

class LRUCache {
    int record[];
    int time[];
    int kv[];
    int l,r,size,capacity;
    public LRUCache(int capacity) {
            record  =new int[200010];
            time  =new int[10005];
            kv =new int[10006];
            Arrays.fill(kv,-1);
            l = 0;
            r  =0;
            size=0;
            this.capacity  =capacity;
    }   
    public int get(int key) {
        // 先判断这个key存不存在,不存在也不会记录
        if (kv[key] == -1) {
            return -1;
        }
            record[r]  =key;
            time[key]  =r++;
            return kv[key];
    } 
    public void put(int key, int value) {    
           record[r]  =key;
           time[key] =r++;
           if(kv[key]==-1){
               if(size<capacity) size++;//由于size>capacity就会逐出一个数据,size不能一直++
               else{
                           while(l<r&&time[record[l]]!=l)  
                            {
                                //   System.out.println(l);
                                //    System.out.println("rec: "+ record[l]+"time"+time[record[l]]);
                                l++;//第一个后面没有再被用的数据就是最久未使用的数据

                            }
                          kv[record[l++]]  =-1;
               }           
           }
           kv[key]  =value;
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

 

706. 设计哈希映射

难度简单

不使用任何内建的哈希表库设计一个哈希映射(HashMap)。

实现 MyHashMap 类:

  • MyHashMap() 用空映射初始化对象
  • void put(int key, int value) 向 HashMap 插入一个键值对 (key, value) 。如果 key 已经存在于映射中,则更新其对应的值 value 。
  • int get(int key) 返回特定的 key 所映射的 value ;如果映射中不包含 key 的映射,返回 -1 。
  • void remove(key) 如果映射中存在 key 的映射,则移除 key 和它所对应的 value 。

 

class MyHashMap {
    LinkedList table[];
    final int num  =769;
    class Node{
        int key,value;
        public Node(int key,int value){
            this.key  =key;
            this.value  =value;
        }
        public int getkey(){
            return key;
        }
         public void setvalue(int value){
            this.value  =value;
        }
          public int getvalue(){
             return  value;
        }
    
    }
    public MyHashMap() {
         table  =new LinkedList[10007];
            for(int i =0;i<num;i++){
         table[i] = new LinkedList<Node>();
     }
    }
    
    public void put(int key, int value) {
         int hash = key%num;
         LinkedList  head = table[hash];
         Iterator<Node>ite  = head.iterator();
         while(ite.hasNext()){
             Node tmp  =ite.next();
             if(tmp.key==key){
                 tmp.setvalue(value);
                 return;
             }
         }
         head.addLast(new Node(key,value));


    }
    
    public int get(int key) {
         int hash = key%num;
         LinkedList  head = table[hash];
         Iterator<Node>ite  = head.iterator();
        while(ite.hasNext()){
             Node tmp  =ite.next();
             if(tmp.key==key){
                
                 return tmp.getvalue();
             }
         }
         return -1;
    }
    
    public void remove(int key) {
         int hash = key%num;
         LinkedList  head = table[hash];
         Iterator<Node>ite  = head.iterator();
        while(ite.hasNext()){
             Node tmp  =ite.next();
             if(tmp.key==key){
                 head.remove(tmp);
                 return ;
             }
         }
         
    // }
    // public void remove(int key) {
    //     int hash  =key%num;
    //     LinkedList  head = table[hash];
    //     Iterator<Node>ite  =head.iterator();
    //     while(ite.hasNext()){
    //         Node tmp  =  ite.next();
    //         if(tmp.getkey()==key){
    //              table[hash].remove(tmp);
    //              return ;
    //         }
    //     }
    // }
    }
}

/**
 * Your MyHashMap object will be instantiated and called as such:
 * MyHashMap obj = new MyHashMap();
 * obj.put(key,value);
 * int param_2 = obj.get(key);
 * obj.remove(key);
 */

 

 

哈希冲突

https://blog.csdn.net/qq_48241564/article/details/118613312

1 、 开放定址法:我们在遇到哈希冲突时,去寻找一个新的空闲的哈希地址。

1.1 线性探测法

当我们的所需要存放值的位置被占了,我们就往后面一直加1并对m取模直到存在一个空余的地址供我们存放值,取模是为了保证找到的位置在0~m-1的有效空间之中。

公式:h(x)=(Hash(x)+i)mod (Hashtable.length);(i会逐渐递增加1)
————————————————

1.2  平方探测法(二次探测)

                 当我们的所需要存放值的位置被占了,会前后寻找而不是单独方向的寻找。

        公式:h(x)=(Hash(x) +i)mod (Hashtable.length);(i依次为+(i^2)和-(i^2))

 

2  再哈希法:同时构造多个不同的哈希函数,等发生哈希冲突时就使用第二个、第三个……等其他的哈希函数计算地址,直到不发生冲突为止。虽然不易发生聚集,但是增加了计算时间。

 

3、链地址法:将所有哈希地址相同的记录都链接在同一链表中。

公式:h(x)=xmod(Hashtable.length);

4   建立公共溢出区:将哈希表分为基本表和溢出表,将发生冲突的都存放在溢出表中。

posted on 2022-01-25 12:59  cltt  阅读(93)  评论(0编辑  收藏  举报

导航