Java——Collection 2-3 (Set)

Set

Set collection overview and characteristics

Set collection features

  • A collection that does not contain duplicate elements
  • There is no method with an index, so you cannot use a normal for loop to traverse

Set collection exercises

  • store the string and iterate over
import java.util.HashSet;
import java.util.Set;

/*
Set集合特点

 不包含重复元素的集合
 没有带索引的方法,所以不能使用普通for循环遍历

HashSet:对集合的迭代顺序不作任何保证

*/
public class SetDemo {
    
    
	public static void main(String[] args) {
    
    
		//创建集合对象
		//HashSet:对集合的迭代顺序不作任何保证
		Set<String> set = new HashSet<String>();

		//添加元素
		set.add("hello");
		set.add("world");
		set.add("java");
		//不包含重复元素
		set.add("hello");

		//遍历
		for (String s : set) {
    
    
			System.out.println(s);
		}
		/*运行结果:
		world
		java
		hello
		*/

	}
}

Running result:
insert image description here
Hash value
Hash value: It is the value of int type calculated by JDK based on the address of the object or string or number

There is a method in the Object class to get the hash value of the object

  • public int hashCode(): returns the hash code value of the object

Object hash value characteristics

  • The hash value returned by calling the hashCode() method multiple times on the same object is the same
  • By default, different objects have different hash values. By rewriting the hashCode() method, you can make the hash values ​​of different objects the same
/*
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

Object类中有一个方法可以获取对象的哈希值:
	public int hashCode():返回对象的哈希码值
*/

public class HashDemo {
    
    
	public static void main(String[] args) {
    
    
		//创建学生对象
		Student s1 = new Student("小白", 12);
		//同一个对象多次调用hashCode()方法返回的哈希值是相同的
		System.out.println(s1.hashCode());//1854778591
		System.out.println(s1.hashCode());//1854778591
		System.out.println("--------");

		//创建学生对象
		Student s2 = new Student("小白", 22);
		//默认情况下,不同对象的哈希值是不相同的
		//通过方法重写,可以实现不同对象的哈希值相同
		System.out.println(s2.hashCode());
		System.out.println("--------");

		System.out.println("hello".hashCode());//99162322
		System.out.println("world".hashCode());//113318802
		System.out.println("java".hashCode());//3254818

		System.out.println("world".hashCode());//113318802
		System.out.println("--------");

		System.out.println("重地".hashCode());//1179395
		System.out.println("通话".hashCode());//1179395
		System.out.println("程序".hashCode());//992740
		System.out.println("代码".hashCode());//656766
	}
}

Running results:
insert image description here
HashSet collection overview and characteristics

HashSet Collection Features

  • The underlying data structure is a hash table
  • Does not make any guarantees about the iteration order of the collection, that is to say, there is no guarantee that the order of the storage group and the retrieved elements are consistent
  • There is no method with an index, so you cannot use a normal for loop to traverse
  • Since it is a Set collection, it is a collection that does not contain duplicate elements

HashSet Collection Practice

  • store the string and iterate over
public class HashSetDemo {
    
    
	public static void main(String[] args) {
    
    
		//创建集合对象
		HashSet<String> hs = new HashSet<String>();

		//添加元素
		hs.add("hello");
		hs.add("world");
		hs.add("java");
		hs.add("world");
		//遍历
		for (String s : hs) {
    
    
			System.out.println(s);
		}

	}
}

Running results:
insert image description here
HashSet collection guarantees element uniqueness source code analysis

//Create collection object
HashSet hs = new HashSet();

//add element
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");


public boolean add(E e) {
return map.put(e, PRESENT)==null;
}

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}

// The hash value is related to the hashCode() method of the element

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;

// If the hash table is not initialized, initialize it

if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;

