목차
2. 내부 해싱: 해시 매핑 기술 " >2. 내부 해싱: 해시 매핑 기술
3. 지도 최적화 " >3. 지도 최적화
" >3.1 구현 크기 조정
3.2、负载因子" >3.2、负载因子
最后" >最后
Java java지도 시간 Java 개선 장(33)------맵 요약

Java 개선 장(33)------맵 요약

Feb 11, 2017 am 10:24 AM

앞서 LZ는 HashMap, HashTable, TreeMap의 구현 방법을 자세히 소개하면서 데이터 구조, 구현 원리, 소스 코드 분석이라는 세 가지 측면을 자세히 설명했습니다. 아래 LZ는 Map에 대한 간략한 요약을 제공합니다.

추천 도서:

Java 개선 장(부분) 2) 3) —-HashMap

                                                           >

 Java 개선 장(26)----hashCode

Java 개선 장(27)—TreeMap1. 맵 개요

먼저 Map의 구조도를 살펴보세요


맵: "키-값" 매핑을 위한 추상 인터페이스입니다. 맵에는 중복 키가 포함되지 않으며 하나의 키는 하나의 값에 해당합니다.

     SortedMap: Map 인터페이스를 상속하는 정렬된 키-값 쌍 인터페이스입니다.

    NavigableMap: 은 SortedMap을 상속하며 지정된 검색 대상 인터페이스에 가장 가까운 일치 항목을 반환하는 탐색 메서드가 있습니다. .

    AbstractMap: 은 Map의 대부분의 기능적 인터페이스를 구현합니다. "Map 구현 클래스"의 반복 코딩을 줄입니다.

    사전: 키를 해당 값에 매핑하는 모든 클래스의 추상 상위 클래스입니다. 현재는 Map 인터페이스로 대체되었습니다.

       TreeMap: Ordered 해시 테이블, SortedMap 인터페이스 구현, 하단 레이어는 빨간색을 통해 구현 -검은 나무.

     HashMap: 은 "zipper 방식"을 기반으로 구현된 해시 테이블입니다. 맨 아래 레이어는 "배열 + 연결리스트"를 사용하여 구현됩니다.

    WeakHashMap: "zipper 방식"을 기반으로 구현된 해시 테이블입니다.

     HashTable: "zipper 방식"을 기반으로 구현된 해시 테이블입니다.

요약은 다음과 같습니다.


 

차이점:

2. 내부 해싱: 해시 매핑 기술

               거의 모든 일반 지도는 해시 매핑 기술을 사용합니다. 우리 프로그래머들은 그것을 이해해야 합니다.

          해시 매핑 기술은 요소를 배열로 매핑하는 매우 간단한 기술입니다. 해시 맵은 배열 결과를 사용하므로 임의의 키로 배열에 대한 액세스를 결정하기 위한 인덱싱 메커니즘이 있어야 합니다. 이 메커니즘은 배열 크기보다 작은 정수를 제공할 수 있습니다. 이 메커니즘을 해시 함수라고 부릅니다. Java에서는 그러한 정수를 찾는 것에 대해 걱정할 필요가 없습니다. 모든 객체에는 정수 값을 반환하는 hashCode 메서드가 있어야 하고, 우리가 해야 할 일은 정수로 변환한 다음 그 값을 배열로 나누는 것뿐입니다. 크기에서 나머지를 가져옵니다.

int hashValue = Maths.abs(obj.hashCode()) % size;
로그인 후 복사

다음은 HashMap과 HashTable입니다.

----------HashMap------------
//计算hash值
static int hash(int h) {
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}
//计算key的索引位置
static int indexFor(int h, int length) {
        return h & (length-1);
}
-----HashTable--------------
int index = (hash & 0x7FFFFFFF) % tab.length;     //确认该key的索引位置
로그인 후 복사

위치의 인덱스는 배열 내 노드의 위치를 ​​나타냅니다. 다음 그림은 해시 매핑의 기본 원리 다이어그램입니다.


이 그림에서 1~4단계는 해당 요소를 찾는 것입니다. 배열 위치, 5~8단계는 요소를 배열에 삽입하는 것입니다. 삽입 과정에서 약간의 좌절감이 있을 것입니다. 동일한 해시 값을 가진 여러 요소가 있을 수 있으므로 동일한 인덱스 위치를 갖게 됩니다. 이는 여러 요소가 동일한 위치에 매핑된다는 의미입니다. 이 프로세스를 "충돌"이라고 합니다. 충돌을 해결하는 방법은 인덱스 위치에 연결 목록을 삽입하고 이 연결 목록에 요소를 추가하는 것입니다. 물론, 단순한 삽입은 아니고, HashMap의 처리 과정은 다음과 같습니다: 연결된 리스트가 null이면 해당 요소를 직접 삽입합니다. 키와 동일합니다. 존재하는 경우 원래 키의 값을 덮어쓰고 이전 값을 반환합니다. 그렇지 않으면 요소가 체인의 선두에 저장됩니다(저장된 첫 번째 요소는 체인의 끝에 배치됩니다). . 다음은 HashMap의 put 메소드로, 인덱스 위치를 계산하여 해당 요소를 적절한 위치에 삽입하는 전체 과정을 자세히 보여줍니다.

