Given the root of a binary search tree, and an integer k, return the kth smallest value (1-indexed) of all the values of the nodes in the tree.

 

 

풀이

이진트리에서 k번째로 작은 숫자를 반환하는 문제이다. (인덱스 1 부터시작)

 

BST트리에서 오름차순으로 순화하기위해서는 중위순회를 하면 된다.

 

방법

1. 중위순회를 통해서 가장 작은 값에서부터 탐색을 시작해서 탐색마다 K의 값을 1씩 빼줘서 (K = K-1)  0이되면 현재 노드의 값 반환시키기

2. 리스트를 만들어서 중위순회를 통해 값을 리스트에 담아서 리스트의 K-1번째 인덱스 반환

 

BST트리가 중위순회를 통해 탐색한다면 최소값부터 순회한다는걸 알면 쉬운 문제이다.

 

코드

 

1. 중위순회 반복분 (k를 차감하며 탐색)

# 재귀로 탐색
class Solution(object):
    def kthSmallest(self, root, k):
        self.cnt = k
        self.result = None
        self.find(root)
        return self.result

    def find(self,node): # 트리의 왼쪽아래 (DETH가 제일 깊은 왼쪽) 탐색
        if node is None: # node가 None이라면 반환
            return             
        self.find(node.left) # 왼쪽탐색 재귀 (왼쪽끝까지 간 후 탐색 시작)
        self.cnt-=1		# k를 cnt로 값을 1씩 차감 
        if self.cnt == 0: # cnt가 0이 된다면 오름차순정렬시 k번째 인덱스의 숫자
            self.result = node.val
            return 
        self.find(node.right)

 2. 중위순회하며 찾은 값들을 리스트에 넣고, 리스트의 [k-1]번째 인덱스를 반환하는 방법

 

# 리스트로 찾기 
class Solution(object):

    def kthSmallest(self, root, k):
        self.result = []
        self.find(root)
        return self.result[k-1]

    def find(self,node):
        if node is None: # none이라면 반환
            return             
        self.find(node.left) # depth가 제일 깊은 왼쪽 노드로 재귀를 통해 탐색 (맨 왼쪽노드부터 탐색시작)
        self.result.append(node.val) # 찾은 값 추가해주기,
        self.find(node.right) # 왼쪽 현재 오른쪽 탐색,

위와 동일하게 재귀문으로 왼쪽 뎁스의 가장 깊은 곳부터 탐색을 시작하며 값들을 모두 리스트에 담고

리스트[k-1]번째 인덱스의 값을 반환해준다.

 

 

다른사람의 코드

class Solution:
    def kthSmallest(self, root: TreeNode, k: int) -> int:
        stack = []
        res = []
        while stack or root:
            while root:
                stack.append(root)
                root = root.left
            root = stack.pop()
            res.append(root)
            root = root.right
        return res[k-1].val

두개의 스택을만들고  root에서 왼쪽을 wihle문으로  먼저 뽑아서 스택에 넣어준 뒤, 오른쪽 값을 찾아서 번갈아가면서 정렬해준다, - 최종적으로 오름차순정렬된 수열의 리스트가 만들어짐,

그다음 k번쨰-1 인덱스 값을 리턴하여 값을 찾는다. 

Given the root of a Binary Search Tree (BST), return the minimum absolute difference between the values of any two different nodes in the tree.

 

 

 

 

풀이

 

이진탐색트리가 주어지면 노드간의 최소 차이값을 찾는 문제이다.

 

최근에 이진탐색트리를 재귀로 구현하는법을 배워서 재귀적으로 만들어봤다.

 

최초코드

import sys
class Solution(object):
    def getMinimumDifference(self, root):
        self.result = sys.maxsize
        def findMin(node):
            if node == None:
                return 
            if node.left:
                self.result =  min(self.result,abs(node.val - node.left.val))
                print(abs(node.val - node.left.val),self.result)
            if node.right:
                self.result = min(self.result,abs(node.right.val - node.val))
                print(abs(node.right.val - node.val),self.result)
            findMin(node.left)
            findMin(node.right)
        findMin(root)

        return self.result

