java集合的算法
集合算法
java的Collections類以靜態方法的形式提供了一些多態算法。
這些算法絕大多數處理List實例,也有個別能處理任意集合的實例。下面我們簡要的介紹下。
排序
sort算法對列表的元素按升序進行排序。它有兩種處理形式:
- 一種是接收一個列表,并根據其元素的自然順序進行排序。
- 第二種是接收一個列表,以及額外的一個Comparator對象,用該對象對元素進行排序。
sort方法使用優化后的歸并排序(merge sort)算法,不僅快,而且穩定:
- 快:它能保證運行的時間復雜度是O(nlog(n)),幾乎和快排(quicksort)一樣快。但是后者不是穩定排序且不能保證O(nlog(n ))的時間復雜度。
- 穩定:他不會重排相等的元素,當你對同一個列表根據不同的屬性進行二次排序時,這一點很重要。比如,某用戶對收件箱的消息先根據日期排序,然后再根據發件人排序。用戶的正常預期是給定發件人的信息仍能保持日期排序。只有第二次排序是穩定的才能保證這一點。
示例1: 將程序的參數按照字母順序排序:
import java.util.*;public class Sort {public static void main(String[] args) {List<String> list = Arrays.asList(args);Collections.sort(list);System.out.println(list);} }示例2: 下面的代碼找出所有符合要求的同字母異序詞,并以列表的形式保存詞組,然后對列表進行排序,按照詞組長度倒序輸出。這里使用Comparator參數自定義排序規則來實現這個效果。它接收兩個參數,一是詞典文件路徑,二是最小詞組大小
詞典文件:https://docs.oracle.com/javase/tutorial/collections/interfaces/examples/dictionary.txt
import java.util.*; import java.io.*;public class Anagrams {public static void main(String[] args) {int minGroupSize = Integer.parseInt(args[1]);Map<String, List<String>> m = new HashMap<>();try{Scanner s = new Scanner(new File(args[0]));while (s.hasNext()) {String word = s.next();String alpha = alphabetize(word);// 類似python字典的setdefault方法m.computeIfAbsent(alpha, k -> new ArrayList<>()).add(word);}} catch (IOException e) {System.out.println(e);System.exit(1);}// 找出詞組長度滿足要求的List<List<String>> candidates = new ArrayList<>();for(List<String> l : m.values()) {if (l.size() >= minGroupSize)candidates.add(l);}// 根據詞組長度倒序排序Collections.sort(candidates, new Comparator<List<String>>() {public int compare(List<String> o1, List<String> o2) {return o2.size() - o1.size();}});for(List<String> l : candidates) {System.out.println(l.size() + ": " + l);}}private static String alphabetize(String s) {char[] letters = s.toCharArray();Arrays.sort(letters);return new String(letters);} }輸出:
12: [apers, apres, asper, pares, parse, pears, prase, presa, rapes, reaps, spare, spear] 11: [alerts, alters, artels, estral, laster, ratels, salter, slater, staler, stelar, talers] 10: [least, setal, slate, stale, steal, stela, taels, tales, teals, tesla] 9: [estrin, inerts, insert, inters, niters, nitres, sinter, triens, trines] 9: [capers, crapes, escarp, pacers, parsec, recaps, scrape, secpar, spacer] 9: [palest, palets, pastel, petals, plates, pleats, septal, staple, tepals] 9: [anestri, antsier, nastier, ratines, retains, retinas, retsina, stainer, stearin]亂序
schuffle算法和sort相反,它隨機打亂列表。利用它可以實現洗牌,生成測試用例等。此操作有兩種形式:
- 一種是接收一個列表并使用默認等隨機源
- 另一種是調用時額外提供一個Random對象作為隨機源。
以下示例打亂程序的參數:
import java.util.*;public class Shuffle {public static void main(String[] args) {List<String> list = new ArrayList<String>();for (String a : args)list.add(a);Collections.shuffle(list, new Random());System.out.println(list);} }以上也可以簡化為:
import java.util.*;public class Shuffle {public static void main(String[] args) {List<String> list = Arrays.asList(args);Collections.shuffle(list); // //使用默認的隨機源System.out.println(list);System.out.println(Arrays.toString(args));} }注意,這里利用Arrays類的靜態工廠方法asList將數組處理為List視圖。這個方法不會拷貝數組,對List視圖的修改會寫入數組,反之亦然。List視圖不是通用的List實現,因為它沒有實現add和remove方法:數組不可調整大小。
常用數據操作
Collections類提供了5個常用的算法來處理列表對象的常用數據操作:
- reverse 反轉列表中元素的順序
- fill 用指定的值覆寫列表的每個元素,可用戶重新初始化一個列表
- copy 接收兩個參數,一個目標列表,一個源列表,將源列表的元素拷貝到目標列表并進行覆蓋。目標列表長度至少要和源列表一樣,如果目標列表更長,多余的元素不會受到影響。
- swap 交換列表中指定位置的元素
- addAll 將所有指定元素拷貝到集合中,要添加的元素可以單獨指定,也可以作為一個數組
示例:
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3,4)); Collections.reverse(list); System.out.println(list); // [4, 3, 2, 1]Collections.fill(list, 0); System.out.println(list); // [0, 0, 0, 0]Collections.copy(list, new ArrayList<>(Arrays.asList(8, 9))); System.out.println(list); // [8, 9, 0, 0]Collections.swap(list, 0, list.size() -1); System.out.println(list); // [0, 9, 0, 8]Collections.addAll(list, 10, 11); System.out.println(list); // [0, 9, 0, 8, 10, 11]查找
binarySearch二分查找算法從一個有序的列表中查找指定的元素。這個算法有兩種形式:
- 一種是接收一個列表和要搜索的元素。這種形式假定列表是有序的(按其元素的自然順序升序排序)。
- 第二種形式接收一個額外Comparator對象,并假定列表是有序的(根據指定的Comparator對象按升序排序)。注意,這里是告訴binarySearch,要查找的列表是根據指定的Comparator對象排序的,而不是讓binarySearch先對列表作排序。
可以在調用binarySearch前,先調用sort對列表進行排序。
二分查找法的返回值是int類型,如果返回值>=0,說明找到了,且返回值是元素對應的索引。
如果小于0,說明沒找到,返回值是(-(insertion_index) - 1),其中insertion_index是元素的預期插入位置的索引,采用這種形式是為了確保未找到時的返回值<0
下面演示二分查找的使用,并在查找不存在的情況下將元素插入列表中合適的位置:
List<Integer> list = new ArrayList<>(Arrays.asList(3,6,2,9,5,8,1,7)); Collections.sort(list); int pos = Collections.binarySearch(list, 4); // -4 if (pos < 0)list.add(-pos-1, 4);為了演示第二種形式,下面故意寫啰嗦一點,和上面是等價的:
List<Integer> list = new ArrayList<>(Arrays.asList(3,6,2,9,5,8,1,7));Comparator c = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1.compareTo(o2);} };Collections.sort(list, c); int pos = Collections.binarySearch(list, 4, c); if (pos < 0)list.add(-pos-1, 4);構成
frequency頻率和disjoint不相交算法:
- frequency 統計指定元素在集合中出現的次數
- disjoint 判斷兩個集合是否不包含共同的元素
極值查找
- min 查找集合中的最小元素
- max 查找集合中的最大元素
以上兩種方法都有兩種形式,一種是只接收一個集合,默認按照元素的自然排序查找。第二種是額外接收一個Comparator對象,按照指定排序查找。
總結
- 上一篇: hadoop--日志聚集功能的配置
- 下一篇: Hadoop--Yarn常用命令 与 生