标准库中的集合与映射

关于Set接口

    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接口

    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);

TreeSet和TreeMap的实现

    Java要求TreeSet和TreeMap支持基本的add、remove和contains
操作以对数最坏的情况时间完成。因此,基本实现方法就是平衡二叉查找树。一般来说,我们并不适用
AVL树,而是经常使用一些自顶向下的红黑树。

利用标注库中的TreeMap和TreeSet写一个实例

    通过改变第一个字母, 单词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);
}
}

你可能感兴趣的:(树)