Java系列笔记第四章:高级数据结构进阶

1. List

继承自Collection

  • 有序
  • 带索引
  • 可以存储重复元素

常用方法:

  • boolean add(e) 返回是否添加成功
  • void add(index, e)
  • boolean remove(e) 返回删除是否成功
  • E remove(index) 返回删除之前index位置的元素
  • E set(index, e) 返回更新之前的元素
  • E get(index) 返回index位置的元素

2. ArrayList

不是同步的,如果多线程访问可能不安全。

  • 查询快
  • 增删慢

注意:当长度到达默认的长度后,再添加元素需要进行整个底层数组的复制,速度会慢,如果长度没到默认长度,那么插入就是O(1)。

3. LinkedList

不是同步的,如果多线程访问可能不安全。

  • 双向链表。
  • 包含大量操作首尾元素的方法。

常用方法:

  • void addFirst(E e):将指定元素插入此列表的开头,等效于push。

  • void push(E e):将元素推入此列表所表示的堆栈。

  • void addLast(E e):将指定元素添加到此列表的结尾,等效于add。


  • E getFirst():返回此列表的第一个元素。
  • E getLast():返回此列表的最后一个元素。

  • E removeFirst():移除并返回此列表的第一个元素。等效于pop。

  • E pop():从此列表所表示的堆栈处弹出一个元素。

  • E removeLast():移除并返回此列表的最后一个元素。


  • boolean isEmpty():如果列表不包含元素,则返回true。

4. Vector

同步的,线程安全。

5. HashSet

实现了java.util.Set接口

  • 不存储重复元素
  • 没索引
  • 不能使用普通的for循环
  • 不保证按序存取
  • 底层是哈希表(查询速度快)

5.1 使用

  • 可以看出,存入顺序和实际存储的顺序并不一定相同。
package SetDemo;

import java.util.HashSet;
import java.util.Set;

public class HashSetDemo {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(3);
        set.add(2);
        set.add(3);
        System.out.println(set);
    }
}

//===========输出===========//
[1, 2, 3]

5.2 遍历

  • 增强for循环。
  • 迭代器,set.iterator()
for (Integer integer : set) {
    System.out.println(integer);
}

Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()){
    System.out.println(iterator.next());
}

6. 哈希表原理

6.1 哈希值

  • 由操作系统给出的一个十进制数字。对象的逻辑地址。
    public native int hashCode();

  • String类的hashCode()重写了,输出的不是地址值。

    “重地”与“通话”的哈希值相同,是个巧合。

6.2 哈希表

jdk1.8开始,哈希表变成了 数组+链表/红黑树(提高查询速度)。

  • 用数组存储哈希值
  • 链表用来解决哈希冲突
  • 如果一个哈希值下面超过了8个元素,就会把链表转为红黑树。

6.3 Set存储不重复元素的原理

Set的add过程:

  • 调用元素的hashCode方法和equals方法,判断元素是否重复。
    • hashCode方法计算出哈希值
    • 在数组中查找对应哈希值的元素
    • 如果不存在,就插入。
    • 如果存在,调用equals方法判断是否重复。
    • 重复就不插入,不重复就插入

6.4 Set存储自定义类型元素

存储的元素必须重写hashCode和equals方法。

举例:定义一个Person类,要求姓名和年龄相同的人是同一个人。将对象存入HashSet。

//===========类定义===========//

package SetDemo;

import java.util.Objects;

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //重写equlas函数
    //age相同且name相同,就认为是同一个人。
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }

    //重写toString函数
    @Override
    public String toString() {
        return "[name='" + name + '\'' + ", age=" + age + "]";
    }

    //重写hashCode函数
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

//===========测试函数===========//

package SetDemo;

import java.util.HashSet;
import java.util.Set;