1. result를 전역변수로 최소값을 계산해준다.

2. findMin의 함수로 node의 값과 node.left,node.right의 절대 차이 값을 구한다.(node.left,node.right가 None이 아닐 때 실행)

3. 구해진 절대 차이 값이 result보다 작다면 result 갱신, 

4. findMin 재귀적으로 실행 (left,right) 

 

결과- node에서 left,right값만 계산해주기 때문에 직접적으로 연결되어 있는 노드만 검색하게된다, - > 조부모 노드와 값 비교 불가 

 

 

ex ) [236,104,701,227,911]

 

 

 

이진탐색트리를 순회할 때  중위순회(inorder) 방식을 사용하는데, . (왼쪽 서브트리-노드-오른쪽 서브트리 순으로 순회) 중위 순회방식을 사용하게되면 이진탐색트리 내에 있는 모든 값들을 정렬된 순서대로 읽을 수 있다고 한다.  

 

문제에서 노드의 차이가 절대값기준으로 가장 적은 값을 가져와야한다. 정렬된 순서로 탐색을 진행하게되면 앞의 인덱스 값과 비교를 해주며 찾아주면 되겠지?

 

먼저 트리의 제일 deth가 깊은 노드부터 탐색을 시작한다. (제일 작은값)

재귀가 동작되는 순서

 

재귀로 왼쪽 노드 제일 깊은 곳부터 탐색하게 만든다

 

 

 

중위탐색이 되는 순서

 

import sys
class Solution:
    def getMinimumDifference(self, root: Optional[TreeNode]) -> int:     
        self.prev = float('-inf')
        self.res = float('inf')
        
        def findMin(node):
            if node is None:
                return
                                        
            findMin(node.left)
            
            self.res = min(node.val - self.prev, self.res)
            self.prev = node.val

            findMin(node.right)
        
        findMin(root)
        return self.res​

맨 왼쪽 뎁스가 깊은 노드 ( 제일 작은 값) 부터 탐색을 시작하여, 조부모 노드를 후보로 두고 탐색하게 만든다.

 

ORM

ORM이란 Object Relation Mapper의 줄임말이다. 객체와 관계형 데이터베이스의 데이터를 자동으로 매핑 해주는 것을 말한다. 객체를 통해 간접적으로 데이터베이스 데이터를 다룬다.

 

N+1 문제란?

1개의 쿼리로 데이터를 조회하고 싶지만 N+1개의 쿼리를 사용하여 조회하는 문제

 

Django의 ORM은 *Lazy-Loading을 기본값으로 사용하고 있어 자체적으로 이를 최적화하여 최소한의 쿼리만 날린다. 하지만 DB 설계에따라 N번 쿼리를 더 날리는 N+1 문제가 종종 발생한다.

 

*Lazy-Loading : ORM에서 명령을 실행할 때마다 데이터베이스에서 데이터를 가져오는 것이 아니라 모든 명령 처리가 끝나고 실제로 데이터를 불러와야 할 시점이 왔을 때 데이터베이스에 쿼리를 실행하는 방식

 

user = User.objects.all()
tim = user.filter(first_name='tim')  # 아직 DB에서 데이터를 가져오지않음
order_tim = tim.order_by('id')       # 아직 DB에서 데이터를 가져오지않음
timha = user.get(id=1)

email = timha.email.name           # timha에서 참조 되는 것이아니라
					# email 를 가져오는 쿼리를 더 보냄

 

N+1 Problem은 쿼리 1번으로 N건의 데이터를 가져왔는데 원하는 데이터를 얻기 위해 이 N건의 데이터를 데이터 수 만큼 반복해서 2차적으로 쿼리를 수행한다.

 

 

해결법

