1、集合基础以及基于二分搜索树的集合实现
集合与映射(Set and Map)是高层的数据结构,什么是高层的数据结构?例如之前的 栈、队列,这些数据结构的底层实现可以是多种多样的,可以是动态数组,也可以是链表,这样的数据结构就是高层的数据结构。
目前为止:
底层的数据结构:数组、链表、二分搜索树
高层的数据结构:栈、队列、集合与映射
二分搜索树实现集合(很简单,直接使用二分搜索树的方法即可)
package com.lkj;
/**
* 使用二分搜索树实现集合
* FileOperationFileOperation注意,集合中不能包含重复的元素!
*/
public class BSTSet<E extends Comparable<E>> implements Set<E>
{
private BinarySearchTree<E> bst;
public BSTSet()
{
bst = new BinarySearchTree<E>();
}
@Override
public void add(E e)
{
//使用二分搜索树的添加方法,二分搜索树的添加方法可以实现不添加重复的元素,这符合集合的要求!
bst.add(e);
}
@Override
public boolean contains(E e)
{
return bst.contains(e);
}
@Override
public void remove(E e)
{
bst.remove(e);
}
@Override
public int getSize()
{
return bst.size();
}
@Override
public boolean isEmpty()
{
return bst.isEmpty();
}
}
2、基于链表的集合实现
代码如下:(其实也就是调用链表的方法,稍微改造一下,很简单)
public class LinkedListSet<E> implements Set<E>
{
private LinkedList<E> list;
public LinkedListSet()
{
list = new LinkedList<>();
}
@Override
public void add(E e)
{
//链表添加之前,需要先判断这个元素是否存在,不存在则进行添加(set中不能有重复的元素)
if(!list.contains(e))
list.addFirst(e);//链表的addFirst()方法的时间复杂度是 O(1)
}
@Override
public boolean contains(E e)
{
return list.contains(e);
}
@Override
public void remove(E e)
{
//删除链表中元素为e的结点。链表的remove方法是删除index位置的结点。
list.removeElement(e);
}
@Override
public int getSize()
{
return list.getSize();
}
@Override
public boolean isEmpty()
{
return list.isEmpty();
}
//我们发现链表生成结果的过程有点慢,可以看出链表的效率不高。
public static void main(String[] args)
{
System.out.println("Pride and Prejudice");
ArrayList<String> words1 = new ArrayList<>();
if(FileOperation.readFile("pride-and-prejudice.txt", words1)) {
System.out.println("Total words: " + words1.size());
LinkedListSet<String> set1 = new LinkedListSet<>();
for (String word : words1)
set1.add(word);
System.out.println("Total different words: " + set1.getSize());
}
System.out.println();
System.out.println("A Tale of Two Cities");
ArrayList<String> words2 = new ArrayList<>();
if(FileOperation.readFile("a-tale-of-two-cities.txt", words2)){
System.out.println("Total words: " + words2.size());
LinkedListSet<String> set2 = new LinkedListSet<>();
for(String word: words2)
set2.add(word);
System.out.println("Total different words: " + set2.getSize());
}
}
}
3、集合类的复杂度分析
测试 LinkedListSet 与 BSTSet 的性能差异,我们发现保存相同的单词, LinkedListSet 所耗费的时间比 BSTSet 高出一个数量级。
可以看出,二分搜索树 add() 、remove()、contains() 操作的时间复杂度都是 O(logn)级别的。