java-栈、队列、数组、链表、Hash、树以及集合(二)

引言
主要整理了集合的另一个部分,Set,Set是一个接口,它的实现类有hashSet和treeSet,下面主要介绍有关这两个实现类。
HashSet
元素顺序:元素唯一,但是无序(它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变)
用一段代码进行测试:

package com.stu.hashset;
import java.util.HashSet;
//案例:创建一个HashSet集合,添加元素(String元素),测试唯一性,无序性
public class HashSetStu01 {
    public static void main(String[] args) {
        HashSet hs = new HashSet();
        hs.add("hello");
        hs.add("world");
        hs.add("java");
        hs.add("world");
        for(String str:hs){
            System.out.println(str);
        }
    }
}

编译运行结果如下:
hello
java
world
那么,hashSet是如何保证元素的唯一性呢?HashSet集合保证元素的唯一性和add()方法相关。如果我们想深入的了解,就必须看add()方法的源码,看它的底层依赖什么内容?
在这里,做一个简单的介绍:
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {…}
左边:e.hash == hash 比较对象的哈希值。
右边:((k = e.key) == key || key.equals(k))
(1)左边:(k = e.key) == key
比较对象的地址值。
(2)右边:key.equals(k)
比较的是对象的内容是否相同。默认情况下比较的是地址值
结论:
底层数据结构是哈希表。
哈希表依赖两个方法:hashCode()和equals()
执行流程:
首先判断哈希值是否相同,如果不同,就直接添加到集合。
如果相同,继续执行equals(),看其返回值,
如果是false,就直接添加到集合。
如果是true,说明元素重复不添加。
使用:
如果你看到哈希结构的集合,就要考虑可能需要重写这两个方法。
如果真要重写,自动生成即可。
举一个简单的例子做一说明:

