JAVA 模拟数据结构
模拟一些数据结构/容器
请定义一个队列并实现函数 max_value
得到队列里的最大值,要求函数max_value
、push_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();
*/
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);