// Calculate the storage location of the object based on the hash value of the object. If there is no element in the location, store the element
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else { Node<K,V> e; K k; /* Comparing the hash value of the stored element with the previous element , if the hash value is different, it will continue to execute downwards, Add the element to the set If the hash values ​​are the same, the equals() method of the object will be called to compare If it returns false, it will continue to execute downwards and add the element to the set If it returns true, it means that the element is duplicated and will not be stored */ if (p .hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode <K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) {
















p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}

The HashSet collection stores elements:

  • To ensure the uniqueness of elements, you need to rewrite hashCode() and equals()

Hash table of common data structures

hash table

  • Before JDK8, the bottom layer was implemented by array + linked list , which can be said to be an array whose elements are linked lists
  • After JDK8, when the length is relatively long, the bottom layer is optimized

Case: HashSet collection stores student objects and traverses

Requirement: Create a collection of student objects, store multiple student objects, and use the program to traverse the collection in the console
Requirement: If the member variable values ​​of student objects are the same, we consider them to be the same object

import java.util.Objects;

//定义学生类
public class Student {
    
    
	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() {
    
    
		super();
	}

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

	//快捷键重写hashCode()和equals()
	@Override
	public int hashCode() {
    
    
		return Objects.hash(age, name);
	}

	@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;
		return age == other.age && Objects.equals(name, other.name);
	}

}
import java.util.HashSet;

/*
案例:HashSet集合存储学生对象并遍历
需求:创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合
要求:学生对象的成员变量值相同,我们就认为是同一个对象

*/
public class HashSetDemo2 {
    
    
	public static void main(String[] args) {
    
    
		//创建HashSet集合对象
		HashSet<Student> hs = new HashSet<Student>();

		// 创建学生对象
		Student s1 = new Student("小白", 12);
		Student s2 = new Student("小黑", 13);
		Student s3 = new Student("小红", 11);

		Student s4 = new Student("小红", 11);

		// 把学生添加到集合
		hs.add(s1);
		hs.add(s2);
		hs.add(s3);
		hs.add(s4);

		//遍历集合
		for (Student s : hs) {
    
    
			System.out.println(s.getName() + "," + s.getAge());
		}

	}
}

operation result:
insert image description here

LinkedHashSet collection overview and characteristics

LinkedHashSet collection features:

  • Set interface implemented by hash table and linked list, with predictable iteration order
  • There is a linked list to ensure that the elements are in order, that is to say, the order of storage and retrieval of elements is consistent
  • There is a hash table to ensure the uniqueness of elements, that is to say, there are no duplicate elements

LinkedHashSet Collection Practice

  • store the string and iterate over
import java.util.LinkedHashSet;

/*
LinkedHashSet集合特点:

- 哈希表和链表实现的Set接口,具有可预测的迭代次序
- 有链表保证元素有序,也就是说元素的存储和取出顺序是一致的
- 有哈希表保证元素唯一性,也就是说没有重复的元素

LinkedHashSet集合练习

- 存储字符串并遍历
*/
public class LinkedHashSetDemo {
    
    
	public static void main(String[] args) {
    
    
		//创建集合对象
		LinkedHashSet<String> lhs = new LinkedHashSet<String>();

		//添加元素
		lhs.add("hello");
		lhs.add("world");
		lhs.add("java");
		lhs.add("world");

		//遍历
		for (String s : lhs) {
    
    
			System.out.println(s);
		}

	}
}

Running results:
insert image description here
TreeSet collection overview and features

TreeSet collection features:

  • The elements are ordered. The order here does not refer to the order of storage and retrieval, but sorting according to certain rules. The specific sorting method depends on the construction method TreeSet()
    : sorting according to the natural sorting of its elements
    TreeSet (Comparator comparator): according to The specified comparator to sort
  • There is no method with an index, so you cannot use a normal for loop to traverse
  • Since it is a Set collection, it does not contain a collection of duplicate elements

TreeSet Collection Practice

  • Store integers and iterate over
import java.util.TreeSet;

/*
TreeSet集合特点:

- 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
TreeSet():根据其元素的自然排序进行排序
TreeSet(Comparator comparator):根据指定的比较器进行排序
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是Set集合,所以不包含重复元素的集合

TreeSet集合练习

- 存储整数并遍历
*/
public class TreeSetDemo {
    
    
	public static void main(String[] args) {
    
    
		//创建集合对象
		TreeSet<Integer> ts = new TreeSet<Integer>();//由于<>里要用引用类型,所以要用int的包装类Integer

		//添加元素
		ts.add(55);
		ts.add(22);
		ts.add(44);
		ts.add(33);
		ts.add(11);

		ts.add(11);//不包含重复元素

		//遍历集合
		for (int i : ts) {
    
    
			System.out.println(i);
		}
		/*运行结果:按照自然顺序从小到大排序
		11
		22
		33
		44
		55
		*/

	}
}

