1. 程式人生 > >HashSet的儲存和遍歷

HashSet的儲存和遍歷

1、特點

1、HashSet實現 Set 介面,由雜湊表(實際上是一個 HashMap 例項)支援。
2、它不保證 set 的迭代順序;特別是它不保證該順序恆久不變。此類允許使用 null 元素。
3、Set介面定一個不包含重複元素的 collection,HashSet的元素自然也不能重複
4、只能儲存引用型別,JDK1.5後對基本型別有了自動裝箱,會將基本型別自動轉換為其包裝類。

2、add方法分析

boolean add(E e);如果此 set 中尚未包含指定元素,則新增指定元素。
該方法底層分析:
1、首先獲取待新增元素的雜湊值(e.hashCode();),與集合中的元素的雜湊值進行比較。
2、如果集合中不存在與待新增元素雜湊值相同的元素

,則將待新增的元素,新增到集合中。(雜湊值可以理解為一塊記憶體空間,這塊記憶體裡面可能存在多個物件,所以理論上可能出現,多個物件的雜湊值相同,地址值不同的情況)
3、如果集合中存在與待新增元素雜湊值相同的元素,則呼叫equals()方法比較這兩個元素,如果不相同就新增,否則不新增
注意:如果沒有重寫equals方法,則呼叫的是Object中的equal()方法,比較這兩個元素的地址,如果地址不相同,就將待新增的元素,新增到集合中,否則不新增。
4、所以一般情況下,需要根據具體的要求重寫hashCode方法和equals方法。

3、新增String字串
Java程式碼

    public static void main(String[] args) {
        //建立集合物件
        HashSet<String> hs=new HashSet<String>();
String str1="hello"; String str2="world"; String str3="java"; String str4="hello"; System.out.println("str1的雜湊值:"+str1.hashCode()); System.out.println("str2的雜湊值:"+str2.hashCode()); System.out.println("str3的雜湊值:"+str3.hashCode()); System.out
.println("str4的雜湊值:"+str4.hashCode()); hs.add(str1); hs.add(str2); hs.add(str3); hs.add(str4); System.out.println("===================="); for (String string : hs) { System.out.println(string); } }

執行結果:

str1的雜湊值:99162322
str2的雜湊值:113318802
str3的雜湊值:3254818
str4的雜湊值:99162322
====================
world
java
hello

分析:
1、可以看出最後一個hello元素沒有進入集合,且集合中的元素順序和存入的順序不同。
2、String類重寫的hashCode方法,所以獲取雜湊值,呼叫的是String類中的hashCode方法
3、上述程式碼中看到str1和str2、str3的雜湊值互不相同,和str4的雜湊值相同,
4、集合為空,str1直接新增進入集合,
5、str1、tr2、str3互不相同,所以str2、str3、也新增到集合中,
6、str4與str3的雜湊值相同,此時呼叫String類的equals方法,比較字串的值,發現相同,不新增str4

4、新增物件

需求:儲存自定義物件,並保證元素的唯一性
要求:如果兩個物件的成員變數值都相同,則視為同一個元素

學生物件:

package com.xiaowen.demo2;

public class Student {

    private String name;
    private String age;

    public Student() {
    }

    public Student(String name, String age) {
        super();
        this.name = name;
        this.age = 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;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

}

測試類:

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

        //建立學生物件
        Student s1=new Student("小A","10");
        Student s2=new Student("小B","20");
        Student s3=new Student("小C","30");
        Student s4=new Student("小D","40");
        Student s5=new Student("小D","40");

        System.out.println("s4:"+s4.hashCode());
        System.out.println("s5:"+s5.hashCode());

        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);
        hs.add(s5);
        hs.add(s4);
        System.out.println("=========================");
        for (Student student : hs) {
            System.out.println(student);
        }   
    }

執行結果:

s4:865113938
s5:1442407170
=========================
Student [name=小D, age=40]
Student [name=小B, age=20]
Student [name=小A, age=10]
Student [name=小C, age=30]
Student [name=小D, age=40]

分析:此時會發現s4和s5的雜湊值不同,但是s4和s5的成員變數的值都相同,所以集合中出現了重複的元素(此處的重複指的是成員變數值都相同),此時呼叫的是Object中的hashCode和equals方法,所以就需要在Student類中重寫hashCode方法和equals方法。

重寫後的Student類:

package com.xiaowen.demo2;

public class Student {

    private String name;
    private String age;

    public Student() {
    }

    public Student(String name, String age) {
        super();
        this.name = name;
        this.age = 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;
    }

    @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 == 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;
    }   
}

執行結果:此時 s5沒有新增到集合中

s4:783066
s5:783066
=========================
Student [name=小D, age=40]
Student [name=小C, age=30]
Student [name=小B, age=20]
Student [name=小A, age=10]

分析:
1、重寫hashCode方法,根據成員變數的雜湊值和成員變數的值,按照一定的規則生成新的雜湊值
2、重寫equals方法,比較成員變數的值

補充:
LinkedHashSet:底層資料結構由雜湊表和連結串列組成,其特點是元素唯一且有序

相關推薦

HashSet儲存

1、特點 1、HashSet實現 Set 介面,由雜湊表(實際上是一個 HashMap 例項)支援。 2、它不保證 set 的迭代順序;特別是它不保證該順序恆久不變。此類允許使用 null 元素

集合巢狀儲存元素的示例

