On Java 8(Java编程思想)笔记 -- 第十二章 集合

集合

简介

java.util 库提供了一套相当完整的集合类(collection classes),其中基本的类型有 List 、 Set 、 Queue 和 Map。这些类型也被称作容器类(container classes),Java集合类都可以自动地调整自己的大小。因此,与数组不同,在编程时,可以将任意数量的对象放置在集合中,而不用关心集合应该有多大。

如果一个类没有显式地声明继承自哪个类,那么它就自动继承自 Object

泛型和类型安全的集合

使用泛型,有效防止在编译期间将错误的类型的对象放置到集合中,

// collections/ApplesAndOrangesWithGenerics.java
import java.util.*;

public class ApplesAndOrangesWithGenerics {
  public static void main(String[] args) {
    ArrayList apples = new ArrayList<>(); //菱形语法
    for(int i = 0; i < 3; i++)
      apples.add(new Apple());
    // Compile-time error:
    // apples.add(new Orange());
    for(Apple apple : apples) {
      System.out.println(apple.id());
    }
  }
}
/* Output:
0
1
2
*/

有了 ArrayList 声明中的类型指定,编译器会阻止将 Orange 放入 apples ,因此,这会成为一个编译期错误而不是运行时错误

使用泛型,从 List 中获取元素不需要强制类型转换。因为 List 知道它持有什么类型,因此当调用 get() 时,它会替你执行转型。因此,使用泛型,你不仅知道编译器将检查放入集合的对象类型,而且在使用集合中的对象时也可以获得更清晰的语法。

序员发现所有类型信息都可以从左侧获得,因此,编译器没有理由强迫右侧再重复这些。虽然类型推断(type inference)只是个很小的请求,Java 语言团队仍然欣然接受并进行了改进。

注意

声明一个基类类型的list,也可以将 基类子类型添加到被指定为保存 基类 对象的集合中

基本概念

Java集合类库采用“持有对象”(holding objects)的思想,并将其分为两个不同的概念,表示为类库的基本接口:

