1. 程式人生 > >黑馬程式設計師-集合-Set和Map和Collections

黑馬程式設計師-集合-Set和Map和Collections

第一講 Set

1.      Set介面的概述

不包含重複的元素,無序(儲存和取出的順序不一樣)。和collection的功能是一樣的,無特殊。

|--HashSet: HashSet底層資料結構是雜湊表,保證元素唯一性的原理是:判斷元素的hashCode()是否相同,相同就判斷equalis()方法是否為true;不保證Set的迭代順序。

|--TreeSet: TreeSet 底層是二叉樹結構,元素是唯一,有序的(按照某種規則排序)

2.      HashSet

HashSet中和元素唯一性相關的操作都依賴於hashCode()和euqals()方法

如add()方法的原始碼可知

步驟:比較雜湊值

                             相同:比較地址值或equals()

                                                         相同:不新增

                                                         不同:新增到集合中

                             不同:新增到集合中

注意:String重寫了hashCode()和equals()方法,所以內容相同的會直接去掉

示例:HashSet儲存自定義物件並遍歷

//先是宣告一個學生類Student.java,兩個成員變數,名字和年齡
public class Student {
private String name;
private int age;
 
public Student() {
           super();
}
 
public Student(String name, int age) {
           super();
           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;
}
 
//重寫hashCode和equals
@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;
}
}

在HashSetDemo.java中遍歷

public class HashSetDemo{
	public static void main(String[] args) {
		// 建立集合物件
		HashSet<Student> hs = new HashSet<Student>();

		// 建立學生物件
		Student s1 = new Student("林青霞", 27);
		Student s2 = new Student("柳巖", 22);
		Student s3 = new Student("王祖賢", 30);
		Student s4 = new Student("林青霞", 27);
		Student s5 = new Student("林青霞", 20);
		Student s6 = new Student("范冰冰", 22);

		// 新增元素
		hs.add(s1);
		hs.add(s2);
		hs.add(s3);
		hs.add(s4);
		hs.add(s5);
		hs.add(s6);

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


3.      TreeSet

TreeSet的特點是唯一,有序的,有序是指讓元素按照某種規則排序

規則分為兩種,自然排序和比較器排序。

TreeSet的底層是依賴於二叉樹中的紅黑樹

3.1   紅黑樹---一種自平衡的二叉查詢樹

 

3.2   TreeSet的排序規則—自然排序

自然排序是讓元素本身具備比較性,所比較的元素的類實現實現Comparable介面,覆蓋compareTo()方法。

如果返回值為0,則表示此物件等於指定物件,所以排序後儲存其中之一

返回值為正數,則此物件大於指定物件;返回值為負數,則此物件小於指定物件

Student.java

/*
 * 如果一個類的元素要想能夠進行自然排序,就必須實現自然排序介面
 */
public class Student implements Comparable<Student> {
	private String name;
	private int age;

	public Student() {
		super();
	}

	public Student(String name, int age) {
		super();
		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 int compareTo(Student s) {
	        // 這裡返回什麼,其實應該根據排序規則來做
		// 按照年齡排序,主要條件
		int num = this.age - s.age;
		// 次要條件
		// 年齡相同的時候,還得去看姓名是否也相同
		// 如果年齡和姓名都相同,才是同一個元素
		int num2 = num == 0 ? this.name.compareTo(s.name) : num;
		return num2;
	}
}
TreeSetDemo.java
public class TreeSetDemo {
	public static void main(String[] args) {
		// 建立集合物件
		TreeSet<Student> ts = new TreeSet<Student>();

		// 建立元素
		Student s1 = new Student("linqingxia", 27);
		Student s2 = new Student("zhangguorong", 29);
		Student s3 = new Student("wanglihong", 23);
		Student s4 = new Student("linqingxia", 27);
		Student s5 = new Student("liushishi", 22);
		Student s6 = new Student("wuqilong", 40);
		Student s7 = new Student("fengqingy", 22);

		// 新增元素
		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.getName() + "---" + s.getAge());
		}
	}
}

顯示結果:



3.3  TreeSet的排序規則—比較器排序

