ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [파이썬 코테 대비 동아리] _개념을 공부하자 "해시"편
    1학년/파이썬 공부 2022. 9. 24. 19:18

    해쉬

    해시(Hash) 란?

    : 자료구조의 하나이다. 임의 값을 ( a, 124, 안녕하세요, Hello World ) 해시( Hash ) 함수로 일정한 길이의 값으로 바꾸는 것이다.

    해시 테이블( Hash Table )이란?

    : 해시 함수를 사용하여 출력값인 색인( index )을 이용해 key 와 value로 저장된 해시 테이블에서 데이터를 찾는다. 데이터를 다루는 기법 중 하나로 데이터의 검색과 저장이 빠르게 진행된다 .

    파이썬에서는 dictionary, 루비에서는 Hash, 자바에선 Map이 해시 테이블의 대표적인 예시이다. 보통은 배열로 미리 Hash Table 사이즈 만큼 생성 후에 사용한다. ( 공간과 탐색 시간을 맞바꾸는 기법) 그러나 파이썬에서는 해시 테이블 사이즈를 딕셔너리 타입을 쓰면 끝이기 때문에 별도로 구현할 필요가 없다 !

    : 기본 연산으로는 search, insert, delete가 있다.

    : 순차적으로 데이터를 저장하지 않고 key를 통해서 value 값을 얻는다.

    : slot이란 단어를 종종 볼 수 있는데 slot은 해시 테이블에서 한 개의 데이터를 저장할 수 있는 공간이다.

    : 쉽게 말하면 데이터 테이블 같은 느낌인 듯 ?

    1. 해시는 자료구조의 하나
    2. key를 이용해서 해시함수를 거치면 출력값 ( index )가 나오는데 이를 해시 주소라고 하며, 해시 테이블에서 해시 주소를 대입하면 데이터 위치를 일관성 있게 찾을 수 있다.
    3. 해시 테이블의 한 개의 데이터 저장 공간을 슬롯( slot )이라고 부른다.
    4. 데이터 검색과 저장이 아주 빠르게 진행되기 때문에 많이들 쓴다 !
    5. 주로 검색이 많이 필요한 경우 / 저장, 읽기, 삭제가 빈번한 경우 / 캐쉬 구현시에 많이 쓴다.

    Dictionary를 쓰기 전에.. 초간단 해시 함수를 한번 만들어보자

    hash_table = list([ 0 for i in range(10)])
    hash_table
    
    #output
    #[0,0,0,0,0,0,0,0,0,0]
    

    해시 함수 ?

    : 임의의 길이를 갖는 메시지를 입력 받아서 고정된 길이의 해시값을 출력하는 함수이다. 원래 입력 값과는 완전히 다른 모습이기 때문에 암호화 영역에서 주요하게 사용되며 SHA ( Secure Hash Algorithm )알고리즘이 대표적인 예시이다 .

    : 가끔… 해시 충돌이 일어난다. 고정된 해시값을 출력하기 때문에 다른 값을 입력해도 같은 해시값이 나오는 것이다. 이를 해결하기 위해서는 별도의 자료구조가 필요하다.

    해시 충돌 방지

    : 개방 주소법(open addressing)으로 해시 테이블 크기는 고정하면서 빈 곳을 찾아 채우거나 분리 연결법(seperate chaining)으로 해시 테이블의 크기를 가변적으로 만드는 방법이다.

    개방 주소법(open addressing)

    : 선형 탐사법(Linear Probing)으로 선형적이게 순차적으로 검색한다. slot에 이미 값이 저장되어 있으면 이 slot만큼 폭을 옮겨 다음 해시값에 저장한다.

    또는 제곱 탐사법(Quadratic Probing)으로 고정폭이 아닌 제곱으로 폭을 늘리는 방법이다. 또는 이중 해싱(Double Hashing) 으로 해시값의 규칙을 없앤다. 충돌된 해시에 또 해시를 적용해서 값을 다르게 변화시키는 것이다.

    분리 연결법(seperate chaining)

    : 하나의 슬롯에 들어갈 값의 제한을 듣지 않는다. 이때 slot 에는 linked list 나 tree를 이용해준다. linked list로 노드가 연결되기 때문에 (기차라고 생각한다 나는…) 주소가 변하지 않고 데이터 개수 제약이 없다. 하지만 메모리 문제가 있을 수 있다.

    파이썬에서의 해시 테이블. 딕셔너리(Dictionary)

    : 먼저 딕셔너리에 대해서 살펴보자

    value1 = {
    	'color' : 'green'.
    	'age' : '24'.
    	'address' :'Seoul'
    }
    
    print(value1) #전체 출력
    print(value1.keys()) #key만 출력
    print(value1.values()) # value만 출력
    print(value1['age']) # key로 값에 접근
    value1['grade'] = 5 # key값 추가
    value1['grade'] =7 #값 수정
    del value1['grade'] # key값 삭제
    

    이제 key와 value를 출력 해보자.

    for key, value in value1.items(): #item함수는 딕셔너리의 key value반환
    	print("key :"+key)
    	print("value: "+value)
    	print("키에 따른 값 :" +user[key]
    
    

    위는 딕셔너리의 구조와 정의 사용법이다.

    hash_table = list([0 for i in range(10)])
    print(hash_table)
    
    def hash_func(key):
        return key % 5
    
    data1 = "red"
    data2 = "yellow"
    data3 = 'blue'
    
    print(ord(data1[0]), ord(data2[0]), ord(data3[0]))
    print(ord(data1[0]), hash_func(ord(data1[0])))
    
    def save_data(data, value):
        key = ord(data[0])
        hash_address = hash_func(key)
        hash_table[hash_address] = value
    
    save_data("red", "1000")
    save_data("yellow", "2000")
    save_data("blue", "3000")
    
    def get_data(data):
        key = ord(data[0])
        hash_address = hash_func(key)
        return hash_table[hash_address]
    
    print(get_data("red"))
    

    이런식으로 hash로 dictionary를 이용해 값에 접근할 수 있다.

    우리의 목표는 뭐다 ? 코딩 테스트다

    해시가 뭔지 다 알아봤으니 이제 몸으로 느껴보자 !

    https://codingpractices.tistory.com/entry/Python-파이썬-해시-Hash-해싱-Hashing-문제로-알아보기

    여기서 풀이를 가져옴 …! 왜냐면..난…아무것도 모르니까..배우는 의미로다가…

    프로그래머스 Level2 전화번호 목록

    :전화번호부의 전화번호 중 한 번호가 다른 번호의 접두어인 경우 확인.

    구조대 : 119

    박준영 : 97 674 223

    지영석 : 11 9552 4421

    다음의 전화번호의 경우 구조대의 번호가 영석이의 접두사이다.

    전화번호부에 적힌 전화번호를 담은 배열 phone_book이 solution함수의 매개변수로 주어질 때 어떤번호가 다른 번호의 접두어인 경우가 있으면 false, 그렇지 않으면 true 를 return 하도록 solution함수를 작형한다.

    해시 x 풀이

    def soulution(phone_book):
    	answer = True
    	for i in phone_book:
    		temp=''
    		for j in i:
    			temp += j
    			if temp in phone_book and temp != i:
    				answer = False
    			return answer
    

    이러면 효율성 문제에서 오류가 난다구 하네요 ~

    해시 o 풀이

    def solution(phone_book):
    	answer = True
    	hash = {}
    
    	for i in phone_book:
    		hash[i] = 1
    	for i in phone_book:
    		temp = ''
    		for j in i:
    			temp += j
    			if temp in hash and temp !=i:
    			answer = False
    
    	print(answer)
    
    solution(['119','97676223','1195524421'])
    solution(['123','456','789'])
    

    사실 봐도 이해가 잘 안 됨 ㅠ-ㅠ

    꾸역꾸역 노력해보자면…

    hash i값에 1을 담는 이유는 value값이 필요없고 key값만 비교하면 되는 문제이기 때문인 것 같다. 딱히 다른 값도 없고 전번만 비교하면 되기 때문에.. 그래서 temp(임시)변수에다 값 너어가며 hash로 비교해가면서 같은 게 있나 없나 검사하는 거 같은데…어…….ㅠㅠㅠㅠㅠㅠ모르겠다..

    다른 블로그의 문제풀이와 해설을 또 가져오봤다

    https://scarletbreeze.github.io/articles/2019-07/pythonKit문제풀이(1)

    완주하지 못한 선수

    • 수많은 사람들이 선수들이 마라톤에 참여
    • 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주
    • 마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때,
    • 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요
    • 제한사항
    • 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하
      • participant의 길이는, 10만 이하를 가질 것이네.
    • completion의 길이는 participant의 길이보다 1 작다.
    • 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있다.
    • 참가자 중에는 동명이인이 있을 수 있다.
      • 동명이인 조건이 없었다면, 집합으로 구해서 차집합으로 구해버리면 되는데, 이 조건을 인해 접근 방법이 달라짐
    • 입출력 에시도 잘 살펴보기

    일단 해설보기 전 내 생각은 마라톤선수 참가선수 배열과 완주 선수 배열을 비교해서( 참가선수 해시에 value값을 모두 0으로 설정 ) 단 한명의 선수 제외하고는 해시 value값이 1로 들어가게끔 만들어주고 해시찾기로 value값이 1인 사람을 출력하게끔 하면 되겠는데 음…

    동명이인을 어떻게 할까 ㅠ가 문제이다.

    해설을 보니 !!! 이런 생각이 …!!! 참가 선수 이름을 a b c d라고 하면 참가 선수에 value에 이름이 나올 때 마다 1을 증가시켜준다. 만약 b가 3명이라 하면 참가 선수만 등록한 해시에는 value가 3이 들어감. 이제 완주 선수 해시를 비교해서 1씩 감소시켜주면 …!! b만 1을 가지기 때문에 리턴값(key)을 호출하면 b가 나온다 !!

    def solution(participant, completion):
    	table = { } # 빈 딕셔너리 == 해시 테이블 만들고
    	for x in participant :
    		table[x] = table.get(x,0) + 1 #key로 value얻어내느 함수 get 사용. 딕셔너리에 x가 없을시 default 입력, 처음 등장하면 1로 만들고 아니면 기존 value에 1 더하기
    	for x in completion :
    		table[x] -= 1  #완주 인원 빼주기
    	tablenf = [ i for i , k in table.items() if k > 0]
    	answer = dnf[0]
    	return answer
    

    다른건 다 이해했는데 7번째 줄 이해불가..ㅠ 파이썬 이해부족인듯 파이썬을 개념부터 안 하고 그냥 찍먹수준으로 필요한 것 만 골라 공부했더니..뭔지 모르겠다…

    일단 items()함수가 key 의 value만 반환한다.

    dnf라는 변수는 배열이며 k와 딕셔너리의 …. 이부분 이해가 안댐 ㅠ0ㅠ

    i for i 가 i 를 리스트 안에 넣는데... items()로 밸류 값 뽑아내서 1이상이면 k가 되고 그 k를 i에 넣는다는건가….?

     

    아@@@ 알아냈다 i 를 리스트 안에 넣는데 key i의 value값 k를items로 1보다 큰 밸류 가 있으면 key값 i를 넣는다 !! 라는 듰 인듯 !! 

    728x90

    댓글

Designed by Tistory.
티스토리 친구하기