AVL트리는 ’단번에’ 찾아내는 방식이라고 말하기는 어렵다
키(key)와 값(value)이 하나의 쌍을 이룬다.
키(key)가 존재하지 않는 ‘값’은 저장할 수 없다.
모든 키는 중복되지 않는다.
typedef struct _empInfo
{
int empNum; //직원의 고유변호 : key
int age; //직원의 나이 : value
}
키를 결정하였다면, 이를 기반으로 데이터를 단번에 찾을 수 있어야 한다
그 결과가 동일한 것을 가리켜 ’충돌(Collision)’이라고 한다
슬롯의 상태
1) Empty : 이 슬롯에는 데이터가 저장된바 없다.
2) Deleted : 이 슬롯에는 데이터가 저장된바 있으나 현재는 지워진 상태이다.
3) Inuse : 이 슬롯에는 현재 유효한 데이터가 저장되어 있다.
테이블 구조
#define MAX_TBL 100
typedef int HashFunc(key, k);
typedef struct _table
{
Slot tbl[MAX_TBL];
HashFunc *hf;
}
// 테이블의 초기화
void TBLInit(Table * pt, HashFunc * f);
// 테이블에 키와 값을 저장
void TBLInsert(Table * pt, Key k, Value v);
// 키를 근거로 테이블에서 데이터 삭제
Value TBLDelete(Table * pt, Key k);
// 키를 근거로 테이블에서 데이터 탐색
Value TBLSearch(Table * pt, Key k);
#include <stdio.h>
#include <stdlib.h>
#include "Table.h"
void TBLInit(Table * pt, HashFunc * f)
{
int i;
// 모든 슬롯 초기화
for(i = 0 ; i < MAX_TBL; i++)
(pt->tbl[i]).status = EMPTY;
pt->hf = f; //해쉬 함수 등록
}
void TBLInsert(Table * pt, Key k, Value v)
{
int hv = pt->hf(k);
pt->tbl[hv].val = v;
pt->tbl[hv].key = k;
pt->tbl[hv].status = INUSE;
}
Value TBLDelete(Table * pt, Key k)
{
int hv = pt->hf(k);
if((pt->tbl[hv]).status != INUSE)
{
return NULL;
}
else
{
(pt->tbl[hv]).status = DELETED;
return (pt->tbl[hv]).val; //소멸 대상의 값 반환
}
}
Value TBLSearch(Table *pt, Key k)
{
int hv = pt->hf(k);
if((pt->tbl[hv]).status != INUSE)
return NULL;
else
return (pt->tbl[hv]).val; //탐색 대상의 값 반환
}
좋은 해쉬 함수는 키의 일부분을 참조하여 해쉬 값을 만들지 않고, 키 전체를 참조하여 해쉬 값을 만들어 낸다
선형 조사법의 순서
’클러스터(Cluster) 현상’ 즉, 특정 영역에 데이터가 몰리는 현상이 발생할 수 있다
이차 조사법의 순서
이차 조사법의 문제
: 해쉬 값이 같으면, 충돌 발생시 빈 슬롯을 찾기 위해서 접근하는 위치가 항상 동일하다
Ex)
- 1차 해쉬 함수 : h1(k) = k % 15
- 2차 해쉬 함수 : h2(k) = 1 + (k % c)
1) 배열 기반 닫힌 어드레싱 방법
2) 연결리스트 기반 닫힌 어드레싱 방법
하나의 해쉬 값에 다수의 슬롯을 둘 수 있다
typedef int key;
typedef Person *value;
typedef struct _slot
{
Key key;
Value val;
} Slot;
슬롯의 상태 정보를 표시할 필요가 없다.
#define MAX_TBL 100
typedef int HashFunc(Key k);
typedef struct _table
{
List tbl[MAX_TBL];
HashFunc *hf;
} Table;
void TBLInit(Table *pt, HashFunc * f);
void TBLInsert(Table *pt, Key k, Value v);
Value TBLDelete(Table *pt, Key k);
Value TBLSearch(Table *pt, Key k);
1. 구조체 Slot을 연결 리스트의 노드로 활용
typedef struct _slot // 구조체 Slot이 연결 리스트의 노드 역할을 겸하는 구조
{
Key key;
Value val;
struct _slot * next; //다음 노드를 가리키는 포인터 변수
} Slot;
2. 슬롯과 노드를 구분하는 구조 1
typedef Slot * Data; //노드에 저장할 데이터는 Slot형 변수의 주소 값이다!
typedef struct _node
{
Data data;
struct _node *next;
} Node;
3. 슬롯과 노드를 구분하는 구조 2
typedef Slot Data; //노드에 저장할 데이터는 Slot형 변수이다!
typedef struct _node
{
Data data;
struct _node *next;
} Node;
#include "Slot2.h"
// 중간 생략 //
typdef Slot LData; //변경된 typedef 선언문
typedef struct _node
{
LData data;
struct _node * next;
} Node;
typedef struct _LinkedList
{
Node * head;
Node * cur;
Node * before;
int numOfData;
int (*comp)(LData d1, LData d2);
} _LinkedList;
// 이하 생략 //
#include "Table2.h"
#include "DLinkedList.h"
void TBLInit(Table *pt, HashFunc * f)
{
int i;
for(i = 0; i < MAX_TBL; i++)
ListInit(&(pt->tbl[i]));
pt->hf = f;
}
void TBLInsert(Table *pt, Key k, Value v)
{
int hv = pt->hf(k);
Slot ns = {k, v};
if(TBLSearch(pt, k) != NULL) //키가 중복되었다면
{
printf("키 중복 오류 발생\n");
return;
}
else
{
LInsert(&(pt->tbl[hv]), ns);
}
}
Value TBLDelete(Table *pt, key k)
{
int hv = pt->hf(k);
Slot cSlot;
if(LFirst(&(pt->tbl[hv]), &cSLot))
{
if(cSlot.key == k)
{
LRemove(&(pt->tbl[hv]));
return cSLot.val;
}
else
{
while(LNext(&(pt->tbl[hv]), &cSlot))
{
if(cSlot.key == k)
{
LRemove(&(pt->tbl[hv]));
return cSLot.val;
}
}
}
}
return NULL;
}
Value TBLSearch(Table *pt, Key k)
{
int hv = pt->hf(k);
Slot cSLot;
if(LFirst(&(pt->tbl[hv]), &cSLot))
{
if(cSlot.key == k)
{
return cSlot.val;
}
else
{
while(LNext(&(pt->tbl[hv]), &cSlot))
{
if(cSlot.key == k)
{
return cSLot.val;
}
}
}
}
return NULL;
}
Value TBLDelete(Table *pt, Key k)
{
….
return NULL; // 삭제할 대상이 존재하지 않는 경우
}
Value TBLSearch(Table *pt, Key k)
{
….
return NULL; // 찾는 대상이 존재하지 않을 경우
}
반환되는 값, 테이블에 저장되는 값은 메모리의 주소 값이라고 가정합니다. 달리 말해서 Value는 포인터 형으로 선언된다고 가정합니다.
NULL은 그 자체로 정수 0이기 때문에 다른 용도로 사용할 경우, 0이라는 의미를 지니는 데이터로 오해할 수 있다
Value TBLDelete(Table *pt, Key k)
{
….
return FALSE; // 삭제할 대상이 존재하지 않는 경우
}
Value TBLSearch(Table *pt, Key k)
{
….
return FALSE; // 찾는 대상이 존재하지 않을 경우
}