public class HashSet_Person {
    public static void main(String[] args) {
        Person p1 = new Person("a",18);
        Person p2 = new Person("b",21);
        Person p3 = new Person("c",18);
        Person p4 = new Person("a",18);

        //p1的哈希值应该与p4相同
        System.out.println(p1.hashCode());
        System.out.println(p2.hashCode());
        System.out.println(p3.hashCode());
        System.out.println(p4.hashCode());

        Set<Person> personSet = new HashSet<>();
        personSet.add(p1);
        personSet.add(p2);
        personSet.add(p3);
        personSet.add(p4);
        System.out.println(personSet);
    }
}

//===========输出===========//
3986
4020
4048
3986
[[name='c', age=18], [name='a', age=18], [name='b', age=21]]

7. LinkedHashSet 插入有序集合

继承自HashSet

  • 底层是哈希表+链表
  • 插入有序
  • 可索引
    • 意味着add、remove等操作均可指定index。
package SetDemo;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        Set<Integer> set1 = new LinkedHashSet<>();
        Set<Integer> set2 = new HashSet<>();
        set1.add(3);
        set1.add(1);
        set1.add(2);

        set2.add(3);
        set2.add(1);
        set2.add(2);
        System.out.println(set1);
        System.out.println(set2);
    }
}
//===========输出===========//
[3, 1, 2]
[1, 2, 3]

8. 可变参数(变长参数表)

public void fun(参数类型...形参名)

等价于

public void fun(参数类型[] 形参名)

  • 参数表底层是一个数组

  • 注意事项:

    • 一个方法只能有一个变长参数。
    • 如果参数表有变长参数有普通参数,变长参数必须写在参数表末尾。
public class test {


    public static void main(String[] args) {
        fun(1,2,3,4,5);
        fun(1,2,3);
        fun();
    }

    private static void fun(int...nums) {
        int sum = 0;
        for(int i:nums){
            sum+=i;
        }
        System.out.println(sum);
    }
}

//===========输出===========//
15
6
0

9. Collections工具类

9.1 shuffle

  • Collections.shuffle(List<T> l) 随机打乱集合内元素的顺序。

9.2 addAll

  • Collections.addAll(集合对象,T...elements), 往集合内添加多个元素。

9.3 sort

  • 对集合进行排序,默认是升序排序。
  • 只能对List排序,不能对set排序。
  • 如果对自定义的类排序,就需要实现Comparable接口的compareTo方法来定义排序规则。
  1. 类内实现Comparable接口

    • 重写comparaTo() 默认返回0,意思是所有元素都是相同的。
    @Override
    public int compareTo(Person o) {
        //this-o,升序排列。
        return this.age-o.age;
    }
    
  2. 使用Comparator,在sort函数内实现排序规则。

    • 创建Comparator的匿名对象。
    List<Integer> integers = new ArrayList<>();
    Collections.addAll(integers, 5, 3, 6, 8, 23, 4, 7);
    System.out.println("排序前:" + integers);
    
    Collections.sort(integers, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2-o1;
        }
    });
    
    System.out.println("排序后:"+integers);
    
    //==========输出==========//
    排序前:[5, 3, 6, 8, 23, 4, 7]
    排序后:[23, 8, 7, 6, 5, 4, 3]
    
    • 创建Comparator对象

      前面减后面,就是升序排列

    System.out.println("=========使用Comparator对象===========");
    List<Integer> integerList = new ArrayList<>();
    Collections.addAll(integerList, 5, 3, 6, 8, 23, 4, 7);
    
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    };
    
    Collections.sort(integerList, comparator);
    System.out.println("排序后:" + integerList);
    
    //==========输出==========//
    排序后:[23, 8, 7, 6, 5, 4, 3]
    

10. Map<K, V>

java.util.Map<K, V>

  • 一个K只能映射到一个V上面。
  • K和V的类型可以不同。
  • K不允许重复,V可以重复。

10.1 HashMap

java.util.HashMap

  • 基于哈希表实现。
  • 不保证插入顺序
  • 线程不安全,不同步

10.2 LinkedHashMap

java.util.LinkedHashMap

  • 记录哈希表+链表实现
  • 保证插入顺序