集合(Collection) :(list 有序可重复 set 无序不可重复 Queue 按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。

映射(Map) : 一组成对的“键值对”对象,允许使用键来查找值。 ArrayList 使用数字来查找对象,因此在某种意义上讲,它是将数字和对象关联在一起。 map 允许我们使用一个对象来查找另一个对象,它也被称作关联数组(associative array),因为它将对象和其它对象关联在一起;或者称作字典(dictionary),因为可以使用一个键对象来查找值对象,就像在字典中使用单词查找定义一样。 Map 是强大的编程工具。

集合中的向上转型并非总是有效的, LinkedList 具有 List 接口中未包含的额外方法,而 TreeMap 也具有在 Map 接口中未包含的方法。如果需要使用这些方法,就不能将它们向上转型为更通用的接口。

添加元素组

Arrays.asList() 方法接受一个数组或是逗号分隔的元素列表(使用可变参数),并将其转换为 List 对象。 Collections.addAll() 方法接受一个 Collection 对象,以及一个数组或是一个逗号分隔的列表,将其中元素添加到 Collection 中。下边的示例展示了这两个方法,以及更通用的 、所有 Collection 类型都包含的addAll() 方法:

package com.example.interface_adapter.listTest;

// collections/AddingGroups.java
// Adding groups of elements to Collection objects
import java.util.*;

public class AddingGroups {
    public static void main(String[] args) {
        Collection collection = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        Integer[] moreInts = { 6, 7, 8, 9, 10 };
        collection.addAll(Arrays.asList(moreInts));
        System.out.println("one"+collection);

        // Runs significantly faster, but you can't
        // construct a Collection this way:
        //运行速度快的多,但你不能用来构造一个集合
        Collections.addAll(collection, 11, 12, 13, 14, 15);
        System.out.println("two"+collection);

        Collections.addAll(collection, moreInts);
        System.out.println("three"+collection);
        // Produces a list "backed by" an array:
        List list = Arrays.asList(16,17,18,19,20);
        System.out.println("four"+list);
        list.set(1, 99); // OK -- modify an element
        System.out.println("five"+list);

//         list.add(21); // Runtime error; the underlying
        // array cannot be resized.  基础数组不能调整大小
    }
}

输出

Connected to the target VM, address: '127.0.0.1:50910', transport: 'socket'
one[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
two[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
three[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 6, 7, 8, 9, 10]
four[16, 17, 18, 19, 20]
five[16, 99, 18, 19, 20]
Disconnected from the target VM, address: '127.0.0.1:50910', transport: 'socket'

Process finished with exit code 0

Collection 的构造器可以接受另一个 Collection,用它来将自身初始化。因此,可以使用 Arrays.asList() 来为这个构造器产生输入。但是, Collections.addAll() 运行得更快,而且很容易构建一个不包含元素的 Collection ,然后调用 Collections.addAll() ,因此这是首选方式。

Collection.addAll() 方法只能接受另一个 Collection 作为参数,因此它没有 Arrays.asList() 或 Collections.addAll() 灵活。这两个方法都使用可变参数列表。

也可以直接使用 Arrays.asList() 的输出作为一个 List ,但是这里的底层实现是数组,没法调整大小。如果尝试在这个 List 上调用 add() 或 remove(),由于这两个方法会尝试修改数组大小,所以会在运行时得到“Unsupported Operation(不支持的操作)”错误:

集合的打印

Arrays.toString() 来生成数组的可打印形式。但是打印集合无需任何帮助

// collections/PrintingCollections.java
// Collections print themselves automatically
import java.util.*;

public class PrintingCollections {
  static Collection
  fill(Collection collection) {
    collection.add("rat");
    collection.add("cat");
    collection.add("dog");
    collection.add("dog");
    return collection;
  }
  static Map fill(Map map) {
    map.put("rat", "Fuzzy");
    map.put("cat", "Rags");
    map.put("dog", "Bosco");
    map.put("dog", "Spot");
    return map;
  }
  public static void main(String[] args) {
    System.out.println(fill(new ArrayList<>()));
    System.out.println(fill(new LinkedList<>()));
    System.out.println(fill(new HashSet<>()));
    System.out.println(fill(new TreeSet<>()));
    System.out.println(fill(new LinkedHashSet<>()));
    System.out.println(fill(new HashMap<>()));
    System.out.println(fill(new TreeMap<>()));
    System.out.println(fill(new LinkedHashMap<>()));
  }
}
/* Output:
[rat, cat, dog, dog]
[rat, cat, dog, dog]
[rat, cat, dog]
[cat, dog, rat]
[rat, cat, dog]
{rat=Fuzzy, cat=Rags, dog=Spot}
{cat=Rags, dog=Spot, rat=Fuzzy}
{rat=Fuzzy, cat=Rags, dog=Spot}
*/

ArrayList 和 LinkedList 都是 List 的类型,从输出中可以看出,它们都按插入顺序保存元素。两者之间的区别不仅在于执行某些类型的操作时的性能,而且 LinkedList 包含的操作多于 ArrayList 。本章后面将对这些内容进行更全面的探讨。

HashSet , TreeSet 和 LinkedHashSet 是 Set 的类型。从输出中可以看到, Set 仅保存每个相同项中的一个,并且不同的 Set 实现存储元素的方式也不同。 HashSet 使用相当复杂的方法存储元素,这在附录:集合主题中进行了探讨。现在只需要知道,这种技术是检索元素的最快方法,因此,存储顺序看上去没有什么意义(通常只关心某事物是否是 Set 的成员,而存储顺序并不重要)。如果存储顺序很重要,则可以使用 TreeSet ,它将按比较结果的升序保存对象)或 LinkedHashSet ,它按照被添加的先后顺序保存对象。

Map (也称为关联数组)使用键来查找对象,就像一个简单的数据库。所关联的对象称为值。 假设有一个 Map 将美国州名与它们的首府联系在一起,如果想要俄亥俄州(Ohio)的首府,可以用“Ohio”作为键来查找,几乎就像使用数组下标一样。正是由于这种行为,对于每个键, Map 只存储一次。

Map.put(key, value) 添加一个所想要添加的值并将它与一个键(用来查找值)相关联。 Map.get(key) 生成与该键相关联的值。上面的示例仅添加键值对,并没有执行查找。这将在稍后展示。

请注意,这里没有指定(或考虑) Map 的大小,因为它会自动调整大小。 此外, Map 还知道如何打印自己,它会显示相关联的键和值。

本例使用了 Map 的三种基本风格: HashMap , TreeMap 和 LinkedHashMap 。

键和值保存在 HashMap 中的顺序不是插入顺序,因为 HashMap 实现使用了非常快速的算法来控制顺序。 TreeMap 通过比较结果的升序来保存键, LinkedHashMap 在保持 HashMap 查找速度的同时按键的插入顺序保存键。

列表list

list类型

众所周知的
ArrayList,擅长随机访问元素,但在 List 中间插入和删除元素时速度较慢。
LinkedList(链表)插入删除操作较快,随机访问较慢 ,具有比 ArrayList 更大的特征集。

注意

与数组不同, List 可以在创建后添加或删除元素,并自行调整大小,一个可修改的序列,

Array和List都是顺序表,Array长度不可变,List长度可变:
Array是连续的存储结构,
List是不连续的存储结构,List的每个节点都有着一个Next属性,这个属性则记录着他的下一个节点的地址,每次访问都是节点顺序查找访问

CPU缓存会把一片连续的内存空间读入,因为数组结构是连续的内存地址,所以数组全部或者部分元素被连续存在CPU缓存里面,平均读取 每个元素的时间只要3个CPU时钟时间。而链表的节点分散在堆空间里面,这时候CPU缓存帮不上忙,只能是去读取内存,平均读取时间需要100个CPU时钟周期

迭代器Iterators

Java 的 Iterator

  1. 使用 iterator() 方法要求集合返回一个 Iterator。 Iterator 将准备好返回序列中的第一个元素。
  2. 使用 next() 方法获得序列中的下一个元素。
  3. 使用 hasNext() 方法检查序列中是否还有元素。
  4. 使用 remove() 方法将迭代器最近返回的那个元素删除。

for-in 和 Iterators

如果只是想向前遍历 List ,并不打算修改 List 对象本身,那么使用 for-in 语法更加简洁。

Iterator 还可以删除由 next() 生成的最后一个元素,这意味着在调用 remove() 之前必须先调用 next()

// collections/CrossCollectionIteration.java
import typeinfo.pets.*;
import java.util.*;

public class CrossCollectionIteration {
  public static void display(Iterator it) {
    while(it.hasNext()) {
      Pet p = it.next();
      System.out.print(p.id() + ":" + p + " ");
    }
    System.out.println();
  }
  public static void main(String[] args) {
    List pets = Pets.list(8);
    LinkedList petsLL = new LinkedList<>(pets);
    HashSet petsHS = new HashSet<>(pets);
    TreeSet petsTS = new TreeSet<>(pets);
    display(pets.iterator());
    display(petsLL.iterator());
    display(petsHS.iterator());
    display(petsTS.iterator());
  }
}
/* Output:
0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug
7:Manx
0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug
7:Manx
0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug
7:Manx
5:Cymric 2:Cymric 7:Manx 1:Manx 3:Mutt 6:Pug 4:Pug
0:Rat
*/

display() 方法不包含任何有关它所遍历的序列的类型信息,能够将遍历序列的操作与该序列的底层结构分离

ListIterator(双向移动)

ListIterator 是一个更强大的 Iterator 子类型,它只能由各种 List 类生成。 Iterator 只能向前移动,而 ListIterator 可以双向移动。它可以生成迭代器在列表中指向位置的后一个和前一个元素的索引,并且可以使用 set() 方法替换它访问过的最近一个元素。可以通过调用 listIterator() 方法来生成指向 List 开头处的 ListIterator ,还可以通过调用 listIterator(n) 创建一个一开始就指向列表索引号为 n 的元素处的 ListIterator

// collections/ListIteration.java
import typeinfo.pets.*;
import java.util.*;

public class ListIteration {
  public static void main(String[] args) {
    List pets = Pets.list(8);
    ListIterator it = pets.listIterator();
    while(it.hasNext())
      System.out.print(it.next() +
        ", " + it.nextIndex() +
        ", " + it.previousIndex() + "; ");
    System.out.println();
    // Backwards:
    while(it.hasPrevious())
      System.out.print(it.previous().id() + " ");
    System.out.println();
    System.out.println(pets);
    //Pets.get() 方法用来从位置 3 开始替换 List 中的所有 Pet 对象。
    it = pets.listIterator(3);
    while(it.hasNext()) {
      it.next();
      it.set(Pets.get());
    }
    System.out.println(pets);
  }
}
/* Output:
Rat, 1, 0; Manx, 2, 1; Cymric, 3, 2; Mutt, 4, 3; Pug,
5, 4; Cymric, 6, 5; Pug, 7, 6; Manx, 8, 7;
7 6 5 4 3 2 1 0
[Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug, Manx]
[Rat, Manx, Cymric, Cymric, Rat, EgyptianMau, Hamster,
EgyptianMau]
*/

堆栈Stack

概念

堆栈是“后进先出”(LIFO)集合。它有时被称为叠加栈(pushdown stack),因为最后“压入”(push)栈的元素,第一个被“弹出”(pop)栈

// onjava/Stack.java
// A Stack class built with an ArrayDeque
package onjava;
import java.util.Deque;
import java.util.ArrayDeque;

public class Stack<T> {
  private Deque storage = new ArrayDeque<>();
  public void push(T v) { storage.push(v); }
  public T peek() { return storage.peek(); }
  public T pop() { return storage.pop(); }
  public boolean isEmpty() { return storage.isEmpty(); }
  @Override
  public String toString() {
    return storage.toString();
  }
}

注意, push() 接受类型为 T 的对象,而 peek() 和 pop() 返回类型为 T 的对象。 peek() 方法将返回栈顶元素,但并不将其从栈顶删除,而 pop() 删除并返回顶部元素。

// collections/StackTest2.java
import onjava.*;

public class StackTest2 {
  public static void main(String[] args) {
    Stack stack = new Stack<>();
    for(String s : "My dog has fleas".split(" "))
      stack.push(s);
    while(!stack.isEmpty())
      System.out.print(stack.pop() + " ");
  }
}
/* Output:
fleas has dog My
*/

不同于上个代码块的Stack类,使用该新类时,要注意区分包名,不要导入成老版本的stack,任何对 Stack 的引用都将选择 onjava 版本 import onjava.Stack;

集合Set

Set 不保存重复的元素。 如果试图将相同对象的多个实例添加到 Set 中,那么它会阻止这种重复行为。 Set 最常见的用途是测试归属性,可以很轻松地询问某个对象是否在一个 Set 中。因此,查找通常是 Set 最重要的操作,因此通常会选择 HashSet 实现,该实现针对快速查找进行了优化。

Set 具有与 Collection 相同的接口,因此没有任何额外的功能,不像前面两种不同类型的 List 那样。实际上, Set 就是一个 Collection ,只是行为不同。(这是继承和多态思想的典型应用:表现不同的行为。)

TreeSet 将元素存储在红-黑树数据结构中,而 HashSet 使用散列函数。 LinkedHashSet 因为查询速度的原因也使用了散列,但是看起来使用了链表来维护元素的插入顺序

// collections/SetOfInteger.java
import java.util.*;

public class SetOfInteger {
  public static void main(String[] args) {
    Random rand = new Random(47);
    Set intset = new HashSet<>();
    for(int i = 0; i < 10000; i++)
      intset.add(rand.nextInt(30));
    System.out.println(intset);
  }
}
/* Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
*/

注意

此处输出有序,当hashSet本身输出无序,如下:

// collections/SetOfString.java
import java.util.*;

public class SetOfString {
  public static void main(String[] args) {
    Set colors = new HashSet<>();
    for(int i = 0; i < 100; i++) {
      colors.add("Yellow");
      colors.add("Blue");
      colors.add("Red");
      colors.add("Red");
      colors.add("Orange");
      colors.add("Yellow");
      colors.add("Blue");
      colors.add("Purple");
    }
    System.out.println(colors);
  }
}
/* Output:
[Red, Yellow, Blue, Purple, Orange]
*/

String 对象似乎没有排序。要对结果进行排序,一种方法是使用 TreeSet 而不是 HashSet :

// collections/SortedSetOfString.java
import java.util.*;

public class SortedSetOfString {
  public static void main(String[] args) {
    Set colors = new TreeSet<>();
    for(int i = 0; i < 100; i++) {
      colors.add("Yellow");
      colors.add("Blue");
      colors.add("Red");
      colors.add("Red");
      colors.add("Orange");
      colors.add("Yellow");
      colors.add("Blue");
      colors.add("Purple");
    }
    System.out.println(colors);
  }
}
/* Output:
[Blue, Orange, Purple, Red, Yellow]
*/

读取文件并按单词划分

// collections/UniqueWords.java
import java.util.*;
import java.nio.file.*;

public class UniqueWords {
  public static void
  main(String[] args) throws Exception {
    List lines = Files.readAllLines(
      Paths.get("SetOperations.java"));
    Set words = new TreeSet<>();
    for(String line : lines)
      for(String word : line.split("\\W+"))
        if(word.trim().length() > 0)
          words.add(word);
    System.out.println(words);
  }
}
/* Output:
[A, B, C, Collections, D, E, F, G, H, HashSet, I, J, K,
L, M, N, Output, Set, SetOperations, String, System, X,
Y, Z, add, addAll, added, args, class, collections,
contains, containsAll, false, from, import, in, java,
main, new, out, println, public, remove, removeAll,
removed, set1, set2, split, static, to, true, util,
void]
*/

我们逐步浏览文件中的每一行,并使用 String.split() 将其分解为单词,这里使用正则表达式 \ W + ,这意味着它会依据一个或多个(即 + )非单词字母来拆分字符串。每个结果单词都会添加到 Set words 中。因为它是 TreeSet ,所以对结果进行排序。这里,排序是按字典顺序(lexicographically)完成的,因此大写和小写字母位于不同的组中。如果想按字母顺序(alphabetically)对其进行排序,可以向 TreeSet 构造器传入 String.CASE_INSENSITIVE_ORDER 比较器(比较器是一个建立排序顺序的对象):

// collections/UniqueWordsAlphabetic.java
// Producing an alphabetic listing
import java.util.*;
import java.nio.file.*;

public class UniqueWordsAlphabetic {
  public static void
  main(String[] args) throws Exception {
    List lines = Files.readAllLines(
      Paths.get("SetOperations.java"));
    Set words =
      new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
    for(String line : lines)
      for(String word : line.split("\\W+"))
        if(word.trim().length() > 0)
          words.add(word);
    System.out.println(words);
  }
}
/* Output:
[A, add, addAll, added, args, B, C, class, collections,
contains, containsAll, D, E, F, false, from, G, H,
HashSet, I, import, in, J, java, K, L, M, main, N, new,
out, Output, println, public, remove, removeAll,
removed, Set, set1, set2, SetOperations, split, static,
String, System, to, true, util, void, X, Y, Z]
*/

Map


// collections/MapOfList.java
// {java collections.MapOfList}
package collections;
import typeinfo.pets.*;
import java.util.*;

public class MapOfList {
  public static final Map>
    petPeople = new HashMap<>();
  static {
    petPeople.put(new Person("Dawn"),
      Arrays.asList(
        new Cymric("Molly"),
        new Mutt("Spot")));
    petPeople.put(new Person("Kate"),
      Arrays.asList(new Cat("Shackleton"),
        new Cat("Elsie May"), new Dog("Margrett")));
    petPeople.put(new Person("Marilyn"),
      Arrays.asList(
        new Pug("Louie aka Louis Snorkelstein Dupree"),
        new Cat("Stanford"),
        new Cat("Pinkola")));
    petPeople.put(new Person("Luke"),
      Arrays.asList(
        new Rat("Fuzzy"), new Rat("Fizzy")));
    petPeople.put(new Person("Isaac"),
      Arrays.asList(new Rat("Freckly")));
  }
  public static void main(String[] args) {
    System.out.println("People: " + petPeople.keySet());
    System.out.println("Pets: " + petPeople.values());
    for(Person person : petPeople.keySet()) {
      System.out.println(person + " has:");
      for(Pet pet : petPeople.get(person))
        System.out.println("    " + pet);
    }
  }
}
/* Output:
People: [Person Dawn, Person Kate, Person Isaac, Person
Marilyn, Person Luke]
Pets: [[Cymric Molly, Mutt Spot], [Cat Shackleton, Cat
Elsie May, Dog Margrett], [Rat Freckly], [Pug Louie aka
Louis Snorkelstein Dupree, Cat Stanford, Cat Pinkola],
[Rat Fuzzy, Rat Fizzy]]
Person Dawn has:
    Cymric Molly
    Mutt Spot
Person Kate has:
    Cat Shackleton
    Cat Elsie May
    Dog Margrett
Person Isaac has:
    Rat Freckly
Person Marilyn has:
    Pug Louie aka Louis Snorkelstein Dupree
    Cat Stanford
    Cat Pinkola
Person Luke has:
    Rat Fuzzy
    Rat Fizzy
*/

Map 可以返回由其键组成的 Set ,由其值组成的 Collection ,或者其键值对的 Set 。 keySet() 方法生成由在 petPeople 中的所有键组成的 Set ,它在 for-in 语句中被用来遍历该 Map 。

队列Queue

队列是一个典型的“先进先出”(FIFO)集合。 即从集合的一端放入事物,再从另一端去获取它们,事物放入集合的顺序和被取出的顺序是相同的。队列通常被当做一种可靠的将对象从程序的某个区域传输到另一个区域的途径。队列在并发编程中尤为重要,因为它们可以安全地将对象从一个任务传输到另一个任务。

LinkedList 实现了 Queue 接口,并且提供了一些方法以支持队列行为,因此 LinkedList 可以用作 Queue 的一种实现。 通过将 LinkedList 向上转换为 Queue ,下面的示例使用了在 Queue 接口中与 Queue 相关(Queue-specific)的方法:

// collections/QueueDemo.java
// Upcasting to a Queue from a LinkedList
import java.util.*;

public class QueueDemo {
  public static void printQ(Queue queue) {
    while(queue.peek() != null)
      System.out.print(queue.remove() + " ");
    System.out.println();
  }
  public static void main(String[] args) {
    Queue queue = new LinkedList<>();
    Random rand = new Random(47);
    for(int i = 0; i < 10; i++)
      queue.offer(rand.nextInt(i + 10));
    printQ(queue);
    Queue qc = new LinkedList<>();
    for(char c : "Brontosaurus".toCharArray())
      qc.offer(c);
    printQ(qc);
  }
}
/* Output:
8 1 1 1 5 14 3 1 0 1
B r o n t o s a u r u s
*/

offer() 是与 Queue 相关的方法之一,它在允许的情况下,在队列的尾部插入一个元素,或者返回 false 。 *peek() 和 element() 都返回队头元素而不删除它,但是如果队列为空,则 element() 抛出 NoSuchElementException ,而 peek() 返回 null 。 poll() 和 remove() 都删除并返回队头元素,但如果队列为空,poll() 返回 null ,而 remove() 抛出 NoSuchElementException

自动包装机制会自动将 nextInt() 的 int 结果转换为 queue 所需的 Integer 对象,并将 char c 转换为 qc 所需的 Character 对象。 Queue 接口窄化了对 LinkedList 方法的访问权限,因此只有适当的方法才能使用,因此能够访问到的 LinkedList 的方法会变少(这里实际上可以将 Queue 强制转换回 LinkedList ,但至少我们不鼓励这样做)。

与 Queue 相关的方法提供了完整而独立的功能。 也就是说,对于 Queue 所继承的 Collection ,在不需要使用它的任何方法的情况下,就可以拥有一个可用的 Queue 。

优先级队列PriorityQueue (暂定了解)

先进先出(FIFO)描述了最典型的队列规则(queuing discipline)。队列规则是指在给定队列中的一组元素的情况下,确定下一个弹出队列的元素的规则。先进先出声明的是下一个弹出的元素应该是等待时间最长的元素。

优先级队列声明下一个弹出的元素是最需要的元素(具有最高的优先级)。例如,在机场,当飞机临近起飞时,这架飞机的乘客可以在办理登机手续时排到队头。如果构建了一个消息传递系统,某些消息比其他消息更重要,应该尽快处理,而不管它们何时到达。在Java 5 中添加了 PriorityQueue ,以便自动实现这种行为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值