Eager-Loading 방식은 사전에 쓸 데이터를 포함하여 쿼리를 날리기 때문에 비효율적으로 늘어나는 쿼리 요청을 방지할 수 있다.

 

user = User.objects.all()
email = user.prefetch_related('email')  # email 가져오는 쿼리를 사전에 날림
  • select_related : foreign-key , one-to-one 처럼 single-valued relationships에서만 사용이 가능하다. SQL의 JOIN을 사용하는 방법이다. 
  • prefetch_related : foreign-key , one-to-one 뿐만 아니라 many-to-many , many-to-one 등 모든 relationships에서 사용 가능하다. SQL의 WHERE … IN 구문을 사용하는 방법이다

'python > django' 카테고리의 다른 글

[DRF] Authentication 종류와 특징  (0) 2023.09.06

1.BasicAuthentication
기본인증. username 및 password에 대해 서명된 HTTP 기본 인증을 사용한다. 매번 유저 정보(이름,비번)를 넘겨야하기 때문에 보안상 위험하다. 테스트 용으로 사용하기엔 용이하지만 실제 인증으로 사용하기엔 부적절

 

 

 

2.TokenAuthentication
토큰인증. 간단한 토큰 기반 HTTP 인증 체계를 사용한다. 기본 데스크톱 및 모바일 클라이언트와 같은 client-server 관계에 적합하다.   토큰 헤더를 사용하여 인증한다 .

Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
  • 유저가 로그인을 요청하고 id, pw 정보가 유효하다면 서버에서 Secret Key를 사용해서 유저에게 토큰을 발급한다.
  • 클라이언트는 발급 받은 토큰을 저장하고, 서버에서 요청 할 때 마다, 해당 토큰을 함께 서버에 전달한다.
  • 서버는 토큰을 검증 하고, 요청에 응답한다.

 

 장점

  • 클라이언트에 토큰이 저장되어 있기 때문에 서버의 메모리에 부담이 되지 않으며 Scale에 있어 대비책을 고려할 필요가 없다.
  • 멀티 디바이스 환경에 대한 부담이 없다. (어느 디바이스던 토큰이 올바르다면 토큰인증을 통해 인증 가능)

 단점

  • 암호화가 풀릴 가능성을 배제할 수 없다.
    => 암호화가 풀리더라도 토큰을 사용할 수 없도록 만료기간을 설정해준다.

 

3.SessionAuthentication
세션 인증. Session에 저장되는 정보를 통해 인증한다. 외부 서비스서는 사용할 수 없고, 웹 사이트와 동일한 session context에서 실행 중인 AJAX 클라이언트에 적합하다.

  • 유저가 로그인을 하면 서버 메모리 상에 세션이 저장된다.
    (이 때 세션을 구분하기 위해 Seesion Id를 기준으로 정보를 저장한다.)
  • 클라이언트의 브라우저에 쿠키로 Session Id가 저장된다
  • 쿠키에 정보가 담겨있기 때문에 브라우저는 해당 사이트에 대한 모든 Request에 Session Id를 쿠키에 담아 전송한다.
  • 서버는 클라이언트가 보낸 Session Id와 서버 메모리를 관리하고 있는 Session Id를 비교해서 일치하면 인증 

 

 

 

 

 

'python > django' 카테고리의 다른 글

Django ORM N+1 문제  (0) 2023.09.06

There is an integer array nums sorted in ascending order (with distinct values).

Prior to being passed to your function, nums is possibly rotated at an unknown pivot index k (1 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,5,6,7] might be rotated at pivot index 3 and become [4,5,6,7,0,1,2].

Given the array nums after the possible rotation and an integer target, return the index of target if it is in nums, or -1 if it is not in nums.

You must write an algorithm with O(log n) runtime complexity.

 

 

풀이

 

오름차순 배열을 임의로 회전하여 target값의 인덱스를 찾아서 반환하는 문제이다.

 