public V put(K key, V value) {
        //当key为null,调用putForNullKey方法,保存null与table第一个位置中,这是HashMap允许为null的原因
        if (key == null)
            return putForNullKey(value);
        //计算key的hash值
        int hash = hash(key.hashCode());                 
        //计算key hash 值在 table 数组中的位置
        int i = indexFor(hash, table.length);            
        //从i出开始迭代 e,判断是否存在相同的key
        for (Entry<K, V> e = table[i]; e != null; e = e.next) {
            Object k;
            //判断该条链上是否有hash值相同的(key相同)
            //若存在相同,则直接覆盖value,返回旧value
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;    //旧值 = 新值
                e.value = value;
                e.recordAccess(this);
                return oldValue;     //返回旧值
            }
        }
        //修改次数增加1
        modCount++;
        //将key、value添加至i位置处
        addEntry(hash, key, value, i);
        return null;
    }
로그인 후 복사

HashMap의 put 메소드는 해시 매핑의 기본 개념을 보여줍니다. 사실 다른 맵을 보면 원리가 비슷하다는 것을 알 수 있습니다!

3. 지도 최적화

                         크기는 1에 불과하며 모든 요소는 이 위치(0)에 매핑됩니다. ), 따라서 더 긴 연결 목록을 형성합니다. 업데이트하고 접근할 때 이 연결된 목록에 대해 선형 검색을 수행해야 하므로 필연적으로 효율성이 떨어집니다. 매우 큰 배열이 있고 연결된 목록의 각 위치에 하나의 요소만 있는 경우 액세스할 때 인덱스 값을 계산하여 객체를 얻을 것이라고 가정합니다. 이렇게 하면 검색 효율성이 향상되지만 낭비가 됩니다. 제어. 물론 이 두 가지 방법은 극단적이지만 최적화 아이디어를 제공합니다. 요소가 고르게 분산될 수 있도록 더 큰 배열을 사용합니다. 맵에는 효율성에 영향을 미치는 두 가지 요소가 있습니다. 하나는 컨테이너의 초기 크기이고 다른 하나는 로드 요소입니다.

3.1 구현 크기 조정

"버킷"으로서 사용 가능한 버킷 수(즉, 크기 내부 배열의)을 용량이라고 합니다. Map 개체가 여러 요소를 효과적으로 처리할 수 있도록 Map 자체 크기를 조정할 수 있도록 설계했습니다. 맵의 요소가 특정 양에 도달하면 컨테이너 자체의 크기가 조정되지만 이 크기 조정 프로세스에는 비용이 매우 많이 듭니다. 크기를 조정하려면 원래 요소를 모두 새 배열에 삽입해야 합니다. 우리는 인덱스 = hash(key) % 길이를 알고 있습니다. 이로 인해 원래 충돌하는 키가 더 이상 충돌하지 않고 충돌하지 않는 키가 이제 충돌하게 됩니다. 재계산, 조정 및 삽입 프로세스는 비용이 많이 들고 비효율적입니다. 따라서 지도의 예상 크기를 알기 시작하고 지도의 크기를 충분히 크게 조정하면 크기 조정의 필요성을 크게 줄이거나 아예 없앨 수 있어 속도가 향상될 가능성이 높습니다. 다음은 HashMap이 컨테이너 크기를 조정하는 과정입니다. 다음 코드를 통해 확장 과정의 복잡성을 확인할 수 있습니다.

void resize(int newCapacity) {
            Entry[] oldTable = table;    //原始容器
            int oldCapacity = oldTable.length;    //原始容器大小
            if (oldCapacity == MAXIMUM_CAPACITY) {     //是否超过最大值:1073741824
                threshold = Integer.MAX_VALUE;
                return;
            }

            //新的数组:大小为 oldCapacity * 2
            Entry[] newTable = new Entry[newCapacity];    
            transfer(newTable, initHashSeedAsNeeded(newCapacity));
            table = newTable;
           /*
            * 重新计算阀值 =  newCapacity * loadFactor >  MAXIMUM_CAPACITY + 1 ? 
            *                         newCapacity * loadFactor :MAXIMUM_CAPACITY + 1
            */
            threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);   
        }
        
        //将元素插入到新数组中
        void transfer(Entry[] newTable, boolean rehash) {
            int newCapacity = newTable.length;
            for (Entry<K,V> e : table) {
                while(null != e) {
                    Entry<K,V> next = e.next;
                    if (rehash) {
                        e.hash = null == e.key ? 0 : hash(e.key);
                    }
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                }
            }
        }
