根据键,寻找值
新建一个map的抽象类
public interface Map<K, V> { void add(K key, V value); boolean contains(K key); V get(K key); void set(K key, V newValue); V remove(K key); int getSize(); boolean isEmpty(); }
基于链表的map
import java.util.ArrayList; public class LinkedListMap<K extends Comparable<K>, V> implements Map<K, V>{ private class Node{ public K key; public V value; public Node next; public Node(K key, V value, Node next){ this.key = key; this.value = value; this.next = next; } public Node(K key, V value){ this(key, value, null); } public Node(K key){ this(key, null, null); } public Node(){ this(null, null, null); } @Override public String toString(){ return key.toString() + ":" + value.toString(); } } private int size; private Node dummyHead; public LinkedListMap(){ size = 0; dummyHead = new Node(); } private Node getNode(K key){ Node cur = dummyHead.next; while (cur != null){ if (key.equals(cur.key)){ return cur; } cur = cur.next; } return null; } @Override public void add(K key, V value) { Node node = getNode(key); if (node == null){ //dummyNode指向的是头节点 dummyHead.next = new Node(key, value, dummyHead.next); size++; }else{ node.value = value; } } @Override public boolean contains(K key) { return getNode(key) != null; } @Override public V get(K key) { Node node = getNode(key); return node != null ? node.value : null; } @Override public void set(K key, V newValue) { Node node = getNode(key); if (node == null){ throw new IllegalArgumentException(key + "is not exist"); } node.value = newValue; } @Override public V remove(K key) { Node prev = dummyHead; while (prev.next != null){ if (key.equals(prev.next.key)){ Node delNode = prev.next; prev.next = delNode.next; delNode.next = null; size--; return delNode.value; } prev = prev.next; } return null; } @Override public int getSize() { return size; } @Override public boolean isEmpty() { return size == 0; } public static void main(String[] args){ System.out.println("Pride and Prejudice"); ArrayList<String> words = new ArrayList<>(); if(FileOperation.readFile("pride-and-prejudice.txt", words)){ System.out.println("Total words: " + words.size()); LinkedListMap<String, Integer> map = new LinkedListMap<>(); for(String word: words) { if (map.contains(word)) map.set(word, map.get(word) + 1); else map.add(word, 1); } System.out.println("Total different words: " + map.getSize()); System.out.println("Frequency of PRIDE: " + map.get("pride")); System.out.println("Frequency of PREJUDICE: " + map.get("prejudice")); } } }
测试:
Pride and Prejudice
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11
基于二分搜索树的map
import java.util.ArrayList; public class BSTMap<K extends Comparable<K>, V> implements Map<K, V>{ private class Node{ public K key; public V value; Node left, right; public Node(K key, V value){ this.key = key; this.value = value; left = null; right = null; } } private int size; private Node root; public BSTMap(){ size = 0; root = null; } private Node getNode(Node node, K key) { if (node == null) { return null; } if (key.compareTo(node.key) < 0) { return getNode(node.left, key); } else if (key.compareTo(node.key) > 0) { return getNode(node.right, key); } else { return node; } } // 向二分搜索树中添加新的元素(key, value) @Override public void add(K key, V value) { root = add(root, key, value); } // 向以node为根的二分搜索树中插入元素(key, value),递归算法 // 返回插入新节点后二分搜索树的根 private Node add(Node node, K key, V value){ if (node == null){ node = new Node(key, value); size++; return node; } if (key.compareTo(node.key) < 0){ node.left = add(node.left, key, value); } else if (key.compareTo(node.key) > 0){ node.right = add(node.right, key, value); }else{ node.value = value; } return node; } @Override public boolean contains(K key) { return getNode(root, key) != null; } @Override public V get(K key) { Node node = getNode(root, key); return node == null ? null : node.value; } @Override public void set(K key, V newValue) { Node node = getNode(root, key); if (node == null){ throw new IllegalArgumentException(key + "is not exist"); } node.value = newValue; } // 从二分搜索树中删除键为key的节点 @Override public V remove(K key) { Node node = getNode(root, key); if (node == null){ return null; } root = remove(root, key); return node.value; } // 删除掉以node为根的二分搜索树中键为key的节点, 递归算法 // 返回删除节点后新的二分搜索树的根 private Node remove(Node node, K key){ if (node == null){ return null; } if (key.compareTo(node.key) < 0){ node.left = remove(node.left, key); return node; } else if (key.compareTo(node.key) > 0){ node.right = remove(node.right, key); return node; }else{ // 待删除节点左子树为空的情况 if (node.left == null){ Node rightNode = node.right; node.right = null; size--; return rightNode; } // 待删除节点右子树为空的情况 if (node.right == null){ Node leftNode = node.left; node.left = null; size--; return leftNode; } // 待删除节点左右子树均不为空的情况 // 找到比待删除节点大的最小节点, 即待删除节点右子树的最小节点 // 用这个节点顶替待删除节点的位置 Node successor = minimum(node.right); successor.right = removeMin(node.right); successor.left = node.left; node.left = node.right = null; return successor; } } @Override public int getSize() { return size; } @Override public boolean isEmpty() { return size == 0; } // 返回以node为根的二分搜索树的最小值所在的节点 private Node minimum(Node node){ if (node.left == null){ return node; } return minimum(node); } // 删除掉以node为根的二分搜索树中的最小节点 // 返回删除节点后新的二分搜索树的根 private Node removeMin(Node node){ if (node.left == null){ Node rightNode = node.right; node.right = null; size--; return rightNode; } node.left = removeMin(node.left); return node; } public static void main(String[] args){ System.out.println("Pride and Prejudice"); ArrayList<String> words = new ArrayList<>(); if(FileOperation.readFile("pride-and-prejudice.txt", words)){ System.out.println("Total words: " + words.size()); BSTMap<String, Integer> map = new BSTMap<>(); for(String word: words) { if (map.contains(word)) map.set(word, map.get(word) + 1); else map.add(word, 1); } System.out.println("Total different words: " + map.getSize()); System.out.println("Frequency of PRIDE: " + map.get("pride")); System.out.println("Frequency of PREJUDICE: " + map.get("prejudice")); } } }
测试结果:
Pride and Prejudice
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11
基于avl的map映射
public class AVLMap<K extends Comparable<K>, V> implements Map<K, V>{ private AVLtree<K, V> avLtree; public AVLMap(){ avLtree = new AVLtree<>(); } @Override public void add(K key, V value) { avLtree.add(key, value); } @Override public boolean contains(K key) { return avLtree.contains(key); } @Override public V get(K key) { return avLtree.get(key); } @Override public void set(K key, V newValue) { avLtree.set(key, newValue); } @Override public V remove(K key) { return avLtree.remove(key); } @Override public int getSize() { return avLtree.getSize(); } @Override public boolean isEmpty() { return avLtree.isEmpty(); } }
接下来,我们对这三个基于不同底层实现的map集合进行测试。
import java.util.ArrayList; public class TestMapMain { private static double testMap(Map<String, Integer> map, String filename){ long startTime = System.nanoTime(); System.out.println(filename); ArrayList<String> words = new ArrayList<>(); if(FileOperation.readFile(filename, words)) { System.out.println("Total words: " + words.size()); for (String word : words){ if(map.contains(word)) map.set(word, map.get(word) + 1); else map.add(word, 1); } System.out.println("Total different words: " + map.getSize()); System.out.println("Frequency of PRIDE: " + map.get("pride")); System.out.println("Frequency of PREJUDICE: " + map.get("prejudice")); } long endTime = System.nanoTime(); return (endTime - startTime) / 1000000000.0; } public static void main(String[] args) { String filename = "pride-and-prejudice.txt"; BSTMap<String, Integer> bstMap = new BSTMap<>(); double time1 = testMap(bstMap, filename); System.out.println("BST Map: " + time1 + " s"); System.out.println(); LinkedListMap<String, Integer> linkedListMap = new LinkedListMap<>(); double time2 = testMap(linkedListMap, filename); System.out.println("Linked List Map: " + time2 + " s"); System.out.println(); AVLMap<String, Integer> avlMap = new AVLMap<>(); double time3 = testMap(avlMap, filename); System.out.println("AVL Map: " + time3 + " s"); } }
测试结果:
pride-and-prejudice.txt
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11
BST Map: 0.360976488 s
pride-and-prejudice.txt
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11
Linked List Map: 15.640178667 s
pride-and-prejudice.txt
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11
AVL Map: 0.179332518 s
这充分说明了avl平衡二叉树在性能上的优势