사실 단순하게, for문이나 find함수를 통해서 값을 찾아올 수 있으나 문제에서 O(log n)의 시간복잡도를 원하므로 

 

O(log n)시간 복잡도로 탐색 할 수 있는 이진 탐색을 사용하겠다.

 

이진탐색을 통해서 left  right의 포인터 중간 미드 값을 기준으로 증가하는 방향과 감소하는 방향을 확인한 후

추가로  target값을 기준으로 mid 포인터를 움직여주면된다,

 

기본적으로 문제에서 오름차순으로 정렬된 리스트를 회전시켰기 때문에, 현재 배열의 상태가 right와 left를 mid값을 기준으로 크고 작음을 확인 한 뒤, 그 범위안에 target의 값이 존재하는지 확인하면 된다,

 

left < = target < mid   = left와 mid 사이에 target값이 존재

 

 mid< taget <= right 이라면 mid와 right아이에 값이 존재

 

이를 기반으로 이진탐색을 진행한다 .

 

class Solution(object):
    def search(self, nums, target):
        result = -1 
        left =0
        right = len(nums)-1
        while left<right:
            mid = (left+right)//2
            if nums[mid] == target:
                return mid
            if nums[left]<=nums[mid]:
                if nums[left] <= target and target < nums[mid]:
                    right = mid-1
                else:
                    left = mid+1
            else:
                if nums[mid] <target and target <= nums[right]:
                    left = mid+1
                else:
                    right= mid-1 
        return result

 

 

 

 

 

 

Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become:

  • [4,5,6,7,0,1,2] if it was rotated 4 times.
  • [0,1,2,4,5,6,7] if it was rotated 7 times.

Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]].

Given the sorted rotated array nums of unique elements, return the minimum element of this array.

You must write an algorithm that runs in O(log n) time.

 

 

 

풀이

 

오름차순으로 주어진 정수 배열의 몇번의 회전한다. 이 배열에서 최소 값을 찾아야한다.

 

정렬해서 맨 앞의 값 가져오면 단순한 문제지만 이 문제에서 O(log n)의 속도 내에서 탐색을하여 값을 가지고 와야한다.

 

이진탐색을해서 값을 가져오는게 맞는거 같은데, 음.. 배열이 [2,3,4,0,1] 일때 mid가 가장 큰 값이되고 양쪽값 모두 적은값이 된다, 이런 경우 어떻게 탐색을 진행해야할지 생각을 해봤다, 일단, 최초의 배열은 오름차순으로 정렬되어 있기 때문에 기본적으로 오른쪽으로 이동 할 수록 값이 증가하게된다. 

 

1.양쪽 다 mid 값보다 작을 경우 ,둘 다 작다면 , mid는 배열의 값 중 회전되어서 잘려진 값이 양쪽으로 나누어져 있다는 것을 알 수 있다. 그렇다면 왼쪽으로 탐색해서 제일 작은 값을 찾아야한다.

 

2. 양 쪽다 mid값보다 클 경우 ,  오른쪽으로 포인터를 이동하면서 찾아줘야한다, 기본적으로 오름차순인데, 오른쪽 값이 작다는 것은 회전해서 잘린 배열의 시작부분이 오른쪽에 있다는 걸 알 수 있다  ex)[3,4,0,1,2] 

 

3. 최초에 배열의 양쪽 끝의 값을 먼저 확인해주고 , 만일 마지막 인덱스의 값이 0번 인덱스 값보다 작다면 회전하지않은 오름차순 그대로의 배열인걸 알 수 있다. [0,1,2,3,4]

 

4. right의 인덱스포인터를 통해 mid포인터를 움직여준다.

 

 

 

