@ 해시(위키피디아)
 

해시는 해시 함수를 이용하여 키 값을 위치로 변환하고 이를 이용해 저장된 자료를 바로 찾아가는 계산 검색 방식이다.

 

저장과 검색은 아래와 같은 과정을 거친다

키 값 –> 해싱 함수 –> 해시 주소(버킷 주소) –> 해시 테이블

 

해싱 함수는 계산이 쉬워야 하고 충돌이 적어야 하며 해시 테이블에 고루 분포할 수 있도록 해야 한다.

자주 쓰는 것은 제산 함수(나누기) 와 승산 함수(곱하기) 이다.

 

서로 다른 키 값에 대해 해싱 함수가 같은 버킷 주소를 지정할 수 있다. 이런 경우를 ‘충돌’ 이라고 하며, 비어 있는 슬롯에 저장하면 되지만, 빈 슬롯이 없는 경우 오버플로우가 발생한다.

 

오버플로우 처리 방법은 두 가지가 있다.

1) 선형 개방 주소법(선형 조사법)

충돌이 일어난 키값을 다른 비어있는 버킷을 찾아 저장한다. 이 때 비어있는 버킷은 순차적으로 찾는다.

찾을 때도 마찬가지로 해싱 함수로 버킷을 찾아 키가 있는지 확인하고, 없으면 순차적으로 버킷을 뒤진다.

 

2) 체이닝

해시 테이블을 변형하여 각 버킷이 무한대의 슬롯을 갖게 한다. 오버플로우가 일어나지 않게 하는 방법이다.

 

소스 >>

 

# 해쉬 구현
# 2009-03-18, Jung-taek Lim(Heart)

class Hash
  def initialize(burket_size, use_chaining)
    @burket_size = burket_size
    @use_chaining = use_chaining

    @burket = []
  end

  # 제산 함수 이용
  def hashing_function(key)
    return key % @burket_size
  end

  def put(key, value)
    return @use_chaining ? put_using_chaining(key, value) :
      put_using_open_addressing(key, value)
  end

  def get(key)
    return @use_chaining ? get_using_chaining(key) :
      get_using_open_addressing(key)
  end

  private
  
  # 선형 개방 주소법 사용
  def put_using_open_addressing(key, value)
    burket_idx = hashing_function(key)

    (burket_idx..@burket_size - 1).each do |idx|
      if nil == @burket[idx]
        @burket[idx] = [key, value]
        
        return true
      end

      return true if @burket[idx][0] == key

    end

    return false
  end

  def get_using_open_addressing(key)
    burket_idx = hashing_function(key)

    (burket_idx..@burket_size - 1).each do |idx|
      return @burket[idx][1] if key == @burket[idx][0]
    end

    return nil
  end

  # 체이닝 사용
  def put_using_chaining(key, value)
    burket_idx = hashing_function(key)

    if nil == @burket[burket_idx]
      @burket[burket_idx] = [[key, value]]
    else
      @burket[burket_idx].push [key,value]
    end

    return true
  end

  def get_using_chaining(key)
    burket_idx = hashing_function(key)

    return nil if nil == @burket[burket_idx]

    @burket[burket_idx].each do |set|
      return set[1] if key == set[0]
    end

    return nil
  end

end

hash = Hash.new(5, false)
hash.put(45, 1)
hash.put(9, 2)
hash.put(10, 3)
hash.put(96, 4)
hash.put(25, 5)

puts hash.get(96)
puts hash.get(25)
puts hash.get(15)

puts "---------------------------------"

hash = Hash.new(5, true)
hash.put(45, 1)
hash.put(9, 2)
hash.put(10, 3)
hash.put(96, 4)
hash.put(25, 5)

puts hash.get(96)
puts hash.get(25)
puts hash.get(15)

 

결과 >>

4

5

nil

---------------------------------

4

5

nil

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Heart