일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 기능적 요구사항
- 자바 필터
- 비기능적 요구사항
- 도커 이미지 빌드
- 스프링부트 도커
- open-session-in-view
- 수정자주입
- fetch join
- IOC
- 스프링 포매터
- 소프트웨어의 품격
- 생성자주입
- 스프링 시큐리티 설정
- ioc컨테이너
- 스프링시큐리티
- 토비의 스프링
- Atomicity
- kotlin ::
- kotlin 리팩터링
- method refetence
- 그래프큐엘
- java predicate
- 정적팩토리메서드
- jpa lazy
- 스프링
- spring formatter
- 동적파라미터
- 스프링di
- jpa no session
- Spring
Archives
- Today
- Total
공부기록
[HashTable] JAVA로 간단히 구현해보며 HashTable을 알아보자! 본문
반응형
개요
- HashTable 은 Key - Value 로 이루어진 자료구조다.
- HashTable.get(Object key)를 쓰면 해당 key와 맞는 value를 반환한다.
- 이름에서 알 수 있듯이 HashCode를 이용한다.
- Key를 HashFunction를 통해 정수 Hash를 만들어내고, 그 Hash를 이용해 데이터에 접근하기 때문에 속도가 매우 빠르다.( O(1) )
- 정수 Hash를 통해 데이터에 접근해서 속도가 빠르다는데.. 그렇다면 동일한 Hash를 반환해서 동일 인덱스에 데이터가 중복될 수 있다. 이를 Hash Colliision(해시 충돌)이라 부른다. 최악의 경우 데이터 검색에 O(n) 이 걸린다. 때문에 Hash를 만들어내는 HashFunction에 쓰이는 Hash Algorithm을 잘 만들어야 한다. 입력받은 Key를 Hash로 만들 때, 최대한 잘 분배해야한다
HashTable과 HashMap의 차이는 ?
HashTable은 Thread Safe 하다.
HashMap은 Thread Unsafe 하다.
동작방식은 비슷하다.
Hash Collision이 발생한다면?
- 해당 인덱스의 배열 저장 위치에다 바로 데이터를 집어넣는 게 아니라, LinkedList를 이용해서 차곡차곡 쌓는 방법을 쓸 수 있다.
- 인덱스 중 비어있는 인덱스를 할당한다.
구현
key와 value를 가지고 있는 Node이너클래스 작성.
private static class Node {
private String key;
private String value;
private Node(String key, String value) {
this.key = key;
this.value = value;
}
}
MyHashTable을 만들고, 위에서 작성한 Node를 제네릭파라미터로 갖는 멤버 LinkedList배열 선언.
public class MyHashTable {
LinkedList<Node>[] data;
public MyHashTable(int size) {
this.data = new LinkedList[size];
}
}
HashCode를 생성해내는 getHashCode(String key) 메서드 작성
private int getHashCode(String key) {
int hashcode = 0;
for(char c : key.toCharArray()) {
hashcode += c;
}
return hashcode;
}
- 간단한 해쉬 알고리즘이다. key 문자열의 각각 문자를 아스키코드로 만들어 모두 더한다.
- 맘에 들지 않는다면
Objects.hashcode(Object o)
를 쓰자
hashcode를 위에 작성한 LinkedList배열의 인덱스로 변환하는 메서드 작성
private int convertToIndex(int hashcode) {
return hashcode % data.length;
}
- 역시 간단한 로직이다. hashcode를 위에서 선언한 LinkedList 배열의 길이로 나머지 연산한 결과다.
입력받은 key로 LinkedList에서 Node를 찾는 searchKey 메서드 작성
private Node searchKey(LinkedList<Node> list, String key) {
if(list == null) return null;
for (Node node : list) {
if (node.key.equals(key)) {
return node;
}
}
return null;
}
데이터를 집어넣는 public api인 put 메서드 작성
public void put(String key, String value) {
int hashCode = getHashCode(key);
int index = convertToIndex(hashCode);
LinkedList<Node> list = data[index];
if (list == null) {
list = new LinkedList<Node>();
data[index] = list;
}
Node node = searchKey(list, key);
if (node == null) {
list.addLast(new Node(key, value));
}else {
node.value = value;
}
}
- key를 hashcode로 변환한다.
- (1)에서 변환한 hashcode를 index로 변환한다.
- 위에서 선언한 LinkedList 배열에서 index로 LinkedList를 찾는다.
- 만약 null 이라면 새로운 LinkedList를 만들고 해당index의 배열에 할당한다.
- searchKey 메서드로 (3)에서 찾은 LinkedList와 key를 파라미터로 넘겨주면 Node가 나온다.
- Node가 null 이라면 key에 해당하는 value가 없다는 뜻이므로 LinkedList의 마지막 위치에 Node를 만들어 저장한다.
- null이 아니라면 기존에 있는 value를 바꿔치기한다.
데이터를 꺼내오는 public api인 get 메서드 작성
public String get(String key) {
int hashCode = getHashCode(key);
int index = convertToIndex(hashCode);
LinkedList<Node> list = data[index];
Node node = searchKey(list, key);
return node == null ? null : node.value;
}
- key를 hashcode로 변환한다.
- (1)에서 변환한 hashcode를 index로 변환한다.
- searchKey 메서드로 해당 key를 갖고있는 Node를 찾는다.
- Node가 null 이라면 key에 해당하는 값이 없다는 뜻이므로 null을 반환하고, null이 아니라면 key에 해당하는 값이 있다는 뜻이므로 value를 return 한다.
전체 코드
/**
* @author : Eunmo Hong
* @since : 2020/06/27
*/
public class MyHashTable {
LinkedList<Node>[] data;
public MyHashTable(int size) {
this.data = new LinkedList[size];
}
public void put(String key, String value) {
int hashCode = getHashCode(key);
int index = convertToIndex(hashCode);
LinkedList<Node> list = data[index];
if (list == null) {
list = new LinkedList<Node>();
data[index] = list;
}
Node node = searchKey(list, key);
if (node == null) {
list.addLast(new Node(key, value));
}else {
node.value = value;
}
}
public String get(String key) {
int hashCode = getHashCode(key);
int index = convertToIndex(hashCode);
LinkedList<Node> list = data[index];
Node node = searchKey(list, key);
return node == null ? null : node.value;
}
private int getHashCode(String key) {
int hashcode = 0;
for (char c : key.toCharArray()) {
hashcode += c;
}
return hashcode;
}
private int convertToIndex(int hashCode) {
return hashCode % data.length;
}
private Node searchKey(LinkedList<Node> list, String key) {
if(list == null) return null;
for (Node node : list) {
if (node.key.equals(key)) {
return node;
}
}
return null;
}
private static class Node {
private String key;
private String value;
private Node(String key, String value) {
this.key = key;
this.value = value;
}
}
}
실행
/**
* @author : Eunmo Hong
* @since : 2020/06/27
*/
public class HashSample {
public static void main(String[] args) {
MyHashTable map = new MyHashTable(3);
map.put("hong" , "Eunmo Hong");
map.put("grace" , "GraceLove");
map.put("github", "https://github.com/gracelove91");
map.put("tistory", "https://gracelove91.tistory.com");
map.put("email", "govlmo91@gmail.com");
}
}
- map.put("hong" , "Eunmo Hong");
- 'h(104)', 'o(111)', 'n(110)', 'g(103)' 의 각각 아스키코드 값을 모두 더한다. (총합 428)
private int getHashCode(String key)
- hashCode와 위에서 선언한 LinkedList 배열의 length를 나머지 연산을 한다. (428 % 3 = 2)
private int convertToIndex(int hashcode)
- LinkedList[2]에 위치한 LinkedList를 찾아온다.
public void put(String key, String value) { ... LinkedList<Node> list = data[index]; ... }
- (3)에서 찾은 LinkedList는 null이니 새로운 LinkedList를 만들어서 (3)에서 찾는 LinkedList 변수에 할당한다.
public void put(String key, String value) { ... if(list == null) { list = new LinkedList<>(); data[index] = list; } ... }
- searchKey로 key와 (4)에서 할당한 LinkedList를 넘겨주면 Node를 반환한다.
public void put(String key, String value) { ... Node node = searchKey(list, key); ... }
- Node가 null이므로 key와 value로 새로운 Node를 만들어서 (3)에서 찾은 LinkedList의 마지막 위치에 할당해준다
public void put(String key, String value) { ... if (node == null) { list.addLast(new Node(key, value)); } ... }
- 'h(104)', 'o(111)', 'n(110)', 'g(103)' 의 각각 아스키코드 값을 모두 더한다. (총합 428)
반응형
'Computer Science > 자료구조' 카테고리의 다른 글
이진 탐색(binary search) (0) | 2024.12.23 |
---|---|
[자료구조] 스택 (0) | 2020.05.22 |
합병정렬 (0) | 2020.01.12 |
기본적인 정렬(선택정렬, 버블정렬, 삽입정렬) (0) | 2020.01.12 |
ArrayList의 add(T t)와 addAll(Collection<? extends T> collection)을 구현해보자. (0) | 2019.10.09 |