Running result:
insert image description here
use of natural sort Comparable

  • Store student objects and traverse, create a TreeSet collection using a no-argument construction method
  • Requirements: Sort by age from youngest to oldest, if the age is the same, sort by name alphabetically
//定义学生类
public class Student implements Comparable<Student> {
    
    
	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() {
    
    
		super();
	}

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

	@Override
	public int compareTo(Student s) {
    
    
		// TODO Auto-generated method stub
		//		return 0;//相同,不存储
		//		return 1;//存储的正序
		//		return -1;//存储的逆序

		//按照年龄从小到大排序
		int num = this.age - s.age;//这里this表示s2,s表示s1
		//		int num=s.age-this.age;//降序排列

		//年龄相同时,按照姓名的字母顺序排序
		int num2 = num == 0 ? this.name.compareTo(s.name) : num;//因为自然排序本身就可以用string类型,所以直接用s.name

		return num2;//可以保证元素的唯一性
	}

}

import java.util.TreeSet;

/*
自然排序Comparable的使用

- 存储学生对象并遍历,创建TreeSet集合使用**无参构造方法**
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
*/

public class TreeSetDemo2 {
    
    
	public static void main(String[] args) {
    
    
		//创建集合对象
		TreeSet<Student> ts = new TreeSet<Student>();

		//创建学生对象
		Student s1 = new Student("xiaobai", 12);
		Student s2 = new Student("dabai", 13);
		Student s3 = new Student("xiaohei", 14);
		Student s4 = new Student("dahei", 10);

		Student s5 = new Student("xiaohong", 10);
		Student s6 = new Student("xiaohong", 10);//元素唯一

		//学生添加到集合
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);

		//遍历集合
		for (Student s : ts) {
    
    
			System.out.println(s.getName() + "," + s.getAge());
		}
		/*运行结果:
			ClassCastException  
			因为:学生类没有实现Comparable接口
		*/

		/*运行结果:
			xiaobai,12   
			因为:此时compareTo()里返回的是0
		*/

		/*将compareTo()改为return 1
			运行结果:
				xiaobai,12
				dabai,13
				xiaohei,14
				dahei,10
			按照存储的顺序输出
		*/

		/*将compareTo()改为return -1
			运行结果:
				dahei,10
				xiaohei,14
				dabai,13
				xiaobai,12
			按照存储的顺序逆序输出
		 */

	}
}

Running results:
insert image description here
Conclusion :

  • Use the TreeSet collection to store custom objects, and the no-argument construction method uses natural sorting to sort the elements
  • Natural sorting is to let the class to which the element belongs implement the Comparable interface and rewrite the compareTo(T o) method
  • When rewriting a method, be sure to note that the collation must be written in accordance with the required primary and secondary conditions

Comparator sorting the use of Comparator

  • Store the student object and traverse it, create a TreeSet collection and use the construction method with parameters
  • Requirements: Sort by age from youngest to oldest, if the age is the same, sort by name alphabetically
//定义学生类
public class Student {
    
    
	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() {
    
    
		super();
	}

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

}
/*
*比较器排序Comparator的使用**

- 存储学生对象并遍历,创建TreeSet集合使用**带参构造方法**
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
*/

import java.util.Comparator;
import java.util.TreeSet;

public class TreeSetDemo3 {
    
    
	public static void main(String[] args) {
    
    
		//创建集合对象
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
    
    //使用匿名内部类
			@Override
			public int compare(Student s1, Student s2) {
    
    
				// TODO Auto-generated method stub
				//this.age--s.age
				//s1--s2
				int num = s1.getAge() - s2.getAge();
				int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
				return num2;
			}
		});

		//创建学生对象
		Student s1 = new Student("xiaobai", 12);
		Student s2 = new Student("dabai", 13);
		Student s3 = new Student("xiaohei", 14);
		Student s4 = new Student("dahei", 10);

		Student s5 = new Student("xiaohong", 10);
		Student s6 = new Student("xiaohong", 10);//元素唯一

		//学生添加到集合
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);

		//遍历集合
		for (Student s : ts) {
    
    
			System.out.println(s.getName() + "," + s.getAge());
		}

	}
}