 集合自身具備比較性。  在集合初始化時,定義一個比較器,將比較器物件作為引數傳遞給TreeSet集合的建構函式。也可以定義一個類,實現Comparator介面,覆蓋compare()方法

我們使用的是直接將比較器物件作為引數傳遞給TreeSet集合的建構函式

public class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {

			@Override
			public int compare(Student s1, Student s2) {
				// 姓名長度
				int num = s1.getName().length() - s2.getName().length();
				// 姓名內容
				int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
						: num;
				// 年齡
				int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
				return num3;
			}
		});

		// 建立元素
		Student s1 = new Student("linqingxia", 27);
		Student s2 = new Student("zhangguorong", 29);
		Student s3 = new Student("wanglihong", 23);
		Student s4 = new Student("linqingxia", 27);
		Student s5 = new Student("liushishi", 22);
		Student s6 = new Student("wuqilong", 40);
		Student s7 = new Student("fengqingy", 22);
		Student s8 = new Student("linqingxia", 29);

		// 新增元素
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);
		ts.add(s7);
		ts.add(s8);

		// 遍歷
		for (Student s : ts) {
			System.out.println(s.getName() + "---" + s.getAge());
		}
	}
}

結果顯示:符合設定的規定,先比較姓名長度,再比較年齡大小都是按照升序排序

         wuqilong---40

         fengqingy---22

         liushishi---22

         linqingxia---27

         linqingxia---29

         wanglihong---23

   zhangguorong---29

第二講 Map

1.   Map概述

Map<K,V>介面儲存鍵值對的元素,其中K代表的是鍵,V代表的是值,K是唯一的,不可重複的。

鍵與值的關係:

將鍵對映到值的物件,一個對映不能包含重複的鍵,每個鍵最多隻能對映到同一個值

注意:Map集合的資料結構針對鍵有效,跟值無關

2.  Map的功能

1:新增功能

 V put(Kkey,V value):新增元素。

 如果鍵是第一次儲存,就直接儲存元素,返回null

 如果鍵不是第一次存在,就用值把以前的值替換掉,返回以前的值

2:刪除功能

 voidclear():移除所有的鍵值對元素

 Vremove(Object key):根據鍵刪除鍵值對元素,並把值返回

3:判斷功能

 booleancontainsKey(Object key):判斷集合是否包含指定的鍵

 booleancontainsValue(Object value):判斷集合是否包含指定的值

 booleanisEmpty():判斷集合是否為空

4:獲取功能

 Set<Map.Entry<K,V>>entrySet():獲取map所有鍵值對

 Vget(Object key):根據鍵獲取值

 Set<K> keySet():獲取集合中所有鍵的集合

 Collection<V> values():獲取集合中所有值的集合

5:長度功能

      intsize():返回集合中的鍵值對的對數

3.   集合的兩種遍歷方式

3.1   通過鍵找值:

思路:A:獲取所有的鍵

               B:遍歷鍵的集合,獲取得到每一個鍵

       C:根據鍵去找值

public class MapDemo3 {
	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();

		// 建立元素並新增到集合
		map.put("楊過", "小龍女");
		map.put("郭靖", "黃蓉");
		map.put("楊康", "穆念慈");
		map.put("陳玄風", "梅超風");

		Set<String> set = map.keySet();
		for (String s : set) {
			String value = map.get(s);
			System.out.println(s + "---" + value);
		}
	}
}

注意:為什麼通過Set儲存鍵集合,因為Set集合具有唯一性的特點,且Set具備迭代器。所以可以通過迭代方式取出鍵,再通過get方法,獲取每一個鍵對應的值。

3.2  鍵值對形式

思路:

A:獲取所有鍵值對物件的集合

B:遍歷鍵值對物件的集合,得到每一個鍵值對物件

         C:根據鍵值對物件獲取鍵和值

public class MapDemo4 {
	public static void main(String[] args) {

		// 建立集合物件
		Map<String, String> map = new HashMap<String, String>();

		// 建立元素並新增到集合
		map.put("楊過", "小龍女");
		map.put("郭靖", "黃蓉");
		map.put("楊康", "穆念慈");
		map.put("陳玄風", "梅超風");

		Set<Map.Entry<String, String>> set = map.entrySet();
		for (Map.Entry<String, String> me : set) {
			String key = me.getKey();
			String value = me.getValue();
			System.out.println(key + "---" + value);
		}
	}
}

