해시 테이블을 이해하려고합니다-누군가 나에게 설명 할 수 있습니까?


25

PHP (미안)에서 해시 테이블의 올바른 사용 및 구현을 이해하고 싶습니다.

경험이없는 프로그래머가 해시 테이블을 만든 다음 반복했습니다. 이제는 왜 이것이 잘못되었는지 이해하지만 내 이해가 올바른지 알 수있는 충분한 지식을 얻지 못했습니다 (내가 무슨 뜻인지 아는 경우).

그래서 누군가 PHP에서 해시 테이블 (어쩌면 연관 배열)을 구현하는 방법과 더 중요한 것은 '해시로'값에 액세스하는 방법과 실제로 의미하는 것을 나에게 설명 할 수 있습니까?

답변:


37

간단한 해시 테이블 개요

리프레셔로서 해시 테이블은 데이터 구조의 특정 키 아래에 값을 저장하는 방법입니다. 예를 들어, "a"key 아래에 value 를 저장 1한 다음 1해시 테이블에서 키 를 찾아서 검색 할 수 있습니다.

내 머리 꼭대기에서 생각할 수있는 해시 테이블의 가장 간단한 예는 정수만 저장할 수있는 해시 테이블입니다. 여기서 해시 테이블 항목의 키도 저장되는 값입니다. 테이블의 크기가 8이며 기본적으로 메모리의 배열이라고 가정 해 봅시다.

---------------------------------
|   |   |   |   |   |   |   |   |
---------------------------------
  0   1   2   3   4   5   6   7  

해시 기능

해시 함수는 값을 저장할 위치에 대한 색인을 제공합니다. 이 테이블의 매우 간단한 해시 함수는 저장하려는 값에 1을 추가 한 다음 모드 8 (테이블 크기)하여. 즉, 해시 함수는입니다 (n+1)%8. 여기서 n저장하려는 정수입니다.

인서트

이 해시 테이블에 값을 삽입하려면 삽입하려는 값에 대해 해시 함수 (이 경우 (n+1)%8) 를 호출하여 색인을 제공합니다. 예를 들어 14를 삽입하려면 (14 + 1) % 8index를 호출 하여 index 7에 값을 삽입합니다.7 .

---------------------------------
|   |   |   |   |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

마찬가지로 33, 82 및 191을 다음과 같이 삽입 할 수 있습니다.

---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

충돌

그러나 항목과 충돌하는 것을 삽입하려고하면 어떻게됩니까? 2 인덱스로 이동3 하지만,이 문제를 해결하기 위해 여러 가지 방법이 있습니다 (82)에 의해 촬영, 간단한 우리가 빈 공간을 찾을 때까지 반복 또 다시 우리의 해시 함수를 호출하는 것입니다.

논리는 다음과 같습니다.

  1. (2 + 1) % 8 = 3
  2. 색인 3 이 가득 찼습니다
  3. 플러그 3 우리 해시 함수로 다시. ( 3 + 1) % 8 = 4 이며 비어 있습니다.
  4. 우리의 가치를 지수 4에 두십시오 .

이제 해시 테이블은 다음과 같이 표시되며 값 2는 index에 저장됩니다 4.

---------------------------------
|191|   |33 |82 |2  |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

이 솔루션의 단점은 곧 테이블이 가득 찰 것입니다! 데이터 크기가 제한되어 있다는 것을 알고 있다면 테이블이 가능한 모든 값을 보유 할 수있을 정도로 큰 경우에는 문제가되지 않습니다. 더 많이 잡으려면 충돌을 다르게 처리 할 수 ​​있습니다. 2를 삽입하기 전에 원래 위치로 되돌아 갑시다.

---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

당신이 기억한다면, (2+1)%8우리에게 index를 제공합니다 3. 해시 테이블을 채우지 않으려면 각 테이블 인덱스를 연결된 목록으로 사용하고 해당 인덱스의 목록에 추가 할 수 있습니다. 따라서 해시 함수를 다시 호출하는 대신 index의 목록에 간단히 추가합니다 3.

            -----
            | 2 |
---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

이 목록은 메모리가 허용하는만큼 커질 수 있습니다. 18을 삽입 할 수 있으며 2에 추가됩니다.

            -----
            |18 |
            -----
            | 2 |
---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

조회

해시 테이블의 크기가 상당히 크면 해시 테이블의 값을 빠르게 찾을 수 있습니다. 해시 함수를 호출하고 색인을 얻으십시오. 82이 테이블에 있는지 확인하고 싶다고 가정 해 봅시다. lookup 함수는 (82+1)%8=를 호출 3하고 index의 항목을보고 3반환합니다. 16을 조회하면 조회 기능이 색인에서 찾습니다.1 존재하지 않는지 확인합니다.

조회도 충돌을 처리해야합니다!

값 2를 찾으려고하면 해시 테이블은 데이터를 검색 할 때 데이터를 저장하는 데 사용한 것과 동일한 충돌 논리를 사용해야합니다. 해시 테이블의 작동 방식에 따라 원하는 항목을 찾을 때까지 (또는 공백을 찾을 때까지) 키를 계속 해시하거나 항목을 찾을 때까지 연결된 목록을 반복합니다 (또는 목록의 끝에 도착)

개요

따라서 해시 테이블은 키-값 쌍을 빠르게 저장하고 액세스하는 좋은 방법입니다. 이 예에서는 값과 동일한 키를 사용했지만 실제 해시 테이블에서는 키가 그렇게 제한되지 않았습니다. 해시 함수는 키에서 작동하여 인덱스를 생성 한 다음 해당 인덱스에 키 / 값을 저장할 수 있습니다. 해시 테이블은 실제로 반복 될 수는 없지만 그렇게 할 수는 있습니다. 보시다시피, 해시 테이블은 많은 빈 공간을 가질 수 있으며,이를 반복하는 것은 시간 낭비입니다. 해시 테이블에 반복자에서 빈 공간 조회를 건너 뛰는 논리가 있더라도 링크 된 목록과 같이 반복 자용으로 설계된 데이터 구조를 사용하는 것이 더 적합합니다.