1 /** 2 * @Auther: lzy 3 * @Date: 2018/12/12 16:07 4 * @Description: 集合巢狀儲存和遍歷元素的示例 5 */ 6 public class ListTest { 7 public static void m

集合中的集合_儲存(增強型for迴圈迭代器)

package GuanQia3_test2_集合中套集合_第一次沒想明白; /* * 一個學科中有若干班級,每一個班級又有若干學生。整個學科一個大集合, * 若干個班級分為每一個小集合(集合巢狀之HashSet巢狀HashSet)。要求如下 * 1、 學生類有兩個屬

Java中ArrayList集合巢狀儲存

student類: package day16_Test; /* * 學生類: * 成員變數:姓名、年齡 * 成員方法 * 構造方法 * *

PAT 1138 Postorder Traversal(二叉樹的儲存

題意:給出二叉樹的前序和中序遍歷,給出其後序遍歷的第一個元素。 思路:根據前序和中序遍歷的結果得到二叉樹的具體構造,再進行後序遍歷。 程式碼: #include <cstdio> #in

圖的儲存

圖的儲存 圖的儲存一般有兩種方式:鄰接矩陣和鄰接表 鄰接矩陣 設圖G(V,E)的頂點標號為0,1,……n-1,則令二維陣列G[n][n]的兩維分別表示圖的頂點標號。 即如果G[i][j]等於1,指頂點i和頂點j之間有邊,如果G[i][j]等於0,指頂

圖的儲存C++實現

最近在做一些OJ題目時,感覺自己圖的應用還不夠熟練。所以又翻書看別人的部落格複習了一下,現把圖的常用內容總結如下: 圖的常用儲存方法有:鄰接矩陣和鄰接表 遍歷方法有:按深度遍歷(DFS),按廣度遍歷(BFS) 下面的程式碼都是C++寫的,用了一些STL庫的容器:

資料結構之 二叉樹的儲存總結

知道前序(包括空結點 下面程式碼用’,’代替)建立一個二叉樹,前序 中序 後序 層序輸出 如何求葉子結點數, 如何求二叉樹深度。 #include<stdio.h> #include<stdlib.h> #include<st

資料結構作業14—圖的概念 儲存結構

2-1若無向圖G =(V,E)中含7個頂點,要保證圖G在任何情況下都是連通的,則需要的邊數最少是: (3分) A.16 B.21 C.15 D.6 作者: DS課程組 單位: 浙江大學 2-2對於有向圖,其鄰接矩陣表示比鄰接表

資料結構作業14—圖的概念 儲存結構(判斷題)

1-1用鄰接矩陣法儲存圖,佔用的儲存空間數只與圖中結點個數有關,而與邊數無關。 (1分) T F 作者: DS課程組 單位: 浙江大學 1-2用鄰接表法儲存圖,佔用的儲存空間數只與圖中結點個數有關,而與邊數無關。 (1分) T

二維陣列的動態儲存方陣,求各元素的

#define _CRT_SECURE_NO_WARNINGS  #include<iostream> using namespace std; int **InitialArray(int row,int column)  //動態建立陣列並初始化 {int

二叉樹的儲存方式方式

二叉樹: 二叉樹的每個節點至多有兩個子樹。如這個二叉樹,其中1,2有兩個子樹,3只有左子樹,5有右子樹,4,6,7沒有子樹。 二叉樹有兩種儲存方式: 第一種,陣列表示。用陣列儲存方式就是用一組連續的儲存單元儲存二叉樹的資料元素。                      

常用資料結構-二叉樹的鏈式儲存、建立

1. 鏈式二叉樹簡介         二叉樹是資料結構——樹的一種,一般定義的樹是指有一個根節點,由此根節點向下分出數個分支結點,以此類推以至產生一堆結點。樹是一個具有代表性的非線性資料結構,所謂的非

樹的創建

樹#include <stdio.h>#include <stdlib.h>struct node{ char data; struct node* left; struct node* right;};void preorder(struct node* root)

數據結構與算法第10周作業——二叉樹的創建算法

技術分享 truct order traverse eof 結構 後序遍歷 lib void 一、二叉樹的創建算法(遞歸方式) 二、二叉樹的先序、中序和後序遍歷算法 #include<stdio.h>#include<stdlib.h>typedef

數據結構-第10周作業(二叉樹的創建算法)

樹的創建 創建 -1 數據結構 二叉 分享 com jpg 遍歷算法 數據結構-第10周作業(二叉樹的創建和遍歷算法)

數據結構學習筆記(五) 樹的創建

一個 後序遍歷 for -1 堆棧 nor ext cnblogs 復制 創建(先序創建和根據先序和中序進行創建)和遍歷(先序遍歷、中序遍歷、後序遍歷、非遞歸堆棧遍歷、層次遍歷):    package tree; public class XianCreateTree

Jsoup解析一個HTML文檔(二)

spl nodes gif .org code htm ips method spa 關於Eclipse編輯器匯總console中字體調整: 1,下載jsoup的jar包:http://jsoup.org/download 2, jsoup英文的開發手冊:http:

線索二叉樹的構建------小甲魚數據結構算法

-- tag typedef pre == 約定 cnblogs amp scan #include <stdio.h> #include <stdlib.h> typedef char ElemType; // 線索存儲標誌位 // Link

二叉樹建立

mil inorder 推斷 microsoft con 是否 font pac node 二叉樹創建遍歷規則: 1.先序:根-左-右 2.中序:左-根-右 3.後序:左-右-根 二叉樹定義和輔助函數例如以下: struct node {