线性表,栈,队列和优先队列

为一个特定的任务选择最好的数据结构和算法是开发高性能软件的一个关键。

1. Collection

Collection接口为线性表,向量,栈,队列,优先队列以及集合定义了共同的操作。

Java collection框架中定义的所有接口和类都分组在java.util包中。

Java collection框架的设计是使用接口,抽象类和具体类的一个优秀范例。用接口定义框架,抽象类提供这个接口的部分实现。具体类用具体数据结构实现这个接口。提供一个部分实现接口的抽象类对用户编写代码提供了方便,用户可以简单地定义一个具体类继承自抽象类,而无需实现接口中的所有方法。

Collection接口是处理对象合集的根接口,它的公共方法在下图中列出:

collection接口中有些方法是不能在具体子类中实现的。这些方法会抛出异常java.lang.UnsupportedOperationException,它是RuntimeException异常类的一个子类。我们在自己的项目中,若一个方法在子类中没有意义,可以如下实现它:

public void someMethod() {
  throw new UnsupportedOperationException("Method not supported.");
}

除了PriorityQueue没有实现Cloneable,Java其他合集框架都实现了java.lang.Cloneable和java.io.Serializable接口。所有Cloneable的实例都是可克隆的,且所有Cloneable的实例都是可序列化的。

2. 迭代器

每种合集都是可迭代的(Iterable)。可以获得集合的Iterator对象来遍历合集中的所有元素。Iterator是一种经典的设计模式,用于在不暴露数据如何保存在数据结构的细节的情况下,来遍历一个数据结构。

Collection接口继承自Iterable接口。Iterable接口中定义了iterator()方法,来返回一个Iterator实例。

Iterator<String> iterator = collction.iterator();

Iterator接口为遍历各种类型的合集中的元素提供了一种统一的方法,如图20-2所示。

3. 线性表

List接口继承自Collection接口,定义了一个用于顺序存储元素的合集。可以用它的两个具体类ArrayList或LinkedList来创建一个线性表(list)。

ArrayList和LinkedList定义在List接口下。List接口继承Collection接口,定义了一个允许重复的有序合集。List接口增加了面向位置的操作,且增加了一个能够双向遍历线性表的新线性表迭代器。

ListIterator接口继承了Iterator接口,以增加对线性表的双向遍历能力。ListIterator接口中的方法如下:

AbstractList类提供了List接口的部分实现。AbstractSequentialList类扩展了AbstractList类,以提供对链表的支持。

ArrayList和LinkedList

ArrayList和LinkedList是实现List接口的两个具体类。ArrayList用数组存储元素,这个数组是动态创建的。LinkedList在一个链表中存储元素。

具体选用两种类中的哪一个取决于特定需求。若要通过下标随机访问元素,而不会在线性表起始位置插入或删除元素,那么ArrayList提供了最高效的合集。但是,若程序需要在线性表起始位置插入或删除元素,就应该选择LinkedList。线性表的大小是可以动态增大或减小的,然而数组一旦被创建,它的大小就是固定的。如果应用程序不需要在线性表中插入或删除元素,那么数组是最高效的数据结构。

ArrayList使用可变大小的数组实现List接口。它还提供了一些方法,用于管理存储线性表的内部数组大小。

LinkedList使用链表实现List接口,除了实现List接口外,这个类还提供从线性表的两端提取,插入和删除元素的方法。

链表可以使用get(i)方法,但是这个操作比较耗时,不要用它来遍历线性表中的所有元素,应该使用一个迭代器。for (listElementType s: list) process s;

为了从可变长参数列表中创建线性表,Java提供了静态的asList方法,这样就可以用下面的方法创建一个字符串线性表:

List<String> list = Arrays.asList("red", "green", "yellow");

该方法适用于对象型数据的数组(String、Integer...),不建议使用于基本数据类型的数组。该方法将数组与List列表链接起来:当更新其一个时,另一个自动更新。此外,还不支持add()、remove()、clear()等方法。

如果你的List只是用来遍历,就用Arrays.asList()。如果你的List还要添加或删除元素,还是乖乖地new一个java.util.ArrayList,然后一个一个的添加元素。

4. Comparator接口

Java API中的一些类,比如String,Data,Calendar,以及所有基本数字类型的数字包装类都实现了Comparable接口,Comparable接口定义了compareTo方法,用于比较实现了Comparable接口的同一个类的两个元素。

若元素的类没有实现Comparable接口,则可以定义一个comparator接口来比较不同类的元素,要做到这一点,需要创建一个实现了java.util.Comprator的接口的类并重写它的compare方法。

public int compare(T element1, T element2)

import java.util.Comparator;
public class GeometricObjectComparator implements Comparator<GeometricObject>, java.io.Serializable {
  public int compare(GeometricObject o1, GeometricObject o2) {
    double area1 = o1.getArea();
    double area2 = o2.getArea();
    if (area1 < area2)
      return -1
    else if (area1 == area2)
      return 0
    else
      return 1;
  }
}
// 测试
public class TestComparator {
  public static void main(String[] args) {
    GeometricObject g1 = new Rectangle(5, 5);
    GeometricObject g2 = new Circle(5);
    GeometricObject g = max(g1, g2, new GeometricObjectComparator())
      public static GeometricObject max (GeometricObject g1, 
                                        GeometricObject g2, 
                                        Comparator<GeometricObject> c)
      return (c.compare(g1, g2) > 0)? g1 : g2
  }
} 

5. 线性表和合集的静态方法

List<String> list = Arrays.asList("red", "green", "blue");
Collections.sort(list);
Collections.sort(list, Collections.reverseOrder());
Collections.reverse(list);
Collections.shuffle(list, new Random(20));

6. 向量类和栈类

Java API中,Vector是AbstractList的子类,Stack是Vector的子类。

除了包含用于访问和修改向量的同步方法之外,Vector类和ArrayList是一样的。对于许多不需要同步的应用程序来说,使用ArrayList比使用Vector高效。

7. 队列和优先队列

队列是一种先进先出的数据结构。优先队列中,元素被赋予优先级,在访问元素时,具有最高优先级的元素最先被移除。

Queue接口继承自java.util.Collection,加入了插入,提取和检验等操作。

LinkedList类实现了Deque接口,Deque又继承自Queue接口。LinkedList很适合用于进行队列操作,因为它可以高效地在线性表两端插入和移除元素。


posted @ 2021-05-15 12:17  geeks_reign  阅读(131)  评论(0编辑  收藏  举报