10.3 Map常用方法

  • V put(K, V) 往Map中插入元素。若K存在,则更新V,返回原来的V。K不存在,则插入键值对并返回空。
  • V get(K) 获取K对应的值。
  • V remove(K) 如果存在K,则移除此键值对,并返回被移除的V。不存在K则返回空。
  • boolean remove(K, V) 按键值对移除元素,如果存在返回true,不存在返回false。
  • 注意:
    • 如果V是Integer类型,返回值不要用int,因为可能返回null,此时如果自动拆箱,就会报空指针异常。

  • boolean containsKey(K) 是否存在K。
  • boolean containsValue(V) 是否存在V。

  • Set<Map.Entry<K, V>> entrySet() 返回包含map中映射关系的Set视图。

  • Set<K> keySet() 返回包含map中的Key的Set视图。

  • Collection<V> values() 返回map中的values集合。

  • 注意:

    • 因为V可以重复,所以values()返回的是集合。
    • 因为K不允许重复,所以keySet()返回的是Set。

  • isEmpty() 是否为空。

package MapDemo;

import java.util.HashMap;
import java.util.Map;

public class HashMapDemo {
    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(4,"d");

        System.out.println("插入1 :  " + map.put(1, "a"));
        System.out.println("更新1,被替换的原来的V是: " + map.put(1, "ab"));

        System.out.println("-------------------------");

        System.out.println("获取存在的K : 1 - " + map.get(1));
        System.out.println("获取不存在的K : 2 - " + map.get(2));

        System.out.println("-------------------------");

        System.out.println("移除不存在的K : 2 - " + map.remove(2));
        System.out.println("移除存在的K : 1 - " + map.remove(1));

        System.out.println("-------------------------");

        System.out.println("按K-V移除不存在的2:b - " + map.remove(2,"b"));
        System.out.println("按K-V移除不存在的4:b - " + map.remove(4,"b"));
        System.out.println("按K-V移除存在的4:d - " + map.remove(4,"d"));

        System.out.println("-------------------------");

        System.out.println("map中的KV对:"+map);
        Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
        System.out.println("包含map中映射关系的Set视图: " + entrySet);

        Set<Integer> keySet = map.keySet();
        System.out.println("包含map中的Key的Set视图" + keySet);
    }
}

//==========输出==========//
插入1 :  null
更新1,被替换的原来的V是: a
-------------------------
获取存在的K : 1 - ab
获取不存在的K : 2 - null
-------------------------
移除不存在的K : 2 - null
移除存在的K : 1 - ab
-------------------------
按K-V移除不存在的2:b - false
按K-V移除不存在的4:b - false
按K-V移除存在的4:d - true
-------------------------
map中的KV对:{}
map中的KV对:{1=a, 2=b, 3=c, 4=d}
包含map中映射关系的Set视图: [1=a, 2=b, 3=c, 4=d]
包含map中的Key的Set视图[1, 2, 3, 4]

10.4 Map的遍历

    • 使用keySet方法,取出所有的K,存储在Set中。
    • 遍历Set,通过map.get(K)来找到对应的值,实现遍历。
    • 使用map.entrySet()方法获取entry对象的Set。
    • 遍历Set,使用entry对象的getKey()或getValue()方法。

10.5 HashMap存储自定义类型

  • 重写hashCode和equals方法,保证HashMap存储的内容是唯一的。

10.6 LinkedHashMap

继承自HashMap

  • 实现了插入有序。

  • 线程不安全。

  • 特有方法:boolean removeEldestEntry(Map.Entry<K,V> eldest)

    • 用来移除最早的键值对。
    • 移除成功,返回true。

11. HashTable

  • 线程安全的。
  • 不能存储null。
  • JDK 1.2 以后被HashMap取代。

12. 通过List、Set、Map的静态方法来创建不可变对象

of(E…e)方法。

List.of()

Set.of()

Map.of()

  • 从jdk1.9开始。
  • 返回不可变对象。
  • 接收变长参数。
  • Set和Map接收参数时不能有重复元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值