2
아스키 아트 FTW!
Anto

2
좋은 대답입니다. 각 인덱스가 연결된 목록 인 방법을 연결이라고합니다.
alexn

+1 훌륭한 답변. 거의 모든 의혹이 내 머리에서 튀어 나왔다. 한 가지 더 질문해야합니다. 모든 구현에서 해싱을 사용하여 정수를 저장합니까? 또는 특정 경우에 사용됩니까? 그렇다면, 그 경우는 무엇입니까?
0decimal0

@ PHIfounder 귀하의 질문을 완전히 이해했는지 잘 모르겠지만 키에서 수행되는 해시 함수는 정수와 같은 특정 데이터 유형에만 적용되는 것이 아니라 일반적인 것으로 설계되었습니다. C 코드에 관해 이야기한다면, 해시 테이블은 키와 값을 (void *) 수락하고 키의 포인터 값에 대한 해시 계산을 수행하도록 설계 될 수 있습니다.
Jeff

@Jeff 사실 나는 이것을 묻는 바보 일지 모르지만 컴퓨터의 내부 구조에 대해 이야기하고있다. 모든 컴퓨터가 해시 테이블과 같은 데이터 구조를 사용하여 상점이 정수를 참조하는지 저장하는지 여부
0decimal0

7

수천 권의 책이있는 도서관을 상상해보십시오. 제목별로 책을 최대한 빨리 찾을 수 있도록 책을 정리해야합니다.

이 작업을 수행하는 한 가지 일반적인 방법은 책을 사전 순으로 정렬하는 것입니다. 제목이 "G"로 시작하면 "G"영역을 찾은 다음 두 번째 문자를 찾아 "ö", "d", "e", "l", 검색 범위를 좁히십시오. 책을 찾을 때까지 그러나 새로운 책이 도착하면 새로운 도착을위한 공간을 마련하기 위해 레이아웃을 재구성해야 할 때가 있습니다.

이진 검색입니다. 좋아요

그러나이를 수행하는 더 빠른 방법이 있습니다. 모든 책장과 선반을 열거 한 다음 각 책마다 책을 찾을 수있는 책장 / 선반에 매핑되는 특별하고 희망적인 고유 번호를 계산한다고 가정 해 봅시다. "키"를 계산하는 방법은 무작위로 보이는 숫자를 제공하는 한 중요하지 않습니다. 예를 들어 제목에 모든 문자의 문자 코드를 추가 한 다음 소수로 나눌 수 있습니다 (가장 좋은 방법은 아니지만 어쨌든 작동합니다).

해싱입니다. 제목의 다음 글자를 찾는 전체 책장과 선반을 거치지 않아도되므로 훨씬 빠릅니다. 둘 이상의 책이 같은 키로 해석 될 때 "충돌"이 없으면 해싱은 일반적으로 원샷 작업입니다. 그러나 그것은 괜찮습니다. 해시 함수의 품질에 따라 같은 키 아래에 너무 많으면 안됩니다.

해시 테이블에는 몇 가지 제한 사항과 변덕 (재해 싱 / 크기 조정)이있어 바이너리 검색을 실행 가능한 경쟁자로 유지합니다. 어떤 방법이 더 나은지 흑백이 아닙니다. 그러나 그것은 다른 이야기입니다.

추신 : 귀하의 질문에 직접 대답하지 않아서 죄송합니다 (PHP로 해시 테이블 작성). 자세한 내용은 "programming";)


2
컴퓨터 관련 문제에 대한 비 컴퓨터 관련 설명을 좋아합니다. +1
gablin

1

내가 아는 한 PHP의 해시 테이블은 단순히 다음을 통해 구현됩니다.

$my_hash = array(
    1 => "Bob",
    2 => "Alice",
    3 => "Jack"
);

그런 다음 다음과 같은 호출을 통해 데이터에 액세스하십시오.

echo $my_hash[2]; // Will echo "Alice"

foreach () 함수를 사용하여 배열 내용을 반복합니다.

해시 테이블을 이해하는 가장 좋은 방법은 http://en.wikipedia.org/wiki/Hash_table 과 같은 것을 읽는 것입니다 . 그러나 대략 다음과 같이 요약됩니다. . 이 키는 해시 계산을 거치며 결과는 해시입니다. 이전에 MD5 또는 SHA 해시를 보았을 것입니다. 이와 매우 유사합니다. 이 해시의 특정 부분 (일반적으로 첫 번째 X 문자이지만 때로는 완전한 해시)은 값의 저장 영역 (오른쪽) 인 소위 '버킷'을 식별하는 데 사용됩니다.

그런 다음 해시 테이블에 액세스 할 때마다 키를 사용하여 값을 얻습니다. 키는 다시 해시로 계산되며 해시는 연결된 값을 빠르게 찾는 데 사용됩니다. 따라서 해시 테이블을 사용하면 모든 것이 저장된 경우 선형 검색보다 빠른 검색이 가능합니다. 유일한 단점은 일부 해시 구현에서 충돌이 발생한다는 것입니다. 이는 두 개의 다른 키에 대해 동일한 계산 된 해시입니다. 일반적으로 걱정할 필요는 없습니다.

나는 이것이 약간의 배경을 제공하기를 바랍니다. 내 설명은 매우 기초적이며 충분한 구멍이 있다고 확신하지만 빠른 설명을 위해서는 충분합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.