Set接口不允许重复元的Collection。由接口SortedSet给出的一种
特殊类型的Set保证其中的各项处于有序的状态。因为一个Set IS-A Collection,所以用于访问继承
Collection的List的项的方法也对Set有效。
由Set所要求的一些独特的操作是一些插入/删除/以及(有效地)执行
基本查找的能力。对于Set,add方法如果执行成功则返回true,否则返回false,因为被添加的项已经存在。
保持各项已有序的状态的Set的实现是TreeSet。TreeSet类的基本操作花费对数最坏时间。
默认情况下,排序假设TreeSet中项实现Comparable接口。另一种排序
可以调用Comparator实例化TreeSet来确定。例如,我们可以创建一个忽略大小写的程序然后进行插入
操作。在下面的代码中,Set 的大小为1。
//@CaseInsensitiveCompare 忽略大小写的函数
Set s = new TreeSet(new CaseInsensitiveCompare());
s.add("Hello"); s.add("HELLO");
system.out.println("The size is:" + s.size());
Map是一个接口,代表由关键字以及它们的值组成的一些项的集合。关键字
必须是唯一的,但是若干个关键字可以映射到一些相同的值。因此,值不必是唯一的。在SortedMap接口
中,映射中的关键字保持逻辑上的有序状态。SortedMap接口的一种实现是TreeMao类。Map的基本操作
包括isEmply/clean/size等方法,而且最重要的是包含下列方法:
//判断是否存在这样的key值
boolean contains(KeyType key);
//查找对应的Key值来进行查找相应的内容值
ValueType get(keyType key);
//添加对应的对象
ValueType put(KeyType key, ValueType value);
通过一个Map迭代要比Collection复杂,因为Map不提供迭代器,而是
提供3种方法,将Map对象的视图作为Collection对象返回。由于这些视图本身就是Collection,
因此它们可以被迭代。
set keySet();
Collection values();
set> entrySet();
方法keySet和values返回简单的集合(这些关键字不包含重复元,因此
以一个Set对象形式返回)。这里的entyySet方法是作为一些项而形成的Set对象被返回(由于关键字是唯一的,
应此不存在重复项)。每一项由被嵌套的接口Map.Entry表示。对于类型Map.Entry的对象,其现有
的方法包括关键字/关键字的值//一起改变关键字的值:
keyType getKey();
valueType getValue();
valueType setValue(ValueType newValue);
Java要求TreeSet和TreeMap支持基本的add、remove和contains
操作以对数最坏的情况时间完成。因此,基本实现方法就是平衡二叉查找树。一般来说,我们并不适用
AVL树,而是经常使用一些自顶向下的红黑树。
通过改变第一个字母, 单词wine可以变成dine,fine,line,mine,
nine,oine或vine。通过改变里三个字母可以变成wind,wing,wink,wins。假设我们有一本词典,
由89000个不同长度的单词。
最直接的方法是使用Map对象,其中关键字是单词,而关键字的值
是用一字母替换得到的单词集合。
代码演示部分
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Mapping_words {
/*
* 计算一个Map对象的函数, 该对象以一些单词作为关键字而已只在一个字母处不同的一列
* 单词作为关键字的值。该函数对一个89000单词的词典运行75秒(非常慢的一个方法,暴力搜索)
*/
private static boolean oneCharOff(String word1, String word2){
if(word1.length() != word2.length()) //判断长度是否相等,如果长度不想等就返回false
return false;
int diffs = 0;
for(int i = 0; i < word1.length(); i++)
if(word1.charAt(i) != word2.charAt(i))
if(diffs++ > 1) //必须有且仅有一个字母不相同, 如果有1个以上的字母不同那么久返回false
return false;
return diffs == 1;
}
/*
* @key 首先会查找在m里面查找是否有对应key值的value集合
* @value
*/
private static void updata(Map> m, keyType key, String value){
List lst = m.get(key); //获取value集合
//如果没有就添加
if(lst == null){
lst = new ArrayList<>();
m.put(key, lst);
}
//不管有没有最后都要添加进去
lst.add(value);
}
/*
* 第一个算法:该算法的时间为75秒。采用的几乎是枚举。
*/
private static Map> computeAdjacentWords_01(List theWords){
Map> adjWords = new TreeMap<>();
String[] words = new String[theWords.size()];
theWords.toArray(words);
for(int i = 0; i < words.length; i++)
for(int j = i + 1; j < words.length; j++)
if(oneCharOff(words[i], words[j])){
updata(adjWords, words[i], words[j]);
updata(adjWords, words[j], words[i]);
}
return adjWords;
}
/**
* 首先我们知道, 一个不同长度的两个单词再怎么变换最终还是不一样, 所以使用了一个策略就是将长度不同的单词来进行划分区域
* 划分之后就减小了不必要的试探
* @param theWords 词典里面所有的单词
* 运行时间缩减到了16秒
*/
private static Map> computeAdjacentWords_02(List theWords){
Map> adjWords = new TreeMap<>();
Map> wordsByLength = new TreeMap<>(); //按长度来进行分组的
for(String w : theWords)
updata(wordsByLength, w.length(), w);
//对长度Map进行迭代
for(List groupsWords : wordsByLength.values()){
String[] words = new String[groupsWords.size()];
groupsWords.toArray(words);
for(int i = 0; i < words.length; i++)
for(int j = i + 1; j < words.length; j++)
if(oneCharOff(words[i], words[j])){
updata(adjWords, words[i], words[j]);
updata(adjWords, words[j], words[i]);
}
}
return adjWords;
}
/**
* 这是一种最优化的算法, 使用一些附加的映射!和前面一样, 首先按长度进行一个划分, 然后分别对每组进行计算。
* 这时,首先要找出像wine和nine这样的单词对, 他们除了第一个单词以外都是一样的。对于长度为4的每一个单词,
* 一种做法是删除第一个字母, 留下一个三个字母的代表。这样就形成了一个Map,其中关键字为一种代表。
* @param theWords
* @return
*/
private static Map> computeAdjacentWords_03(List theWords){
Map> adjWords = new TreeMap<>();
Map> wordsByLength = new TreeMap<>(); //按长度来进行分组的
for(String w : theWords)
updata(wordsByLength, w.length(), w);
for(Map.Entry> entry : wordsByLength.entrySet()){
//每个长度的集合
List groupsWords = entry.getValue();
int groupNum = entry.getKey();
for(int i = 0; i < groupNum; i++){
Map> repToWord = new TreeMap<>();
for(String str : groupsWords){
//每个rep为单词的代表
String rep = str.substring(0, i) + str.substring(i + 1);
updata(repToWord, rep, str);
}
for(List wordClique : repToWord.values())
if(wordClique.size() >= 2)
for(String s1 : wordClique)
for(String s2: wordClique)
if(s1 != s2)
updata(adjWords, s1, s2);
}
}
return adjWords;
}
/**
* 打印结果并且显示时间差
* @param map
*/
public static void printHighChangeables(Map> map){
long start = System.currentTimeMillis();
for(Map.Entry> entry : map.entrySet()){
List words = entry.getValue();
System.out.print(entry.getKey() + " (");
System.out.println(words.size() + "):");
for(String s : words)
System.out.print(" " + s);
System.out.println();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
public static void main(String[] args) {
String[] words = {"wine", "wife", "wipe", "wire", "dine", "fine", "line",
"mine", "nine", "pine", "vine"};
List list = new ArrayList<>();
for (String string : words) {
list.add(string);
}
Map> theMap = computeAdjacentWords_01(list);
printHighChangeables(theMap);
System.out.println('\n' + "----------------------------");
Map> theMap2 = computeAdjacentWords_02(list);
printHighChangeables(theMap2);
System.out.println('\n' + "----------------------------");
Map> theMap3 = computeAdjacentWords_03(list);
printHighChangeables(theMap3);
}
}