【算法】Java 中常用的集合类

22 篇文章 2 订阅

  想要熟练写出算法题,必须要做到对 java 中的集合做到熟练使用。java 中的集合实现了各种数据结构,我们可以直接使用这些数据结构,更加专注与解决算法问题而不是实现这些数据结构。

  集合主要分为两大类,包括 Collection 和 Map,Collection 表示一组对象,Map 表示一组映射关系或键值对。

下图是 Collection 之间的继承和实现关系:

在这里插入图片描述

下图是 Map 之间的继承和实现关系:

在这里插入图片描述

1.Collection 常用功能

  Collection是所有单列集合的父接口,因此在 Collection 中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。方法如下:

1、添加元素

(1)add(E obj):添加元素对象到当前集合中。

(2)addAll(Collection<? extends E> other):添加other集合中的所有元素对象到当前集合中,即this = this ∪ other。

2、删除元素

(1)boolean remove(Object obj) :从当前集合中删除第一个找到的与obj对象equals返回true的元素。

(2)boolean removeAll(Collection<?> coll):从当前集合中删除所有与coll集合中相同的元素。即this = this - this ∩ coll

3、判断元素

(1)boolean isEmpty():判断当前集合是否为空集合。

(2)boolean contains(Object obj):判断当前集合中是否存在一个与obj对象equals返回true的元素。

(3)boolean containsAll(Collection<?> c):判断c集合中的元素是否在当前集合中都存在。即c集合是否是当前集合的“子集”。

4、查询

(1)int size():获取当前集合中实际存储的元素个数。

(2)Object[] toArray():返回包含当前集合中所有元素的数组。

5、交集

(1)boolean retainAll(Collection<?> coll):当前集合仅保留与c集合中的元素相同的元素,即当前集合中仅保留两个集合的交集,即this = this ∩ coll。

2.Iterator 迭代器

Iterator 接口主要用于遍历元素,的常用方法如下:

  • public E next():返回迭代的下一个元素。
  • public boolean hasNext():如果仍有元素可以迭代,则返回 true。
public class IteratorDemo {
  	public static void main(String[] args) {
        // 使用多态方式 创建对象
        Collection<String> coll = new ArrayList<String>();

        // 添加元素到集合
        coll.add("张三");
        coll.add("李四");
        coll.add("王五");

        Iterator<String> it = coll.iterator();
        //  泛型指的是 迭代出 元素的数据类型
        while(it.hasNext()){ //判断是否有迭代元素
            String s = it.next();//获取迭代出的元素
            System.out.println(s);
        }
  	}
}

注意:不要在使用Iterator迭代器进行迭代时,调用 Collection 的 remove(xx) 方法,否则会报异常java.util.ConcurrentModificationException,或出现不确定行为。可以使用迭代器的 remove() 方法。

3.List 集合

  List 继承至 Collection 接口,继承了 Collection 接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法,如下:

1、添加元素

  • void add(int index, E ele)
  • boolean addAll(int index, Collection<? extends E> eles)

2、获取元素

  • E get(int index)
  • List subList(int fromIndex, int toIndex)

3、获取元素索引

  • int indexOf(Object obj)
  • int lastIndexOf(Object obj)

4、删除和替换元素

  • E remove(int index)
  • E set(int index, E ele)

List集合特有的方法都是跟索引相关。

3.1 ArrayList 集合

  实现了 List 接口。可以使用 Collection 和 List 中提供的方法。

3.2 Vector 集合

  版本古老,不支持快速失败,很少使用。

3.3 LinkedList 集合

  链表结构。方便元素添加、删除的集合。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。

  JDK1.6 之后 LinkedList 实现了 Deque 接口。双端队列也可用作 LIFO(后进先出)堆栈。如果要使用堆栈结构的集合,可以考虑使用LinkedList,而不是Stack。

