Java集合框架【二容器[LinkedList容器类、Set接口]】

一 LinkedList容器类

  • LinkedList底层用双向链表实现的存储。
  • 特点:查询效率低,增删效率高,线程不安全双向链表也叫双链表,是链表的一种,它的每个数据节点中都有两个指针,分别指向前一个节点和后一个节点。所以,从双向链表中的任意一个节点开始,都可以很方便地找到所有节点。
    在这里插入图片描述
class Node<E> {
	E item;
	Node<E> next;
	Node<E> prev;
}

1.1 LinkedList的使用(List接口)

  • Linked实现了List接口,所以LinkedList是具备List的存储特征的【有序、可重复】
public class LInkedListTest {
    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("a");
        for(String s :list) {
            System.out.println(s);
        }
    }
}

在这里插入图片描述

1.2 Linked的使用(非List标准)

方法说明
void addFirst(E e)将指定元素插入到开头
void add Last(E e)将指定元素插入到结尾
getFirst()返回此列表的第一个元素
getLast()返回此列表的最后一个元素
removeFirst()移除此列表中的第一个元素,并返回这个元素
removeLast()移除此列表中的最后一个元素,并返回这个元素
E pop()从此列表所表示的堆栈处弹出一个元素,等效于removeFirst
voidpush(E e)将元素推入此列表所表示的堆栈这个等效于addFisrt(E e)
booleanisEmpty()判断列表是否包含元素,如果不包含元素则返回true

1.4 LinkedList源码分析

  • 节点类
private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

二 Set接口

  • Set接口继承自Collection,Set接口中没有新增方法,方法和Collection保持完全一致。我们在前面通过List学习的方法,在Set中仍然适用。因此,学习Set的使用将没有任何难度。

2.1 Set接口特点

  • Set特点:无序、不可重复无序指Set中的元素没有索引,我们只能遍历查找;不可重复指不允许加入重复的元素。更确切地讲,新元素如果和Set中某个元素通过equals()方法对比为true,则只能保留一个。
  • Set常用的实现类有:HashSet、TreeSet等。

2.2 HashSet容器类

  • Hashset是一个没有重复元素的集合,不保证元素的顺序。而且HashSet允许有null元素。HashSet是采用哈希算法实现,底层实际是用HashMap实现的(HashSet本质就是一个简化版的HashMap),因此,查询效率和增删效率都比较高。

2.2.1 Hash算法原理

  • Hash算法也称之为散列算法
    在这里插入图片描述

2.2.2 HashSet的例子

/**
 * @author 缘友一世
 * date 2022/11/23-9:03
 */
public class HashSetTest {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("a");
        set.add("d");
        set.add("b");
        set.add("a");
        //获取元素,在set容器中没有索引,没有对应的get方法。
        for(String s:set) {
            System.out.println(s);
        }
        boolean flag = set.remove("d");
        System.out.println(flag);
        for(String s:set) {
            System.out.println(s);
        }
        System.out.println(set.size());
    }
}

在这里插入图片描述

2.2.3 HashSet存储特征分析

  • Hashset是一个不保证元素的顺序且没有重复元素的集合,是线程不安全的。Hashset允许有null元素
    1. 无序:
      • 在HashSet中底层是使用HashMap存储元素的。
      • HashMap底层使用的是数组与链表实现元素的存储。
      • 元素在数组中存放时,并不是有序存放的也不是随机存放的,而是对元素的哈希值进行运算决定元素在数组中的位置。
    2. 不重复:
      • 当两个元素的哈希值进行运算后得到相同的在数组中的位置时,会调用元素的equals()方法判断两个元素是否相同。如果元素相同则不会添加该元素,如果不相同则会使用单向链表保存该元素。
/**
 * @author 缘友一世
 * date 2022/11/23-9:11
 */
public class Users {
    private String userName;
    private int userAge;

    public Users() {
    }

    public Users(String userName, int userAge) {
        this.userName = userName;
        this.userAge = userAge;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getUserAge() {
        return userAge;
    }

    public void setUserAge(int userAge) {
        this.userAge = userAge;
    }

    @Override
    public int hashCode() {
        int result=userName !=null ? userName.hashCode():0;
        result=31*result+userAge;
        return result;
    }

    @Override
    public boolean equals(Object o) {
        if(this==o) return true;
        if(o==null || getClass()!=o.getClass()) return false;
        Users users = (Users) o;
        if(userAge!=users.userAge) return false;
        return userName!=null ? userName.equals(users.userName):false;
    }

    @Override
    public String toString() {
        return "Users{" +
                "userName='" + userName + '\'' +
                ", userAge=" + userAge +
                '}';
    }
}

class Test {
    public static void main(String[] args) {
        HashSet<Users> set1 = new HashSet<>();
        Users aaa = new Users("aaa", 19);
        Users bbb = new Users("aaa", 19);
        set1.add(aaa);
        set1.add(bbb);
        for(Users user:set1) {
            System.out.println(user);
        }

    }
}

在这里插入图片描述

2.3 TreeSet容器类

