From ede0ac9642cf7ddc323da41799f11393e2c4bfd1 Mon Sep 17 00:00:00 2001 From: zan Date: Wed, 2 Dec 2020 09:19:57 +0800 Subject: [PATCH 1/4] [add] code --- HashTable.java | 37 +++++++++++++++++++++++++++++++++++++ Main.java | 11 +++++++++++ Student.java | 17 +++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 HashTable.java create mode 100644 Main.java create mode 100644 Student.java diff --git a/HashTable.java b/HashTable.java new file mode 100644 index 0000000..7cb4dc2 --- /dev/null +++ b/HashTable.java @@ -0,0 +1,37 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Iterator; + + +public class HashTable { + // 1. int hash(int key){} + // 2. void put(Student obj){} + // 3. Student get(int key){} + private final int DEFAULT_TABLE_SIZE = 17; + private ArrayList> array = null; + + HashTable(){ + array = new ArrayList>(DEFAULT_TABLE_SIZE); // [0-16]大小的Array + for (int i = 0; i < DEFAULT_TABLE_SIZE; i++) { + array.add(null); + } + } + + + public int hash(int id){ + + } + + public void put(Student stu){ + // 1. 将id hash到[0-16]之间 + int hashValue = hash(stu.id); + // 2. 将stu放入array中hashValue对应的链表 + } + + + public Student get(int id){ + + } + + public void delete(int id){} +} \ No newline at end of file diff --git a/Main.java b/Main.java new file mode 100644 index 0000000..13940e6 --- /dev/null +++ b/Main.java @@ -0,0 +1,11 @@ +class Main { + public static void main(String[] args){ + HashTable ht = new HashTable(); + Student st1 = new Student(60, "Albert", "1996.10.01", "Male"); + + ht.put(st1); + System.out.println(ht.get(60)); + + // TODO: 写更多的测试 + } +} \ No newline at end of file diff --git a/Student.java b/Student.java new file mode 100644 index 0000000..f2d88fa --- /dev/null +++ b/Student.java @@ -0,0 +1,17 @@ +public class Student { + public int id; + public String name; + public String birthday; + public String sex; + + Student(int id, String name, String birthday, String sex){ + this.id = id; + this.name = name; + this.birthday = birthday; + this.sex = sex; + } + + public String toString(){ + return Integer.toSring(id) + " " + name + " " + birthday + " " + sex; + } +} \ No newline at end of file -- Gitee From a29e805602923f3d0b93014679d730f53b633437 Mon Sep 17 00:00:00 2001 From: zan Date: Wed, 2 Dec 2020 09:20:47 +0800 Subject: [PATCH 2/4] update README.md. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b96096..dd45c13 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ ### 进阶 -1. 结合链表和散列表,实现⼀个 O(1)的 LRU 缓存淘汰算法 +1. 结合链表和散列表,实现一个 O(1)的 LRU 缓存淘汰算法 ## 工作流程 -- Gitee From 7c75007930e9bcc5bda417237975eda7f6b199e9 Mon Sep 17 00:00:00 2001 From: zan Date: Wed, 2 Dec 2020 09:21:17 +0800 Subject: [PATCH 3/4] update README.md. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dd45c13..b087b36 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ ### 基础 -1. 实现⼀个基于链表法解决冲突问题的散列表 +1. 实现一个基于链表法解决冲突问题的散列表 ### 进阶 -1. 结合链表和散列表,实现一个 O(1)的 LRU 缓存淘汰算法 +1. 结合链表和散列表,实现一个O(1)的 LRU 缓存淘汰算法 ## 工作流程 -- Gitee From 222c73be692eac40d99d4320993c50beee1fac0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=95=E7=81=BF=E7=83=BD?= <7857427+he_canfeng@user.noreply.gitee.com> Date: Tue, 8 Dec 2020 21:43:35 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HashTable.java | 8 +- .../\345\237\272\347\241\200/HashTable.java" | 78 ++++++ .../\345\237\272\347\241\200/Main.java" | 29 ++ .../\345\237\272\347\241\200/Student.java" | 20 ++ .../LRUCache.java" | 160 +++++++++++ .../LRUacheHashTable.java" | 87 ++++++ .../\347\256\200\344\273\213.txt" | 1 + .../SingleList.java" | 257 ++++++++++++++++++ ...2\350\247\243\347\254\224\350\256\260.txt" | 10 + 9 files changed, 644 insertions(+), 6 deletions(-) create mode 100644 "\344\275\234\344\270\232/\345\237\272\347\241\200/HashTable.java" create mode 100644 "\344\275\234\344\270\232/\345\237\272\347\241\200/Main.java" create mode 100644 "\344\275\234\344\270\232/\345\237\272\347\241\200/Student.java" create mode 100644 "\344\275\234\344\270\232/\350\277\233\351\230\266/HashTable\345\212\240\345\217\214\345\220\221\351\223\276\350\241\250\345\256\236\347\216\260/LRUCache.java" create mode 100644 "\344\275\234\344\270\232/\350\277\233\351\230\266/HashTable\345\212\240\345\217\214\345\220\221\351\223\276\350\241\250\345\256\236\347\216\260/LRUacheHashTable.java" create mode 100644 "\344\275\234\344\270\232/\350\277\233\351\230\266/HashTable\345\212\240\345\217\214\345\220\221\351\223\276\350\241\250\345\256\236\347\216\260/\347\256\200\344\273\213.txt" create mode 100644 "\344\275\234\344\270\232/\350\277\233\351\230\266/\345\215\225\351\223\276\350\241\250\345\256\236\347\216\260LRU\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225/SingleList.java" create mode 100644 "\346\225\243\345\210\227\350\241\250/PPT\350\256\262\350\247\243\347\254\224\350\256\260.txt" diff --git a/HashTable.java b/HashTable.java index 7cb4dc2..c467f00 100644 --- a/HashTable.java +++ b/HashTable.java @@ -4,33 +4,29 @@ import java.util.Iterator; public class HashTable { - // 1. int hash(int key){} + // 1. int hash(int key){} // 2. void put(Student obj){} // 3. Student get(int key){} private final int DEFAULT_TABLE_SIZE = 17; private ArrayList> array = null; HashTable(){ - array = new ArrayList>(DEFAULT_TABLE_SIZE); // [0-16]大小的Array + array = new ArrayList> (DEFAULT_TABLE_SIZE); // [0-16]大小的Array for (int i = 0; i < DEFAULT_TABLE_SIZE; i++) { array.add(null); } } - public int hash(int id){ } - public void put(Student stu){ // 1. 将id hash到[0-16]之间 int hashValue = hash(stu.id); // 2. 将stu放入array中hashValue对应的链表 } - public Student get(int id){ - } public void delete(int id){} diff --git "a/\344\275\234\344\270\232/\345\237\272\347\241\200/HashTable.java" "b/\344\275\234\344\270\232/\345\237\272\347\241\200/HashTable.java" new file mode 100644 index 0000000..b0fb3f3 --- /dev/null +++ "b/\344\275\234\344\270\232/\345\237\272\347\241\200/HashTable.java" @@ -0,0 +1,78 @@ +package hashtable; + +import java.util.ArrayList; //数组列表 +import java.util.LinkedList; //链表 +import java.util.Iterator; //迭代器 + + +public class HashTable { + // 1. int hash(int key){ } + // 2. void put(Student obj){ } + // 3. Student get(int key){ } + + private final int DEFAULT_TABLE_SIZE = 17; + private ArrayList> array = null; + + HashTable(){ + array = new ArrayList>(DEFAULT_TABLE_SIZE); // [0-16]大小的Array + + for (int i = 0; i < DEFAULT_TABLE_SIZE; i++){ + array.add(new LinkedList()); + + } + } + + + public int hash(int id){ + return id % DEFAULT_TABLE_SIZE; + } + + + public void put(Student stu){ + // 1. 将id hash到[0-16]之间 + int hashValue = hash(stu.id); + + array.get(hashValue).addFirst(stu); //2.将stu放入array中hashValue对应的链表 + + } + + //获取第一个链表 + public Student getLinkedListFirst(int id){ + int hashValue = hash(id); + LinkedList students = array.get(hashValue); + return students.getFirst(); + } + +public Student get(int id){ + int hashValue=hash(id); + LinkedList students = array.get(hashValue); + + for (int i=0;i students=array.get(hashValue); + + for(int i=0;icapacity){ + myHashTableRemove(head.next.key); + removeNode(head.next); + } + } + + + + + + public void myHashTableRemove(Integer key){ + Integer hash =hash(key); + DoubleLinkedList node = MyHashTable[hash]; + DoubleLinkedList prevNode = null; + while(!node.key.equals(key)&& node.hnext != null){ + prevNode = node; + node= node.hnext; + } + if(node.key.equals(key) && prevNode == null && node.hnext == null){ + MyHashTable[hash]=null; + }else if(node.key.equals(key) && prevNode == null && node.hnext == null){ + prevNode.hnext=null; + }else if(node.key.equals(key) && prevNode == null && node.hnext == null){ + MyHashTable[hash]=node.hnext; + }else if(node.key.equals(key) && prevNode == null && node.hnext == null){ + DoubleLinkedList hnext = node.hnext; + prevNode.hnext= hnext; + } + } + + public void removeNode(DoubleLinkedList node){ + DoubleLinkedList perv = node.perv; + DoubleLinkedList next = node.next; + perv.next=next; + next.perv = perv; + } + public void addCache(Integer key,Integer value,Integer hash){ + DoubleLinkedList newNode= nodeSetKeyAndValue(key,value); + addNode(newNode); + MyHashTable[hash] = newNode; + ++size; + } + + + + public void hashConflictAdd(DoubleLinkedList node,Integer key,Integer value){ + DoubleLinkedList newNode= nodeSetKeyAndValue(key,value); + node.hnext= newNode; + ++size; + addNode(newNode); + checkCapacity(); + } + public DoubleLinkedList nodeSetKeyAndValue (Integer key,Integer value){ + DoubleLinkedList newNode = new DoubleLinkedList(); + newNode.key=key; + newNode.value=value; + return newNode; + } + + public void addNode(DoubleLinkedList node){ + tail.perv.next = node; + node.perv=tail.perv; + node.next=tail; + tail.perv= node; + + } + public Integer get(Integer key){ + Integer hash = hash(key); + DoubleLinkedList node = MyHashTable[hash]; + if(node == null){ + return -1; + } + while (!node.key.equals(key)&& node.hnext != null){ + node=node.hnext; + + } + if (node.key.equals(key)){ + removeNode (node); + addNode(node); + return node.value; + + } + return -1; + } + + + static final class DoubleLinkedList{ + Integer key; + Integer value; + DoubleLinkedList next; + + DoubleLinkedList perv; + + DoubleLinkedList hnext; + } + +} diff --git "a/\344\275\234\344\270\232/\350\277\233\351\230\266/HashTable\345\212\240\345\217\214\345\220\221\351\223\276\350\241\250\345\256\236\347\216\260/LRUacheHashTable.java" "b/\344\275\234\344\270\232/\350\277\233\351\230\266/HashTable\345\212\240\345\217\214\345\220\221\351\223\276\350\241\250\345\256\236\347\216\260/LRUacheHashTable.java" new file mode 100644 index 0000000..5662399 --- /dev/null +++ "b/\344\275\234\344\270\232/\350\277\233\351\230\266/HashTable\345\212\240\345\217\214\345\220\221\351\223\276\350\241\250\345\256\236\347\216\260/LRUacheHashTable.java" @@ -0,0 +1,87 @@ +package hashtable; + //使用散列表+链表实现一个O(1)时间复杂度的LRU缓存算法——2020.12.8.何灿烽 + //思路:Java中自带的HashTable来作为散列,然后自定一个链表来实现 +import hashtable.LRUCache.DoubleLinkedList; + +import java.util.Hashtable; + +public class LRUacheHashTable { + + private DoubleLinkedList head,tail; //定义头尾指针 + + private int size=0; //容量长度为0 + + private int defaultCapacity=32; //Hashtable默认长度 + + private int capacity = 0; //缓存长度为0 + + Hashtable hashtable = new Hashtable(defaultCapacity); + + public LRUacheHashTable(int capacity){ + this.capacity = capacity; + head =new DoubleLikedLinkedList(); + tail = new DoubleLikedLinkedList(); + head.next = tail; + tail.prev = head; +} + + public int get(int key){ + DoubleLikedLinkedList node =hashtable.get(key); + if(node!=null){ + moveNode(node); + return node.value; + } + return -1; +} + +public void addNode(DoubleLikedLinkedList node){ + tail.prev.next =node; + node.prev= tail.prev; + node.next = tail; + tail.prev= node; +} + +private void removeNode(DoubleLikedLinkedList node){ + DoubleLikedLinkedList prev =node.prev; + DoubleLikedLinkedList next =node.next; + node.prev.next = next; + node.next.prev=prev; +} + +private void moveNode(DoubleLikedLinkedList node){ + removeNode(node); + addNode(node); +} + + +public void put(int key,int value){ + DoubleLikedLinkedList node = hashtable.get(key); + if(node == null){ + DoubleLikedLinkedList newNode = new DoubleLikedLinkedList(); + newNode.key=key; + newNode.value=value; + + addNode(newNode); + hashtable.put(key,newNode); + + ++size; + if(size>capacity){ + hashtable.remove(head.next.key); + removeNode(head.next); + --size; + } + }else{ + node.value=value; + moveNode(node); + } + } + + //双向链表 + static final class DoubleLikedLinkedList{ + Integer key; + Integer value; + DoubleLikedLinkedList prev; + DoubleLikedLinkedList next; + } + +} diff --git "a/\344\275\234\344\270\232/\350\277\233\351\230\266/HashTable\345\212\240\345\217\214\345\220\221\351\223\276\350\241\250\345\256\236\347\216\260/\347\256\200\344\273\213.txt" "b/\344\275\234\344\270\232/\350\277\233\351\230\266/HashTable\345\212\240\345\217\214\345\220\221\351\223\276\350\241\250\345\256\236\347\216\260/\347\256\200\344\273\213.txt" new file mode 100644 index 0000000..1386b0f --- /dev/null +++ "b/\344\275\234\344\270\232/\350\277\233\351\230\266/HashTable\345\212\240\345\217\214\345\220\221\351\223\276\350\241\250\345\256\236\347\216\260/\347\256\200\344\273\213.txt" @@ -0,0 +1 @@ +每次get的时候如果存在此数据,那么我们就将它移动到链表的尾部,这样在淘汰时我们只需要删除链表的首地址就行了,而链表的删除操作时间复杂度也是O(1)的 \ No newline at end of file diff --git "a/\344\275\234\344\270\232/\350\277\233\351\230\266/\345\215\225\351\223\276\350\241\250\345\256\236\347\216\260LRU\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225/SingleList.java" "b/\344\275\234\344\270\232/\350\277\233\351\230\266/\345\215\225\351\223\276\350\241\250\345\256\236\347\216\260LRU\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225/SingleList.java" new file mode 100644 index 0000000..90ceb1e --- /dev/null +++ "b/\344\275\234\344\270\232/\350\277\233\351\230\266/\345\215\225\351\223\276\350\241\250\345\256\236\347\216\260LRU\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225/SingleList.java" @@ -0,0 +1,257 @@ +package hashtable; + /*结合链表和散列表,实现一个O(1)的 LRU 缓存淘汰算法——2020.12.08何灿烽*/ + +public class SingleList { + public int length = 0; + + private Node firstNode; //首节点 + private Node endNode; //尾结点 + + private Integer maxLength; //添加最大长度属性 + //添加一个构造方法 + public SingleList(int maxLength) { + this.maxLength = maxLength; + } + + public SingleList() { + this.length = 0; + } + + //创建一个链表结点 + private class Node { + private T obj; + private Node next; + + private Node() { + + } + private Node(T object) { + this.setObj(object); + this.setNext(null); + } + + private T getObj() { + return obj; + } + + private void setObj(T obj) { + this.obj = obj; + } + + private Node getNext() { + return next; + } + + private void setNext(Node node) { + this.next = node; + } + } + + //添加结点方法 + public void add(T object) { + if (object == null) { + throw new IllegalArgumentException("不能为空!"); + } + if (this.firstNode == null) { + //首节点 + this.firstNode = new Node(object); + } + if (this.length==1) { + this.endNode = new Node(object); + //第二个结点 + this.firstNode.setNext(this.endNode); + } + if (this.length > 1) { + Node node = new Node(object); //添加一个新的节点node + Node tempEndNode = node; //临时保存最后结点 + this.endNode.setNext(node); //最后的节点——>添加的node + node = this.endNode; //新添加的node与尾结点互换位置 + this.endNode = tempEndNode; //最后的节点——>临时结束节点 + } + + this.length++; + } + + //根据index位置插入结点 + public void insert(T object, int index) { + if (length < 0 || length < index) { + throw new IllegalArgumentException("index is error!"); + } + + if (length == index) { + this.add(object); + return; + } + + Node node = new Node(object); + if (index == 0) { + Node tempFirstNode = this.firstNode; + node.setNext(firstNode); + this.firstNode = node; + node = tempFirstNode; + } + else if (index == 1) { + node.setNext(this.firstNode.getNext()); + this.firstNode.setNext(node); + } + else { + Node indexNode = this.findNodeByIndex(index-1); + node.setNext(indexNode.getNext()); + indexNode.setNext(node); + } + this.length++; + } + + //根据index删除节点 + public void delete(int index) { + if (this.length < 0 || this.length <= index) { + throw new IllegalArgumentException("index is error!"); + } + if (index == 0) { + this.firstNode = this.firstNode.getNext(); + } else { + Node indexNode = this.findNodeByIndex(index-1); + if (index == length - 1) { + indexNode.setNext(null); + } else { + indexNode.setNext(indexNode.getNext().getNext()); + } + } + this.length--; + } + + //根据index查找结点 + private Node findNodeByIndex(int index) { + if (this.length < 0 || this.length <= index) { + throw new IllegalArgumentException("index is error!"); + } + + Node currentNode = this.firstNode; + + int currentIndex = 0; + + while (currentNode.getNext() != null) { + if (currentIndex == index) { + break; + } + currentNode = currentNode.getNext(); + currentIndex++; + } + return currentNode; + } + + //根据index查找结点的值 + public T find(int index) { + return (T) this.findNodeByIndex(index).getObj(); + } + + //重写toString() + + public String toString() { + if (this.length <= 0) { + return "SingleList={}"; + } + StringBuffer str = new StringBuffer(); + Node currentNode = this.firstNode; + int currentIndex = 0; + str.append("," + currentNode.getObj().toString()); + while (currentNode.next != null) { + str.append("," + currentNode.getNext().getObj().toString()); + currentNode = currentNode.getNext(); + currentIndex++; + } + return "SingleList={" + str.substring(1) + "}"; + } + + +public int singleListForLRU(T object) { + + //添加之前判断链表中是否存在元素 + int index = this.findNodeIndexByObject(object); + + //如果存在,并且位置是0,不做删除和插入操作 + if (index == 0) { + return this.length; + } + // 如果大于零,删除掉再插入 + if (index>0) { + this.delete(index); + } + //向链表头部插入元素 + this.insert(object, 0); + //删除最后多余结点 + if (maxLength!=null&&this.length > maxLength) { + this.delete(maxLength - 1); + } + return this.length; //最后返回当前链表的长度 +} + +//根据查找的元素返回结点位置 -1,表示查找的对象在链表中不存在 +public int findNodeIndexByObject(T object) { + int currentIndex = -1; + if (firstNode == null) { + return currentIndex; + } else { + Node currentNode = this.firstNode; + int tempIndex = 0; + do { + if (currentNode.getObj() == object) { + currentIndex = tempIndex; + + } + currentNode = currentNode.getNext(); + tempIndex++; + } while (currentNode != null); + + return currentIndex; + } +} + //测试类 +public static void main(String[] args){ + + SingleList singleList = new SingleList(6); + + singleList.singleListForLRU("零"); + System.out.println("当前链表长度: "+singleList.length+"; 当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("一"); + + System.out.println("当前链表长度: "+singleList.length+"; 当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("零"); + + System.out.println("当前链表长度: "+singleList.length+"; 当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("二"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("三"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("一"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("二"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("三"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("四"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("五"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("六"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("⑦"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("零"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + singleList.singleListForLRU("零"); + + System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString()); + + } +} \ No newline at end of file diff --git "a/\346\225\243\345\210\227\350\241\250/PPT\350\256\262\350\247\243\347\254\224\350\256\260.txt" "b/\346\225\243\345\210\227\350\241\250/PPT\350\256\262\350\247\243\347\254\224\350\256\260.txt" new file mode 100644 index 0000000..63b791b --- /dev/null +++ "b/\346\225\243\345\210\227\350\241\250/PPT\350\256\262\350\247\243\347\254\224\350\256\260.txt" @@ -0,0 +1,10 @@ +1.目前我们学到的,用于查找和插入最有效的数据结构是? +链表,栈,数列,树 +2.封闭散列的缺点在于有依赖关系,不能简单把65去掉。 + +3. +查找元素的复杂度是多少? +插入元素的复杂度是多少? +依赖条件:冲突的个数,散列的类型,散列当前空余位数 + +4.涉及删除操作,不要使用封闭散列 \ No newline at end of file -- Gitee