4.    HashMap:

HashMap是基於雜湊表的Map介面實現,雜湊表的作用是保證鍵的唯一性

HashMap<K,V>,如果K為引用型別,需要重寫內部的equals()和hashCode()方法

示例:一個引用型別的遍歷

public class Student {
//省略部分程式碼
@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;
	}

}

測試程式碼

public class HashMapDemo4 {
	public static void main(String[] args) {

		// 建立集合物件
		HashMap<Student, String> hm = new HashMap<Student, String>();

		// 建立學生物件
		Student s1 = new Student("貂蟬", 27);
		Student s2 = new Student("王昭君", 30);
		Student s3 = new Student("西施", 33);
		Student s4 = new Student("楊玉環", 35);
		Student s5 = new Student("貂蟬", 27);
		// 新增元素
		hm.put(s1, "8888");
		hm.put(s2, "6666");
		hm.put(s3, "5555");
		hm.put(s4, "7777");
		hm.put(s5, "9999");

		Set<Student> set = hm.keySet();
		for (Student key : set) {
			String value = hm.get(key);
			System.out.println(key.getName() + "---" + key.getAge() + "---"
					+ value);
		}

	}
}

測試結果:重複的值根本就沒有儲存在map中

 

5.  TreeMap

TreeMap的鍵是紅黑樹結構,保證鍵的排序性和唯一性

依舊是兩種排序方式:自然排序和比較器排序

示例:比較器排序

public class TreeMapDemo2 {
	public static void main(String[] args) {
		TreeMap<Student, String> tm = new TreeMap<Student, String>(
				new Comparator<Student>() {

					@Override
					public int compare(Student s1, Student s2) {
						// 主要條件
						int num = s1.getAge() - s2.getAge();
						// 次要條件
						int num2 = num == 0 ? s1.getName().compareTo(
								s2.getName()) : num;
						return num2;
					}

				});
		// 建立學生物件
		Student s1 = new Student("潘安", 30);
		Student s2 = new Student("柳下惠", 35);
		Student s3 = new Student("唐伯虎", 33);
		Student s4 = new Student("燕青", 32);
		Student s5 = new Student("唐伯虎", 33);

		// 儲存元素
		tm.put(s1, "宋朝");
		tm.put(s2, "元朝");
		tm.put(s3, "明朝");
		tm.put(s4, "清朝");
		tm.put(s5, "漢朝");
		
		Set<Student> set = tm.keySet();
		for(Student key:set){
			String value = tm.get(key);
			System.out.println(key.getName() + "---" + key.getAge() + "---"
					+ value);
		}
	}
}
測試結果:可以看出“唐伯虎--33”元素並沒有重複

第三講 Collections

1. Collections類概述

針對集合操作的工具類,都是靜態方法

2. 需要掌握的方法

  要知道的方法
  public static <T> void sort(List<T> list):排序 預設情況下是自然順序。
  public static <T> int binarySearch(List<?> list,T key):二分查詢
  public static <T> T max(Collection<?> coll):最大值
  public static void reverse(List<?> list):反轉
  public static void shuffle(List<?> list):隨機置換,每調一次,元素的位置隨機換一次

示例:Collections類針對自定義物件的排序

/*
 * Collections可以針對ArrayList儲存自定義物件的元素排序
 */
public class CollectionsDemo {
	public static void main(String[] args) {
		// 建立集合物件
		List<Student> list = new ArrayList<Student>();

		// 建立學生物件
		Student s1 = new Student("林青霞", 27);
		Student s2 = new Student("風清揚", 30);
		Student s3 = new Student("劉曉曲", 28);
		Student s4 = new Student("武鑫", 29);
		Student s5 = new Student("林青霞", 27);

		// 新增元素物件
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);

		// 排序
		// 自然排序
		// Collections.sort(list);
		// 比較器排序
		// 如果同時有自然排序和比較器排序,以比較器排序為主
		Collections.sort(list, new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				int num = s2.getAge() - s1.getAge();
				int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
						: num;
				return num2;
			}
		});

		// 遍歷集合
		for (Student s : list) {
			System.out.println(s.getName() + "---" + s.getAge());
		}
	}
}