堆栈方法等效Deque方法
push(e)addFirst(e)
pop()removeFirst()
peek()peekFirst()
public static void main(String[] args) {
    LinkedList<Integer> list = new LinkedList<>();
    //入栈
    list.addFirst(1);
    list.addFirst(2);
    list.addFirst(3);

    //出栈: LIFO(后进先出)
    System.out.println(list.removeFirst());//3
    System.out.println(list.removeFirst());//2
    System.out.println(list.removeFirst());//1
    //栈空了,会报异常java.util.NoSuchElementException
    System.out.println(list.removeFirst());
}

用作队列时,将得到 FIFO(先进先出)行为。将元素添加到双端队列的末尾,从双端队列的开头移除元素。

Queue 方法等效 Deque 方法
add(e)addLast(e)
offer(e)offerLast(e)
remove()removeFirst()
poll()pollFirst()
element()getFirst()
peek()peekFirst()
public static void main(String[] args) {
		LinkedList<Integer> list = new LinkedList<>();
		//入队
		list.addLast(1);
		list.addLast(2);
		list.addLast(3);
		
		//出队, FIFO(先进先出)
		System.out.println(list.pollFirst());//1
		System.out.println(list.pollFirst());//2
		System.out.println(list.pollFirst());//3
		//队空了,返回null
		System.out.println(list.pollFirst());//null
	}

每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。

3.4 ListIterator

List 集合额外提供了一个 listIterator() 方法,该方法返回一个 ListIterator 对象, ListIterator 接口继承了 Iterator 接口,提供了专门操作 List 的方法:

  • void add():通过迭代器添加元素到对应集合
  • void set(Object obj):通过迭代器替换正迭代的元素
  • void remove():通过迭代器删除刚迭代的元素
  • boolean hasPrevious():如果以逆向遍历列表,往前是否还有元素。
  • Object previous():返回列表中的前一个元素。
  • int previousIndex():返回列表中的前一个元素的索引
  • boolean hasNext()
  • Object next()
  • int nextIndex()
public static void main(String[] args) {
    List<String> c = new ArrayList<>();
    c.add("张三");
    c.add("李四");
    c.add("王五");

    //从指定位置往前遍历
    ListIterator<String> listIterator = c.listIterator(c.size());
    while(listIterator.hasPrevious()){
        String previous = listIterator.previous();
        System.out.println(previous);
    }
}
4.Set 集合

  Set 接口是 Collection 的子接口,set 接口没有提供额外的方法。但是比Collection接口更加严格了,Set 集合不允许包含相同的元素。Set集合支持的遍历方式和Collection集合一样:foreach和Iterator。Set的常用实现类有:HashSet、TreeSet、LinkedHashSet。

4.1 HashSet

  HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。java.util.HashSet底层的实现其实是一个java.util.HashMap支持,然后 HashMap 的底层物理实现是一个 Hash 表。

  HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。因此,存储到HashSet的元素要重写hashCode和equals方法。例如实现一个 Employee 类,要求 name 和 birthday 一样的视为同一个员工:

public class Employee {
	private String name;
	private MyDate birthday;
	
    // 这里 构造方法、getter、setter 都省略
    
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((birthday == null) ? 0 : birthday.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
    
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Employee other = (Employee) obj;
		if (birthday == null) {
			if (other.birthday != null)
				return false;
		} else if (!birthday.equals(other.birthday))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
    // toString() 这里省略
}

public class MyDate {
	private int year;
	private int month;
	private int day;
	
    // 这里 构造方法、getter、setter 都省略
    
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + day;
		result = prime * result + month;
		result = prime * result + year;
		return result;
	}
    
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		MyDate other = (MyDate) obj;
		if (day != other.day)
			return false;
		if (month != other.month)
			return false;
		if (year != other.year)
			return false;
		return true;
	}
	
    // toString() 这里省略
}
4.2 LinkedHashSet

  LinkedHashSet 是 HashSet 的子类,它在HashSet的基础上,在结点中增加两个属性 before 和 after 维护了结点的前后添加顺序。java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。

4.3 TreeSet

底层结构:里面维护了一个TreeMap,基于红黑树实现。

特点:

  • 不允许重复
  • 实现排序:自然排序或定制排序