class Solution(object):
    def findMin(self, nums):
        if len(nums)<1:
            return 0
        left =0
        right = len(nums)-1
        
        
        if nums[left]<nums[right]: #맨 오른쪽값이 맨 왼쪽값보다 크다면 정렬된 배열인 걸 확인 가능
            return nums[left]
        while left<right-1:  # 왼쪽 포인터가 오른쪽 포인터를 넘는다면 모든 탐색 완료, 
            if nums[mid] > nums[right]:  #mid인덱스의 값이 right보다 크다면,
                left = mid + 1    #왼쪽 포인터 = mid+1 (mid포인터의 위치와 오른쪽포인터 사이에 존재함)
            else:
                right = mid 	# 오른쪽 포인터 = mid   (mid포인터의 위치와 왼쪽 포인터 사이에 존재함)
        return nums[left]

로직을 만들면서 잘 안풀려서  leetcode에서 다른사람의 코드를 보고 다시 만들었다.

 

그러면서 알게된건 내가 이진탐색에 대해서 좀 잘못이해하고있는걸 알게되었는데,

 

문제에서 주어지는 배열은 기본적으로 오름차순 정렬이라, right포인터를 통해 현재 인덱스의 상황을 알 수 있다.

 

mid의 값이 right보다 크다면 최소 값은 mid와 right에 존재하게되고, 만일 작다면  최소 값은 left와 mid 사이에에 존재하게된다, 이걸 생각못하고, right = mid-1을 사용해서 자꾸 찾아야되는 인덱스를 벗어나게되어서 문제가 생겼었다. 

 

몇 일 뒤에 다시 풀어봐야겠다.

 

 

 

 

 

 

A peak element is an element that is strictly greater than its neighbors.

Given a 0-indexed integer array nums, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks.

You may imagine that nums[-1] = nums[n] = -∞. In other words, an element is always considered to be strictly greater than a neighbor that is outside the array.

You must write an algorithm that runs in O(log n) time.

 

 

 

풀이

 

문제를 보고 for문으로 돌면서 두번쨰인자부터 최대 길이 -1 의 인덱스까지 for문으로 돌면서 앞뒤의 인덱스를 확인하면 되는거 아니야? 라고 생각하고 쉬운문제라고 생각했었지만, You must write an algorithm that runs in O(log n) time. 

O(Iog n)의 시간복잡도를 가져야된다고한다.

 

리스트를 탐색하는데 O(Iog n)의 시간복잡도?  -> 이진탐색을 써야하는구나 

 

class Solution(object):
    def findPeakElement(self, nums):
        if len(nums)<1:
            return 0
        left =0
        right = len(nums)-1
        while left<right-1: #왼쪽 포인터가 오른쪽 포인터를 넘는 순간 while문 중지
            mid = (left+right)/2 #중간값을 기준으로 양 옆 비교 조건 만족시 return 
            if nums[mid] >nums[mid+1] and nums[mid]<nums[mid-1]:
                return mid
            if nums[mid]<nums[mid+1]: #본인 인덱스 앞쪽이 본인의 수보다 크다면 왼쪽조건 충족
                left = mid+1
            else:
                right =mid-1 
        return left


다른 사람의 코드

 

class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        low, high = 0, len(nums)-1
        while low < high:
            mid = low + int((high-low)/2)
            if nums[mid] < nums[mid+1]:
                low = mid+1
            else:
                high = mid
        return low

동일한 로직이다 ,2개의 포인터로 중간값을 정하고 각 값의 조건을 충족하면 포인터가 움직인다.

'알고리즘 > LeetCode' 카테고리의 다른 글

LeetCode 33. Search in Rotated Sorted Array  (0) 2023.09.05
153. Find Minimum in Rotated Sorted Array  (0) 2023.09.05
LeetCode 205. Isomorphic Strings  (0) 2023.09.01
LeetCode 202. Happy Number  (0) 2023.09.01
49. Group Anagrams  (0) 2023.09.01

 

Hash table ? Hashing?

해싱이란? (Hashing)

해싱이란 임의의 길이의 값을 해시함수(Hash Function)를 사용하여 고정된 크기의 값으로 변환하는 작업을 말한다.

 

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

