集合的典型应用:
客户统计
词汇量统计
1、基于二分搜索树的集合
定义接口ISet
public interface ISet<E> { void add(E e); void remove(E e); boolean contains(E e); int getSize(); boolean isEmpty(); }
定义基于二分搜索树的集合
public class BinarySearchTreeSet<E extends Comparable<E>> implements ISet<E> { private BinarySearchTree<E> bst; public BinarySearchTreeSet(){ bst = new BinarySearchTree<E>(); } public void add(E e) { bst.add(e); } public void remove(E e) { bst.remove(e); } public boolean contains(E e) { return bst.contains(e); } public int getSize() { return bst.size(); } public boolean isEmpty() { return bst.isEmpty(); } }
2、 基于链表的集合
public class LinkedListSet<E> implements ISet<E> { private LinkedList<E> linkedList; public LinkedListSet(){ linkedList= new LinkedList<E>(); } public void add(E e) { if(!linkedList.contains(e)){ linkedList.addFirst(e); } } public void remove(E e) { linkedList.removeElement(e); } public boolean contains(E e) { return linkedList.contains(e); } public int getSize() { return linkedList.getSize(); } public boolean isEmpty() { return linkedList.isEmpty(); } }
3、基于二分搜索树结合和链表结合性能对比
public class TwoSetTest { private static double testSet(ISet<String> set){ long startTime = System.nanoTime(); String[] arr = {"张三", "李四","王五", "赵六","张三丰","李思明","王老五","赵明"}; for(int i = 0; i < 5000; i++){ for(String str : arr){ set.add(str +i); } } long endTme = System.nanoTime(); return (endTme - startTime) / 1000000000.0; } public static void main(String[] args) { BinarySearchTreeSet<String> set2 = new BinarySearchTreeSet<String>(); double time2 = testSet(set2); System.out.println("二分搜索树Set花费" + time2); LinkedListSet<String> set1 = new LinkedListSet<String>(); double time1 = testSet(set1); System.out.println("链表Set花费" + time1); } }
输出结果如下:
二分搜索树Set花费0.040670373 链表Set花费7.014404433
可以发现,二分搜索树的Set花费的时间明显小于基于链表的Set
两种集合的时间复杂度比较
LinkedListSet |
BinarySearchTreeSet |
|
增add | O(n) | O(h), 或者平均O(logn) 最差O(n) |
查contains | O(n) | O(h) ,或者平均O(logn) 最差O(n) |
删remove | O(n) | O(h), 或者平均O(logn) 最差O(n) |
h为数的高度。n和h的关系 h = logn , 2^h = n
BinarySearchTreeSet 最差O(n),比如
最差是O(n),我们可以使用平衡二叉树,这个后面再进行介绍。
4、leetcode集合的使用题目 804 唯一摩尔斯密码词
https://leetcode-cn.com/problems/unique-morse-code-words/
题目描述
国际摩尔斯密码定义一种标准编码方式,将每个字母对应于一个由一系列点和短线组成的字符串, 比如: "a" 对应 ".-", "b" 对应 "-...", "c" 对应 "-.-.", 等等。 为了方便,所有26个英文字母对应摩尔斯密码表如下: [".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."] 给定一个单词列表,每个单词可以写成每个字母对应摩尔斯密码的组合。例如,"cab" 可以写成 "-.-..--...",(即 "-.-." + ".-" + "-..." 字符串的结合)。我们将这样一个连接过程称作单词翻译。 返回我们可以获得所有词不同单词翻译的数量。 例如: 输入: words = ["gin", "zen", "gig", "msg"] 输出: 2 解释: 各单词翻译如下: "gin" -> "--...-." "zen" -> "--...-." "gig" -> "--...--." "msg" -> "--...--." 共有 2 种不同翻译, "--...-." 和 "--...--.".
解决方法:
public int uniqueMorseRepresentations(String[] words) { TreeSet<String> treeSet = new TreeSet<String>(); String[] codes = {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."}; for(String word : words){ StringBuilder res = new StringBuilder(); for(int i = 0; i < word.length(); i++){ res.append(codes[word.charAt(i) - 'a']); } treeSet.add(res.toString()); } return treeSet.size(); }
5、有序集合和无序集合
有序集合中的元素具有顺序性,如基于搜索树的实现
无序集合中的元素没有顺序性,基于哈希表的实现
6、多重集合
集合中的元素可以重复。