如何实现去重的?

  • 如果使用的是自然排序,则通过调用实现的compareTo方法
  • 如果使用的是定制排序,则通过调用比较器的compare方法

如何排序?

  • 自然排序:让待添加的元素类型实现Comparable接口,并重写compareTo方法

  • 定制排序:创建Set对象时,指定Comparator比较器接口,并实现compare方法

下面给出定制排序的例子:

public class Student{
	private int id;
	private String name;
	
    // 这里省略了构造方法、getter、setter、toString
}

public void test3(){
    TreeSet<Student> set = new TreeSet(new Comparator<Student>(){
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getId() - o2.getId();
        }

    });
    set.add(new Student(3,"张三"));
    set.add(new Student(1,"李四"));
    set.add(new Student(2,"王五"));
    set.add(new Student(3,"张三凤"));

    System.out.println("元素个数:" + set.size());
    for (Student stu : set) {
        System.out.println(stu);
    }
}
5.Map 集合

Map<K,V>接口下的集合与Collection<E>接口下的集合,它们存储数据的形式不同。

  • Collection中的集合,元素是孤立存在的,向集合中存储元素采用一个个元素的方式存储。
  • Map中的集合,元素是成对存在的。每个元素由键与值两部分组成,通过键可以找对所对应的值。
  • Collection中的集合称为单列集合,Map中的集合称为双列集合。
  • Map中的集合不能包含重复的键,值可以重复。

Map 的常用方法如下:

1、添加操作

  • V put(K key,V value)
  • void putAll(Map<? extends K,? extends V> m)

2、删除

  • void clear()
  • V remove(Object key)

3、元素查询的操作

  • V get(Object key)
  • boolean containsKey(Object key)
  • boolean containsValue(Object value)
  • boolean isEmpty()

4、元视图操作的方法:

  • Set keySet()
  • Collection values()
  • Set<Map.Entry<K,V>> entrySet()

5、其他方法

  • int size()

Map 的遍历可以采用如下几种方式:

// map.keySet()
System.out.println("所有的key:");
Set<String> keySet = map.keySet();
for (String key : keySet) {
    System.out.println(key);
}

// map.values()
System.out.println("所有的value:");
Collection<String> values = map.values();
for (String value : values) {
    System.out.println(value);
}

// map.entrySet()
System.out.println("所有的映射关系");
Set<Map.Entry<String,String>> entrySet = map.entrySet();
for (Map.Entry<String,String> entry : entrySet) {
    System.out.println(entry.getKey()+"->"+entry.getValue());
}
5.1 HashMap 和 HashTable

  Map 接口提供的方法都可以使用。

5.2 LinkedHashMap

  LinkedHashMap 是 HashMap 的子类。此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。

5.3 TreeSet

  基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

TreeMap<String,Integer> map = new TreeMap<>(new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.compareToIgnoreCase(o2);
    }
});
5.4 Properties

Properties 类是 Hashtable 的子类,Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法。

代码示例:

	public static void main(String[] args) {
		Properties properties = System.getProperties();
		String p2 = properties.getProperty("file.encoding");//当前源文件字符编码
		System.out.println(p2);
	}
6.Collections 工具类

Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法:

  • public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,而且支持自然排序
  • public static T max(Collection<? extends T> coll,Comparator<? super T> comp)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,按照比较器comp找出最大者
  • public static void reverse(List<?> list)反转指定列表List中元素的顺序。
  • public static void shuffle(List<?> list) List 集合元素进行随机排序,类似洗牌
  • public static <T extends Comparable<? super T>> void sort(List list)根据元素的自然顺序对指定 List 集合元素按升序排序
  • public static void sort(List list,Comparator<? super T> c)根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
  • public static void swap(List<?> list,int i,int j)将指定 list 集合中的 i 处元素和 j 处元素进行交换
  • public static int frequency(Collection<?> c,Object o)返回指定集合中指定元素的出现次数
  • public static void copy(List<? super T> dest,List<? extends T> src)将src中的内容复制到dest中
  • public static boolean replaceAll(List list,T oldVal,T newVal):使用新值替换 List 对象的所有旧值

欢迎关注公众号。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值