로그인 후 복사

3.2、负载因子

         为了确认何时需要调整Map容器,Map使用了一个额外的参数并且粗略计算存储容器的密度。在Map调整大小之前,使用”负载因子”来指示Map将会承担的“负载量”,也就是它的负载程度,当容器中元素的数量达到了这个“负载量”,则Map将会进行扩容操作。负载因子、容量、Map大小之间的关系如下:负载因子 * 容量 > map大小  ----->调整Map大小。

         例如:如果负载因子大小为0.75(HashMap的默认值),默认容量为11,则 11 * 0.75 = 8.25 = 8,所以当我们容器中插入第八个元素的时候,Map就会调整大小。

        负载因子本身就是在控件和时间之间的折衷。当我使用较小的负载因子时,虽然降低了冲突的可能性,使得单个链表的长度减小了,加快了访问和更新的速度,但是它占用了更多的控件,使得数组中的大部分控件没有得到利用,元素分布比较稀疏,同时由于Map频繁的调整大小,可能会降低性能。但是如果负载因子过大,会使得元素分布比较紧凑,导致产生冲突的可能性加大,从而访问、更新速度较慢。所以我们一般推荐不更改负载因子的值,采用默认值0.75.

最后

        推荐阅读:

        java提高篇(二三)—–HashMap

        java提高篇(二五)—–HashTable

        Java提高篇(二六)-----hashCode

        Java提高篇(二七)—–TreeMap

 


以上就是Java提高篇(三三)-----Map总结的内容,更多相关内容请关注PHP中文网(www.php.cn)!


본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. 크로스 플레이가 있습니까?
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

자바의 완전수 자바의 완전수 Aug 30, 2024 pm 04:28 PM

Java의 완전수 가이드. 여기서는 정의, Java에서 완전 숫자를 확인하는 방법, 코드 구현 예제에 대해 논의합니다.

자바의 웨카 자바의 웨카 Aug 30, 2024 pm 04:28 PM

Java의 Weka 가이드. 여기에서는 소개, weka java 사용 방법, 플랫폼 유형 및 장점을 예제와 함께 설명합니다.

Java의 스미스 번호 Java의 스미스 번호 Aug 30, 2024 pm 04:28 PM

Java의 Smith Number 가이드. 여기서는 정의, Java에서 스미스 번호를 확인하는 방법에 대해 논의합니다. 코드 구현의 예.

Java Spring 인터뷰 질문 Java Spring 인터뷰 질문 Aug 30, 2024 pm 04:29 PM

이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Feb 07, 2025 pm 12:09 PM

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

Java의 날짜까지의 타임스탬프 Java의 날짜까지의 타임스탬프 Aug 30, 2024 pm 04:28 PM

Java의 TimeStamp to Date 안내. 여기서는 소개와 예제와 함께 Java에서 타임스탬프를 날짜로 변환하는 방법에 대해서도 설명합니다.

캡슐의 양을 찾기위한 Java 프로그램 캡슐의 양을 찾기위한 Java 프로그램 Feb 07, 2025 am 11:37 AM

캡슐은 3 차원 기하학적 그림이며, 양쪽 끝에 실린더와 반구로 구성됩니다. 캡슐의 부피는 실린더의 부피와 양쪽 끝에 반구의 부피를 첨가하여 계산할 수 있습니다. 이 튜토리얼은 다른 방법을 사용하여 Java에서 주어진 캡슐의 부피를 계산하는 방법에 대해 논의합니다. 캡슐 볼륨 공식 캡슐 볼륨에 대한 공식은 다음과 같습니다. 캡슐 부피 = 원통형 볼륨 2 반구 볼륨 안에, R : 반구의 반경. H : 실린더의 높이 (반구 제외). 예 1 입력하다 반경 = 5 단위 높이 = 10 단위 산출 볼륨 = 1570.8 입방 단위 설명하다 공식을 사용하여 볼륨 계산 : 부피 = π × r2 × h (4

Spring Tool Suite에서 첫 번째 Spring Boot 응용 프로그램을 실행하는 방법은 무엇입니까? Spring Tool Suite에서 첫 번째 Spring Boot 응용 프로그램을 실행하는 방법은 무엇입니까? Feb 07, 2025 pm 12:11 PM

Spring Boot는 강력하고 확장 가능하며 생산 가능한 Java 응용 프로그램의 생성을 단순화하여 Java 개발에 혁명을 일으킨다. Spring Ecosystem에 내재 된 "구성에 대한 협약"접근 방식은 수동 설정, Allo를 최소화합니다.

See all articles