//学生类
package com.stu.hashset;
public class Student {
    private String name;
    private String age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public Student(String name, String age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    //重写hashcode和equals
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((age == null) ? 0 : age.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;
        Student other = (Student) obj;
        if (age == null) {
            if (other.age != null)
                return false;
        } else if (!age.equals(other.age))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

编译运行结果如下:
周杰伦 35
方大同 35
薛之谦 35
用一个图解对上述做一个简单的说明:
java-栈、队列、数组、链表、Hash、树以及集合(二)_第1张图片
TreeSet
元素顺序:使用元素的自然顺序对元素进行排序,或者根据创建 set时提供的 Comparator进行排序(比较器排序),具体取决于使用的构造方法。
底层算法:二叉树,如图所示:
java-栈、队列、数组、链表、Hash、树以及集合(二)_第2张图片
元素要求, 加入自定义JavaBean
用一个案例进行理解:创建集合存储Integer类型的元素(20,18,23,22,17,24,19,18,24),分析如何保证元素唯一性,以及排序的规则。二叉树数据结构是怎么存入元素的,根据compareTo()方法的返回值来确定要存入元素的安放位置
具体代码实现如下:

package com.stu.treeset;
import java.util.TreeSet;
/*创建集合存储Integer类型的元素(20,18,23,22,17,24,19,18,24),
分析如何保证元素唯一性,以及排序的规则。二叉树
(首先讲解二叉树数据结构是怎么存入元素的,
根据compareTo()方法的返回值来确定要存入元素的安放位置)*/
public class TreeSetStu01 {
    public static void main(String[] args) {
        TreeSet ts = new TreeSet();
        //(20,18,23,22,17,24,19,18,24)
        ts.add(20);
        ts.add(18);
        ts.add(23);
        ts.add(22);
        ts.add(17);
        ts.add(24);
        ts.add(19);
        ts.add(18);
        ts.add(24);
        for(Integer integer:ts){
            System.out.println(integer);
        }   
    }
}

编译运行结果如下:
17
18
19
20
22
23
24
当我们自定义一个对象的时候,就需要重写comparato方法,否则无法完成比较,举一个案例来实现:
存入学生对象(姓名,年龄),1.按年龄排序,2.姓名排序(自然排序实现Comparable接口,并重写comparaTo()方法)

//学生javabean
    package com.stu.treeset;
/*存入学生对象(姓名,年龄),
    1.按年龄排序,
    2.姓名排序(自然排序实现Comparable接口,并重写comparaTo()方法)*/
public class Student implements Comparable{
    private String name;
    private int 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;
    }
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public int compareTo(Student s) {
        //按照学生的年龄进行排序
        /**
         * 两个对象进行比较:
         * s
         * this
         */
        int num=this.age-s.age;
        //判断年龄是否相同,如果相同比较姓名
     int    num2=(num==0?this.name.compareTo(s.name):num);
        return num2;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
}
//测试类
package com.stu.treeset;
import java.util.TreeSet;
public class TreeSetStu03 {
    public static void main(String[] args) {
        TreeSet ts = new TreeSet();
        Student s1 = new Student("薛之谦",35);
        Student s2= new Student("方大同",32);
        Student s3 = new Student("汪涵",40);
        Student s4 = new Student("周杰伦",35);
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        for(Student st:ts){
            System.out.println(st);
        }
    }
}

编译运行后结果如下:
Student [name=方大同, age=32]
Student [name=周杰伦, age=35]
Student [name=薛之谦, age=35]
Student [name=汪涵, age=40]
HashSet与TreeSet的相同点与不同点:
相同点:
单列集合,元素不可重复
不同点
1. 底层存储的数据结构不同
HashSet底层用的是HashMap哈希表结构存储,而TreeSet底层用的是TreeMap树结构存储
2.存储时保证数据唯一性依据不同
HashSet是通过复写hashCode()方法和equals()方法来保证的,而TreeSet通过Compareable接口的compareTo()方法来保证的
3.有序性不一样
HashSet无序,TreeSet有序
这种情况的数据,属于一一对应的映射关系。这种关系的集合在java叫Map。
Map:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map接口中的方法概述(创建集合测试方法):
java-栈、队列、数组、链表、Hash、树以及集合(二)_第3张图片
有关其功能,用相应代码进行实现:

package com.stu.map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/*
 * Map接口中的方法概述(创建集合测试方法):
 *      A:删除功能
 *          void clear():移除集合中的所有键值对元素
 *          V remove(Object key):根据键移除键值对元素,并返回值
 *      B:判断功能
 *          boolean containsKey(Object key):判断集合中是否包含指定的键
 *          boolean containsValue(Object value):判断集合中是否包含指定的值
 *          boolean isEmpty():判断集合是否为空
 *      C:获取功能
 *          Set> entrySet():获取键值对对象的集合,遍历键值对对象,
            利用getKey(),getValue()取出键和值(理解即可)
 *          
            V get(Object key):根据键获取值
 *          Set keySet():获取所有的键
 *          Collection values():获取所有的值
 *      D:添加功能
 *          V put(K key,V value):集合添加键值对
 *      E:长度功能
 *          int size():键值对对数。
 */
public class MapStu01 {
    public static void main(String[] args) {
        //V put(K key,V value):集合添加键值对
        Map hm = new HashMap();
        hm.put(1, "薛之谦");
        hm.put(2, "周杰伦");
        hm.put(3, "方大同");
        hm.put(4, "孙子涵");
        //int size():键值对对数
        int len =hm.size();
        System.out.println(len);//4
        //void clear():移除集合中的所有键值对元素
        //hm.clear();
        /*int len2 =hm.size();
        System.out.println(len2);//0
*/      //V remove(Object key):根据键移除键值对元素,并返值
//      String remove = hm.remove(2);
//      System.out.println(remove);//周杰伦
        //boolean containsKey(Object key):判断集合中是否包含指定的键
//      boolean key = hm.containsKey(3);
//      System.out.println(key);//true
        //boolean containsValue(Object value):判断集合中是否包含指定的值
        boolean value = hm.containsValue("薛之谦");
        System.out.println(value);//true
        //boolean isEmpty():判断集合是否为空
        boolean empty = hm.isEmpty();
        System.out.println(empty);//false
        //Set.Entry> entrySet():获取键值对对象的集合,
        //遍历键值对对象,利用getKey(),getValue()取出键和值(理解即可)
        Set> entrySet = hm.entrySet();
        for(Entry entry:entrySet){
            System.out.println(entry.getKey()+" "+entry.getValue());
        }
        /*
         *  1 薛之谦
            2 周杰伦
            3 方大同
            4 孙子涵
         */
        //Set keySet():获取所有的键
        Set keySet = hm.keySet();
        for(Integer key:keySet){
            //V get(Object key):根据键获取值
            System.out.println(key+" "+hm.get(key));
        }
        //Collection values():获取所有的值
        Collection values = hm.values();
        Iterator it = values.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        /*
         *  薛之谦
            周杰伦
            方大同
            孙子涵
         */
    }
}

部分运行结果在代码中注释
HashMap
元素顺序:元素顺序不可预测
底层算法:哈希算法
对键没有要求(仅仅相对于TreeMap来说)
在这里,做一个需求:存入(Student,String),键是同一个对象的时候要把之前存入的元素挤出去,想要实现这样的效果的话,
需要重写javabean里面的hashCode()和equals()方法

//学生javabean
package com.edu_10;
public class Student{
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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 String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        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;
        Student other = (Student) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}
//测试
package com.edu_10;
import java.util.HashMap;
import java.util.Set;
public class HashMapDemo {
    public static void main(String[] args) {
        // 3.存入(Student,String)
        //创建一个Map集合
        HashMap hm = new HashMap();
        //创建学生对象
        Student s1 = new Student("杰克逊", 60);
        Student s2 = new Student("孙楠", 50);
        Student s3 = new Student("权志龙", 30);
        Student s4 = new Student("权志龙", 30);
        //将对象存入集合
        hm.put(s1, "美国");
        hm.put(s2, "中国");
        hm.put(s3, "韩国");
        hm.put(s4, "中国");
        //遍历集合
        Set keys = hm.keySet();
        for (Student s : keys) {
            System.out.println(s+"  "+hm.get(s));
        }   
    }
}

编译运行后如下:
Student [name=权志龙, age=30] 中国
Student [name=杰克逊, age=60] 美国
Student [name=孙楠, age=50] 中国
Treemap
元素顺序:元素顺序与键的排序规则有关
底层算法:Tree算法
HashMap与TreeMap的相同点与不同点
相同点:主要用于存储键(key)值(value)对,根据键得到值,因此键不允许键重复,但允许值重复。
不同点:
1.HashMap里面存入的键值对在取出的时候是随机的,也是我们最常用的一个Map.根据键可以直接获取它的值,
具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。
2.TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。

你可能感兴趣的:(java语言)