  • TreeSet是一个可以对元素进行排序的容器底层实际是用TreeMap实现的,***内部维持了一个简化版的TreeMap,通过key来存储Set的元素。***TreeSet内部需要对存储的元素进行排序,因此,我们需要给定排序规则。
  • 排序规则实现方式
    • 通过元素自身实现比较规则
    • 通过比较器指定比较规则
/**
 * @author 缘友一世
 * date 2022/11/23-9:30
 */
public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet<String> set = new TreeSet<>();
        set.add("c");
        set.add("a");
        set.add("b");
        set.add("1");
        for(String str:set) {
            System.out.println(str);
        }
    }
}

在这里插入图片描述
在这里插入图片描述

2.4 通过元素自身实现比较规则

  • 在元素自身实现比较规则时,需要实现Comparable接口中的compareTo方法,该方法中用素定义比较规则。TreeSet通过调用该方法来完成对元素的排序处理。
/**
 * @author 缘友一世
 * date 2022/11/23-12:53
 */
public class SortTest {
    public static void main(String[] args) {
        TreeSet<Users2> set1 = new TreeSet<>();
        Users2 aaa = new Users2("aaa", 19);
        Users2 ccc = new Users2("ccc", 17);
        Users2 bbb = new Users2("bbb", 19);
        set1.add(aaa);
        set1.add(bbb);
        set1.add(ccc);
        for(Users2 user:set1) {
            System.out.println(user);
        }
    }
}
class Users2 implements Comparable<Users2> {

    private String userName;
    private int userAge;

    public Users2() {
    }

    public Users2(String userName, int userAge) {
        this.userName = userName;
        this.userAge = userAge;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getUserAge() {
        return userAge;
    }

    public void setUserAge(int userAge) {
        this.userAge = userAge;
    }

    @Override
    public int hashCode() {
        int result=userName !=null ? userName.hashCode():0;
        result=31*result+userAge;
        return result;
    }



    @Override
    public boolean equals(Object o) {
        if(this==o) return true;
        if(o==null || getClass()!=o.getClass()) return false;
        Users2 users = (Users2) o;
        if(userAge!=users.userAge) return false;
        return userName!=null ? userName.equals(users.userName):false;
    }

    @Override
    public String toString() {
        return "Users{" +
                "userName='" + userName + '\'' +
                ", userAge=" + userAge +
                '}';
    }

    @Override
    public int compareTo(Users2 o) {
        if(this.userAge>o.getUserAge()) {
            return 1;
        }
        if(this.userAge==o.getUserAge()) {
            return this.userName.compareTo(o.getUserName());
        }
        return -1;
    }
}

在这里插入图片描述

2.5 通过比较器实现比较规则

  • 通过比较器定义比较规则时,我们需要单独创建一个比较器,比较器需要实现Comparator接口中的compare方法来定义比较规则。
  • 在实例化TreeSet时将比较器对象交给TreeSet来完成元素的排序处理。此时元素自身就不需要实现比较规则了。

/**
 * @author 缘友一世
 * date 2022/11/23-13:24
 */
class Test {
    public static void main(String[]args){
        TreeSet<student> set = new TreeSet<>(new ComparatorTest());
        student ooo = new student("ooo", 18);
        student aaa = new student("aaa", 22);
        student sss = new student("sss", 22);
        set.add(ooo);
        set.add(aaa);
        set.add(sss);
        for(student x:set) {
            System.out.println(x);
        }
    }
}
public class ComparatorTest implements Comparator<student> {
    //定义比较规则

    @Override
    public int compare(student o1, student o2) {
        if(o1.getAge()>o2.getAge()) {//升序
            return 1;
        }else if(o1.getAge()==o2.getAge()) {
            return o1.getName().compareTo(o2.getName());
        }
        return -1;
    }
}
class student {
    private  String name;
    private int age;

    public student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        student student = (student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

在这里插入图片描述

三 单例集合使用例子

  • 生成1-10之间的随机数(1-10),将不重复的10个随机数放到容器中

List实现

/**
 * @author 缘友一世
 * date 2022/11/23-13:36
 */
public class SetDemo {
  public static void main(String[] args) {
  ArrayList<Integer> list = new ArrayList<>();
        while(true) {
            int num=(int)(Math.random()*10+1);
            if(!list.contains(num)) {
                list.add(num);
            }
            if(list.size()==10) {
                break;
            }
        }
        for(Integer x:list) {
            System.out.println(x);
        }
    }
}

在这里插入图片描述

Set实现

/**
 * @author 缘友一世
 * date 2022/11/23-13:36
 */
public class SetDemo {
    public static void main(String[] args) {
        HashSet<Integer> set = new HashSet<>();
        while(true) {
            //set容器是不允许有重复元素的,所以不需要
            int num=(int)(Math.random()*10+1);
            set.add(num);
            if(set.size()==10) {
                break;
            }
        }
        for(Integer i:set) {
            System.out.println(i);
        }
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值