diff --git a/.gitignore b/.gitignore index a1c2a23..4570fca 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +/.idea/ +/JavaCourse_HW_1_9.iml +/out/ diff --git a/src/GarriksCoolerLinkedList.java b/src/GarriksCoolerLinkedList.java new file mode 100644 index 0000000..a774bdc --- /dev/null +++ b/src/GarriksCoolerLinkedList.java @@ -0,0 +1,35 @@ +public class GarriksCoolerLinkedList extends GarriksLinkedList { + + public E getByKey(Object key) { + for (GarriksNode node : this) { + if (node.getKey().equals(key)) { + return node.getItem(); + } + } + return null; + } + + public K getKey(int index) { + return getNode(index).getKey(); + } + + public void addMap(K key, E element) { + for (GarriksNode node : this) { + if (node.getKey().equals(key)) { + node.setKey(key); + return; + } + } + add(element, key); + } + + public boolean add(E o, K key) { + GarriksNode prevNode = tail.getPrev(); + GarriksNode newNode = new GarriksNode<>(o, key, tail, prevNode); + prevNode.setNext(newNode); + tail.setPrev(newNode); + len++; + return true; + } + +} diff --git a/src/GarriksHashMap.java b/src/GarriksHashMap.java new file mode 100644 index 0000000..2aacc65 --- /dev/null +++ b/src/GarriksHashMap.java @@ -0,0 +1,159 @@ +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class GarriksHashMap implements HashMapInterface { + private final int MINIMAL_LEN_CAUSING_REPLACEMENT = 13; + private final int DEFAULT_CAPACITY = 16; + private final double DEFAULT_LOAD_FACTOR = 0.75; + private GarriksCoolerLinkedList[] array; + private int capacity; + private double loadFactor; + private int len; + + public GarriksHashMap() { + createNewHashMap(); + } + + @Override + public int size() { + return len; + } + + @Override + public boolean isEmpty() { + return len == 0; + } + + @Override + public boolean containsKey(Object key) { + int bucket = getBucketNum(key); + if (array[bucket] != null) { + for (GarriksNode node : array[bucket]) { + if (node.getKey().equals(key)) { + return true; + } + } + } + return false; + } + + + @Override + public boolean containsValue(Object value) { + for (GarriksLinkedList bucket : array) { + if (bucket != null) { + for (GarriksNode node : bucket) { + if (node.getItem().equals(value)) { + return true; + } + } + } + } + return false; + } + + @Override + public Collection values() { + List result = new ArrayList<>(); + for (GarriksLinkedList bucket : array) { + if (bucket != null) { + for (GarriksNode node : bucket) { + result.add(node.getItem()); + } + } + } + return result; + } + + @Override + public V put(K key, V value) { + checkSize(); + int bucket = getBucketNum(key); + createBucket(bucket); + array[bucket].addMap(key, value); + len++; + return value; + } + + @Override + public V get(Object key) { + int bucket = getBucketNum(key); + return array[bucket].getByKey(key); + } + + @Override + public V remove(Object key) { + checkSize(); + int bucket = getBucketNum(key); + V result = array[bucket].getByKey(key); + array[bucket].remove(result); + if (array[bucket].size() == 0) { + array[bucket] = null; + } + len--; + return result; + } + + @Override + public void clear() { + createNewHashMap(); + } + + private int getBucketNum(Object key) { + return Math.abs(key.hashCode() % capacity); + } + + private void checkSize() { + if (len > loadFactor * capacity) { + capacity *= 2; + replacementArray(); + } + if (len > MINIMAL_LEN_CAUSING_REPLACEMENT && capacity > len * loadFactor / 2) { + capacity /= 2; + replacementArray(); + } + } + + private void replacementArray() { + GarriksCoolerLinkedList[] newArray = new GarriksCoolerLinkedList[capacity]; + for (GarriksCoolerLinkedList bucket : array) { + if (bucket == null) { + continue; + } + for (GarriksNode node : bucket) { + if (newArray[getBucketNum(node.getKey())] == null) { + newArray[getBucketNum(node.getKey())] = new GarriksCoolerLinkedList<>(); + } + int bucketIndex = getBucketNum(node.getKey()); + K currKey = node.getKey(); + V currItem = node.getItem(); + newArray[bucketIndex].addMap(currKey, currItem); + } + } + array = newArray; + } + + private void createBucket(int index) { + if (array[index] == null) { + array[index] = new GarriksCoolerLinkedList<>(); + } + } + + private void createNewHashMap() { + array = new GarriksCoolerLinkedList[16]; + capacity = DEFAULT_CAPACITY; + loadFactor = DEFAULT_LOAD_FACTOR; + len = 0; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + for (GarriksLinkedList bucket : array) { + result.append(bucket).append("\n"); + } + return result.toString(); + } + +} diff --git a/src/GarriksLinkedList.java b/src/GarriksLinkedList.java new file mode 100644 index 0000000..c5bf276 --- /dev/null +++ b/src/GarriksLinkedList.java @@ -0,0 +1,168 @@ +import java.util.Iterator; + +public class GarriksLinkedList implements LinkedListInterface, Iterable> { + + + protected final GarriksNode head; + protected final GarriksNode tail; + protected int len; + + public GarriksLinkedList() { + this.head = new GarriksNode<>(null, null, null); + this.tail = new GarriksNode<>(null, null, head); + this.head.setNext(this.tail); + this.len = 0; + } + + public GarriksNode getHead() { + return head; + } + + @Override + public int size() { + return len; + } + + @Override + public boolean isEmpty() { + return len == 0; + } + + @Override + public boolean contains(Object o) { + + if (isEmpty()) { + return false; + } + + GarriksNode currNode = head.getNext(); + + if (currNode.getItem().getClass() != o.getClass()) { + return false; + } + + while (currNode.getItem() != null && !currNode.getItem().equals(o)) { + currNode = currNode.getNext(); + } + return currNode.getItem() != null && currNode.getItem().equals(o); + } + + @Override + public boolean add(E o) { + GarriksNode prevNode = tail.getPrev(); + GarriksNode newNode = new GarriksNode<>(o, tail, prevNode); + prevNode.setNext(newNode); + tail.setPrev(newNode); + len++; + return true; + } + + @Override + public void add(int index, E element) { + GarriksNode currNode = index == 0 ? head : getNode(index - 1); + GarriksNode nextNode = currNode.getNext(); + GarriksNode newNode = new GarriksNode<>(element, nextNode, currNode); + currNode.setNext(newNode); + nextNode.setPrev(newNode); + len++; + } + + + @Override + public E get(int index) { + return getNode(index).getItem(); + } + + + @Override + public int indexOf(Object o) { + GarriksNode currNode = head; + for (int i = 0; i < len; i++) { + currNode = currNode.getNext(); + if (o.equals(currNode.getItem())) { + return i; + } + } + return -1; + } + + @Override + public E set(int index, E element) { + getNode(index).setItem(element); + return element; + } + + @Override + public E remove(int index) { + GarriksNode currItem = getNode(index); + GarriksNode prevItem = currItem.getPrev(); + GarriksNode nextItem = currItem.getNext(); + prevItem.setNext(nextItem); + nextItem.setPrev(prevItem); + len--; + return currItem.getItem(); + } + + @Override + public boolean remove(Object o) { + GarriksNode currItem = getNode(o); + if (currItem.equals(tail) || currItem.equals(head)) { + return false; + } + GarriksNode prevItem = currItem.getPrev(); + GarriksNode nextItem = currItem.getNext(); + prevItem.setNext(nextItem); + nextItem.setPrev(prevItem); + len--; + return true; + } + + @Override + public void clear() { + head.setNext(tail); + tail.setPrev(head); + len = 0; + } + + public Iterator> iterator() { + return new GarriksLinkedListIterator<>(this); + } + + protected GarriksNode getNode(int index) { + if (index >= len || index < 0) { + throw new IndexOutOfBoundsException(String.format("Attempt to get the index %d, in range 0..%d", index, len)); + } + GarriksNode currNode = head; + for (int i = 0; i < index + 1; i++) { + currNode = currNode.getNext(); + } + return currNode; + } + + protected GarriksNode getNode(Object o) { + GarriksNode currNode = head; + for (int i = 0; i < len; i++) { + if (currNode.getItem().equals(o)) { + return currNode; + } + currNode = currNode.getNext(); + } + return currNode; + } + + + + @Override + public String toString() { + GarriksNode currElem = head; + StringBuilder result = new StringBuilder("head <-> "); + for (int i = 0; i < len; i++) { + currElem = currElem.getNext(); + result.append(currElem.getItem()).append(" <-> "); + } + result.append("tail"); + + return result.toString(); + } + +} diff --git a/src/GarriksLinkedListIterator.java b/src/GarriksLinkedListIterator.java new file mode 100644 index 0000000..3dc6bc4 --- /dev/null +++ b/src/GarriksLinkedListIterator.java @@ -0,0 +1,25 @@ +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class GarriksLinkedListIterator implements Iterator> { + + private GarriksNode currElem; + + public GarriksLinkedListIterator(GarriksLinkedList arr) { + this.currElem = arr.getHead(); + } + + @Override + public boolean hasNext() { + return currElem.getNext().getItem() != null; + } + + @Override + public GarriksNode next() { + if (!this.hasNext()) { + throw new NoSuchElementException("Garriks iterator can't see more elements :)"); + } + currElem = currElem.getNext(); + return currElem; + } +} diff --git a/src/GarriksNode.java b/src/GarriksNode.java new file mode 100644 index 0000000..fe12368 --- /dev/null +++ b/src/GarriksNode.java @@ -0,0 +1,58 @@ +import java.util.Iterator; + +public class GarriksNode { + private E item; + private K key; + private GarriksNode next; + private GarriksNode prev; + + public GarriksNode(E item, GarriksNode next, GarriksNode prev) { + this.item = item; + this.next = next; + this.prev = prev; + } + + public GarriksNode(E item, K key, GarriksNode next, GarriksNode prev) { + this.item = item; + this.key = key; + this.next = next; + this.prev = prev; + } + + public GarriksNode getNext() { + return next; + } + + public void setNext(GarriksNode newNext) { + next = newNext; + } + + public E getItem() { + return item; + } + + public void setItem(E newItem) { + item = newItem; + } + + public GarriksNode getPrev() { + return prev; + } + + public void setPrev(GarriksNode prev) { + this.prev = prev; + } + + public K getKey() { + return key; + } + + public void setKey(K key) { + this.key = key; + } + + public String toString() { + return (String) item; + } + +} diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..538e692 --- /dev/null +++ b/src/README.md @@ -0,0 +1,47 @@ +| Метод LinkedList | Время работы, мс | +|----------------------|------------------| +| garriksList.add | 131 | +| linkedList.add | 126 | +| garriksList.getHead | 9 | +| linkedList.getFirst | 2 | +| garriksList.size | 10 | +| linkedList.size | 2 | +| garriksList.isEmpty | 6 | +| linkedList.isEmpty | 10 | +| garriksList.contains | 17604 | +| linkedList.contains | 10095 | +| garriksList.get | 15524 | +| linkedList.get | 7033 | +| garriksList.indexOf | 17704 | +| linkedList.indexOf | 10158 | +| garriksList.isEmpty | 6 | +| linkedList.isEmpty | 10 | +| garriksList.set | 17506 | +| linkedList.set | 7638 | +| garriksList.remove | 178 | +| linkedList.remove | 108 | +| garriksList.clear | 0 | +| linkedList.clear | 11 | +| garriksList.add | 8812 | +| linkedList.add | 6 | + + +| Метод HashMap | Время работы, мс | +|--------------------------|------------------| +| garriksMap.put | 5101 | +| hashMap.put | 8 | +| garriksMap.size | 1375 | +| hashMap.size | 10 | +| garriksMap.isEmpty | 1374 | +| hashMap.isEmpty | 11 | +| garriksMap.containsKey | 28 | +| hashMap.containsKey | 17 | +| garriksMap.containsValue | 201 | +| hashMap.containsValue | 260 | +| garriksMap.get | 2 | +| hashMap.get | 1 | +| garriksMap.remove | 4716 | +| hashMap.remove | 8 | +| garriksMap.clear | 0 | +| hashMap.clear | 0 | + diff --git a/src/RunHashMap.java b/src/RunHashMap.java new file mode 100644 index 0000000..20710b4 --- /dev/null +++ b/src/RunHashMap.java @@ -0,0 +1,110 @@ +import java.util.HashMap; +import java.util.LinkedList; + +public class RunHashMap { + private static void endTime(double start, String funcName) { + System.out.printf("%s %.0f %s", funcName, (System.currentTimeMillis() - start), "\n\n"); + } + + public static void main(String[] args) { + GarriksHashMap garriksMap = new GarriksHashMap<>(); + HashMap hashMap = new HashMap<>(); + + double start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + garriksMap.put(String.format("sus%d", i), i); + } + endTime(start, "garriksMap.put "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + hashMap.put(String.format("sus%d", i), i); + } + endTime(start, "hashMap.put "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + garriksMap.size(); + } + endTime(start, "garriksMap.size "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + hashMap.size(); + } + endTime(start, "hashMap.size "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + garriksMap.isEmpty(); + } + endTime(start, "garriksMap.isEmpty "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + hashMap.isEmpty(); + } + endTime(start, "hashMap.isEmpty "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + garriksMap.containsKey(String.format("sus%d", i)); + } + endTime(start, "garriksMap.containsKey "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + hashMap.containsKey(String.format("sus%d", i)); + } + endTime(start, "hashMap.containsKey "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + garriksMap.containsValue(i); + } + endTime(start, "garriksMap.containsValue "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + hashMap.containsValue(i); + } + endTime(start, "hashMap.containsValue "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000; i++) { + garriksMap.get(String.format("sus%d", i)); + } + endTime(start, "garriksMap.get "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000; i++) { + hashMap.get(String.format("sus%d", i)); + } + endTime(start, "hashMap.get "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + garriksMap.remove(String.format("sus%d", i)); + } + endTime(start, "garriksMap.remove "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + hashMap.remove(String.format("sus%d", i)); + } + endTime(start, "hashMap.remove "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000; i++) { + garriksMap.clear(); + } + endTime(start, "garriksMap.clear "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000; i++) { + hashMap.clear(); + } + endTime(start, "hashMap.clear "); + } +} diff --git a/src/RunLinkedList.java b/src/RunLinkedList.java new file mode 100644 index 0000000..9b5cf80 --- /dev/null +++ b/src/RunLinkedList.java @@ -0,0 +1,156 @@ +import java.util.LinkedList; + +public class RunLinkedList { + private static void endTime(double start, String funcName) { + System.out.printf("%s %.0f %s", funcName, (System.currentTimeMillis() - start), "\n\n"); + } + + public static void main(String[] args) { + GarriksLinkedList garriksList = new GarriksLinkedList<>(); + LinkedList linkedList = new LinkedList<>(); + + double start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + garriksList.add(i); + } + endTime(start, "garriksList.add "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + linkedList.add(i); + } + endTime(start, "linkedList.add "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + garriksList.getHead(); + } + endTime(start, "garriksList.getHead "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + linkedList.getFirst(); + } + endTime(start, "linkedList.getFirst "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + garriksList.size(); + } + endTime(start, "garriksList.size "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + linkedList.size(); + } + endTime(start, "linkedList.size "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + garriksList.isEmpty(); + } + endTime(start, "garriksList.isEmpty "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + linkedList.isEmpty(); + } + endTime(start, "linkedList.isEmpty "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + garriksList.contains(i); + } + endTime(start, "garriksList.contains "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + linkedList.contains(i); + } + endTime(start, "linkedList.contains "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + garriksList.get(i); + } + endTime(start, "garriksList.get "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + linkedList.get(i); + } + endTime(start, "linkedList.get "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + garriksList.indexOf(i); + } + endTime(start, "garriksList.indexOf "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + linkedList.indexOf(i); + } + endTime(start, "linkedList.indexOf "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + garriksList.set(i, i); + } + endTime(start, "garriksList.set "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + linkedList.set(i, i); + } + endTime(start, "linkedList.set "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + garriksList.remove(i); + } + endTime(start, "garriksList.remove "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + linkedList.remove(i); + } + endTime(start, "linkedList.remove "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + garriksList.clear(); + } + endTime(start, "garriksList.clear "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + linkedList.clear(); + } + endTime(start, "linkedList.clear "); + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + garriksList.add(i, i); + } + endTime(start, "garriksList.add "); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + linkedList.add(i, i); + } + endTime(start, "linkedList.add "); + } + +} +