Running results:
insert image description here
Conclusion:

  • Use the TreeSet collection to store custom objects, and the construction method with parameters uses comparator sorting to sort the elements
  • Comparator sorting is to let the collection construction method receive the Comparator implementation class object , and rewrite the compare(T o1, T o2) method
  • When rewriting a method, be sure to note that the collation must be written in accordance with the required primary and secondary conditions

Case: Sorting grades

Requirement: Use TreeSet collection to store multiple student information (name, Chinese grade, math grade), and traverse the collection
Requirement: Appear according to the total score from high to low

//定义学生类
public class Student {
    
    
	private String name;
	private int chinese;
	private int math;

	public String getName() {
    
    
		return name;
	}

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

	public int getChinese() {
    
    
		return chinese;
	}

	public void setChinese(int chinese) {
    
    
		this.chinese = chinese;
	}

	public int getMath() {
    
    
		return math;
	}

	public void setMath(int math) {
    
    
		this.math = math;
	}

	public Student(String name, int chinese, int math) {
    
    
		super();
		this.name = name;
		this.chinese = chinese;
		this.math = math;
	}

	public Student() {
    
    
		super();
	}

	@Override
	public String toString() {
    
    
		return "name=" + name + ", chinese=" + chinese + ", math=" + math + ", sum=" + getSum();
	}

	public int getSum() {
    
    

		return this.chinese + this.math;
	}

}
import java.util.Comparator;
import java.util.TreeSet;

/*
案例:成绩排序
需求:用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩),并遍历该集合
要求:按照总分从高到低出现
*/
public class TreeSetDemo4 {
    
    
	public static void main(String[] args) {
    
    
		//创建集合对象
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
    
    
			@Override
			public int compare(Student s1, Student s2) {
    
    
				// TODO Auto-generated method stub
				//按照总分从高到低出现
				//s---this
				//s2---s1
				//			int num=(s2.getChinese()+s2.getMath())-(s1.getChinese()+s1.getMath());
				//主要条件
				int num = s2.getSum() - s1.getSum();
				//次要条件
				int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
				int num3 = num2 == 0 ? s1.getName().compareTo(s2.getName()) : num2;

				return num3;

			}
		});

		//创建学生对象
		Student s1 = new Student("小白", 55, 66);
		Student s2 = new Student("小黑", 54, 76);
		Student s3 = new Student("小红", 67, 44);
		Student s4 = new Student("小黄", 23, 64);
		Student s5 = new Student("小蓝", 95, 78);

		Student s6 = new Student("小绿", 94, 79);//总分相同,单科成绩不同
		Student s7 = new Student("小紫", 94, 79);//总分和单科成绩都相同

		//学生添加到集合
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);
		ts.add(s7);

		//遍历集合
		for (Student s : ts) {
    
    
			System.out.println(s.toString());
		}

	}
}

operation result:
insert image description here

Case: non-repeating random numbers

Requirement: Write a program to obtain 10 random numbers between 1–20, require that the random numbers cannot be repeated, and output them on the console

import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

import hello.randomDemo;

/*
案例:不重复的随机数

需求:编写一个程序,获取10个1--20之间的随机数,要求随机数不能重复,并在控制台输出

*/
public class SetDemo2 {
    
    
	public static void main(String[] args) {
    
    
		//创建Set集合对象
		//		Set<Integer> set=new HashSet<Integer>();
		Set<Integer> set = new TreeSet<Integer>();

		//创建随机数对象
		Random r = new Random();

		//判断集合长度是否小于10
		while (set.size() < 10) {
    
    //小于10,就产生随机数添加到集合中
			int number = r.nextInt(20) + 1;
			set.add(number);
		}

		//变量集合
		for (Integer i : set) {
    
    
			System.out.println(i);
		}

	}
}

operation result:
insert image description here

Guess you like

Origin blog.csdn.net/weixin_47678894/article/details/119367343