해시 테이블이란 해시함수를 사용하여 변환한 값을 색인(index)으로 삼아 키(key)와 데이터(value)를 저장하는 자료구조를 말한다. 기본연산으로는 탐색(Search), 삽입(Insert), 삭제(Delete)가 있다.

 

 

간단한 테이블을 만들어서 보자면 key의 값을 주소로 사용하여 만드는 테이블을 말한다. 만일 key가 30이라면 배열의 인덱 30에 데이터를 저장시켜 놓는 방법이다 .

key를 주소로 값을 저장

이렇게 테이블을 해시테이블을 만들어서 사용한다면 탐색,삽입,삭제 등 O(1) 시간 복잡도로 연산할 수 있다.

 

하지만 여기에서 해시테이블을 사용하기 위해선 몇가지 주의점이 있다.

 

1. 키 값의 최대가 얼마인지 알고 있어야한다.

2. 최대 키 값이 적을 때 좋은 성능을 보여준다 (최대 키 값이 커진다면 메모리 비용 상승)

3. 키 값이 골고루 분포되지 않는다면 메모리 낭비가 심해진다.

4. Key는 고유해야 하며, 만일 중복된 key 가 있으면 먼저 있던 key와 value를 대체한다.

5. 저장 순서를 보장하지 않으므로 순서에 의존적인 작업에는 적합하지 않을 수 있습니다.

 

 

해시테이블을 만드는 과정 

Hash Table에서 해시 함수는 입력된 Key를 table의 크기에 적합한 인덱스 값으로 변환하는 것이 목적이다.

만일 해시함수를 통해 해시한 값이 테이블의 크기를 벗어나게 된다면 사용 할 수 없음 (그래서 키 값의 최대가 얼마인지 알아야함 -> 변환 했을 때 범위 내에 존재하는지 알기 위해)

 

 

 아스키코드로 변환한 값을 특정 값으로 나눠 인덱스를 결정하는 모듈로 해싱(Modulo Hashing) 

  • Hash Table의 장점과 단점
    • 장점
      • 빠른 데이터 접근 속도 : 평균적으로 O(1)의 시간 복잡도로 조회 / 삽입 / 삭제를 수행
      • 키-값 쌍 저장 : 키를 기반으로 데이터를 저장하고 검색하는 구조로, 데이터의 연관 관계를 보다 명확하고 쉽게 관리할 수 있음
      • 중복 방지 : 키의 유일성을 통해 데이터의 중복을 자연스럽게 방지
    • 단점
      • 두 개 이상의 키가 동일한 해시 값을 가질 경우 충돌이 발생합니다. 충돌을 관리하는 많은 방법들이 있지만, 충돌이 빈번하게 발생할 경우 성능 저하를 가져올 수 있습니다.

 

Hash Collision이란?

해시 테이블 내에 어떤 키가 이미 자리 잡고 있는 상태에서 다른 키가 삽입을 시도하는 경우에, 해시 함수가 서로 다른 입력에 대해 동일한 값을 반환하는 경우 Hash Collision 발생 

 -  해시 함수를 임의의 크기 값을 고정 해시값으로 변경하면서 중복될 수 있음

 -  해시 함수를 나온 값이 table 크기의 범위를 넘어서는 경우가 발생 할 수 있음

 

 

해결 방법 1) Separate Chaning

- 같은 주소로 해싱되어 충돌이 일어나는 Entry를 연결 리스트(Linked List)로 연결해서 저장하는 방식으로 해시 충돌을 피할 수 있습니다. 

  • Chaning 방법에서 임의의 키에 해당하는 엔트리를 저장할 때는 해시값이 가리키는 bucket의 연결 리스트에 삽입 
  • 이때 내가 사용하고 있는 연결 리스트의 구현체에 따라서 맨 앞 혹은 끝에 삽입

 

 

해결 방법 2) Open Addressing

- Separate Chaning 방식과 달리 추가 공간을 사용하지 않고 충돌을 해결하는 방법입니다.

해시 출돌이 일어나도 정해진 hash table 공간에 다른 위치에 저장방법이다. 다른 위치에 저장함으로서 key로 해시 테이블을 때  buket에 들어있는 인덱스와 주소가 일치하지 않을 수 있다. 

 

선형 탐색 (Linear Probing) - 가장 간단한 방법으로 메모리주소 다음 위치에 bucket을 저장하는 방법

 

 

Separate Chaning 해시테이블 (python)

(list로 해시인덱스 데이터 저장)
class Chaining_Hash_table:
    def __init__(self,length= 97): # 97 테이블 크기만큼 나눈다
        self.max_len = length     #테이블 key를 97로 나누어 해싱
        self.table = [[] for __ in range(length)]

    def hash(self,key): #해시테이블에 key와 value넣기.
        hash_key = sum([ord(i) for i in key])
        return hash_key % self.max_len # #ord함수로 문자열 변경후 나온 값  % max_len

    def add(self,key,value):
        index = self.hash(key)
        self.table[index].append((key,value))

    def put(self,key,value):
        index = self.hash(key)
        if not value:         #리스트 안의 값이 존재하지않는다면 None반환
            return None
        for i in range(len(value)): # 리스트에서 동일한 값 찾기
            if value[i] == key:
                value.pop(i)  # pop으로 해시테이블 인덱스에 안에있는 튜플 제거
                break
        self.table[index].append((key,value)) # 수정할 데이터 추가,

    def get(self,key):
        index = self.hash(key)
        value = self.table[index]
        if not value:         #리스트 안의 값이 존재하지않는다면 None반환
            return None
        for v in value:       # 리스트에서 값을 찾아 반환 
            if v[0] == key:
                return v[1]

 

 

Linear Probing 해시테이블 (python)

# ”Hash Table의 크기는 2의 멱수 (2^0, 2^1, 2^2...2^11에 가깝지 않은 소수(prime number)”를 선택하는 것이 좋습니다.
class Linear_Probing_Hash_table:
    def __init__(self,length= 97): # 97 테이블 크기만큼 나눈다
        self.max_len = length     #테이블 key를 97로 나누어 해싱
        self.table = [[0] for __ in range(length)]

    def hash(self,key): #해시테이블에 key와 value넣기.
        hash_key = sum([ord(i) for i in key])
        return hash_key % self.max_len # #ord함수로 문자열 변경후 나온 값  % max_len

    def add(self,key,value):
        index = self.hash(key)
        if self.table[index]!=0:
            for i in range(index,self.max_len):
                if self.table[i]==0:
                    self.table[i] = [key,value]
        else:
            self.table[index]=[key,value]

    def put(self,key,value):
        index = self.hash(key)
        if self.table[index]==0:
            return None # 데이터 존재하지 않음
        else:
            for i in range(index,self.max_len):
                if self.table[i][0]==index: #변환된 인덱스부터 밑으로 내려가며 탐색 
                    self.table[i] = [key,value] # 키가 동일하다면 값 변경 후 저장
                    return

    def get(self,key):
        index = self.hash(key)
        if self.table[index]==0:
            return None # 첫인덱스 조회시 데이터가 0이라면 데이터 존재하지 않음
        else:
            for i in range(index,self.max_len):
                if self.table[i][0]==index: #변환된 인덱스부터 밑으로 내려가며 탐색 
                    return self.table[i][1] # 키가 동일한 인덱스를 찾았다면 값 반환,
            return None # 동일한 인덱스 범위에 다른 값이 있지만 동일한 값을 찾지 못했다면 None 반환

 

 

'CS > 자료구조' 카테고리의 다른 글

Set의 시간복잡도  (0) 2023.09.01
python으로 LinkedList 만들기  (0) 2023.08.30

+ Recent posts