해싱(hashing)은 데이터를 효율적으로 관리하기 위한 방법 중 하나이다. 해싱에서는 키를 해시 함수에 입력하여 나온 해시값을 인덱스로 사용하여 데이터를 저장하고 검색한다. 그러나 다른 키들이 동일한 해시값을 가질 때 '충돌'이 발생하는데, 이런 경우를 처리하기 위한 한 가지 방법이 '체이닝'이다. 체이닝에서는 같은 해시값을 가진 데이터들을 연결 리스트에 저장하여 관리합니다. 이 때, 단순 연결 리스트가 주로 사용됩니다. 각 해시값에 대응되는 연결 리스트의 헤드가 해시 테이블의 각 슬롯에 저장되며, 충돌이 발생하면 새 노드가 해당 연결 리스트에 추가된다.
노드는 자기 참조 구조체를 이용하여 정의된다. 자기 참조 구조체란 자기 자신을 참조하는 포인터를 포함하는 구조체이다. 구조체 안에는 데이터를 저장하는 data필드와 포인터가 저장되어 있는 link필드가 존재한다.
procedure INSERT(Head, Item, Y)
/* Y:삽입할 노드, X:삽입 후 Y의 선행 노드*/
call GETNODE(Y)
/*삽입할 Y노드를 생성*/
DATA(Y)←item
/*Y노드에 데이터 값을 저장*/
if (Head=nil) then Head←Y
/* Head노드가 nil인 경우 Head가 Y를 가리키도록 한다. */
LINK(Y)←nil
/* 마지막노드는 항상 null임 */
else LINK(Y)←LINK(X) /* ② */
LINK(X)←Y /* ② */
end INSERT
void insert(listPointer *first, listpointer X)
{ /* data = 50인 새로운 노드를 체인 first의 노드 x뒤에 삽입 */
listPointer temp;
MALLOC(temp, sizeof(*temp));
temp→data = 50l
if (*first) {
temp→link = x→link;
x→link = temp;
}
else {
temp→link = NULL;
*first = temp;
}
}
procedure DELETE(X, Y, Head)
/* Y: 삭제할 노드, X:Y노드의 선행 노드 */
/
if (Head = nil) call List-empty
/* 리스트에 노드가 존재하지 않으므로 삭제 노드가 없다. */
if (X=nil) then Head←LINK(Head)
/* 첫 번째 노드 삭제 */
else LINK(X)←LINK(Y)
/* 중간 노드 삭제 */
call RET(Y)
end DELETE
void delete (listPointer *fisr, listPointer trail, listPointer node) {
/* 리스트로부터 노드를 삭제, trail은 삭제될 x의 선행 노드이며 first는 리스트의 시작 */
if (trail)
trail→link = x→link;
else
*first = (*first)→link;
free(x);
}
procedure INSERT(T, Y) /* T(헤드 포인터)는 마지막 노드를 가리킨다. */
/* Y가 지시하는 노드를 원형 리스트의 맨 앞에 삽입 */
① if T = nil then T←Y /* 리스트가 빈 상태로 T가 Y를 지시 */
LINK(Y) ← T /* Y가 지시하는 노드는 자신을 가리킨다. */
② else LINK(Y)←LINK(T) /* 새 리스트가 첫 번째 노드를 지시 */
③ LINK(T)←Y /* 마지막 노드의 링크 필드가 새 노드를 지시 */
end INSERT
```c
void insertFront(listPointer last, listPointer node)
{ /* 리스트의 마지막 노드가 last인 원형 리스트의 앞에 노드를 삽입한다. */
if(!(*last)) { /* 리스트가 공백일 경우, last가 새로운 항목을 가리키도록 변경시킨다. */
*last = node;
node→link = node;
}
else { /* 리스트가 공백이 아닌 경우, 리스트 앞에 새로운 항목을 삽입한다. */
node→link = (*last)→link;
(*last)→link = node;
}
}
```
procedure INSERT(T, Y) /* T(헤드 포인터)는 마지막 노드를 가리킨다. */
/* Y가 지시하는 노드를 원형 리스트의 맨 뒤에 삽입 */
if T = nil then T←Y /* T가 Y를 가리킨다. */
LINK(Y)←T /* 리스트가 빈 상태로 Y가 자신을 지시 */
① else LINK(Y)←LINK(T) /* 새 리스트가 첫 번째 노드를 지시 */
② LINK(T)←Y /* 마지막 노드의 링크 필드가 새 노드를 지시 */
③ T←Y /* T가 Y를 가리킨다 */
end INSERT
void insertFront(listPointer last, listPointer node)
{ /* 리스트의 마지막 노드가 last인 원형리스트의 뒤에 노드를 삽입한다. */
if (!last) { /* 리스트가 공백일 경우, last가 새로운 항목을 가리키도록 변경시킨다. */
last = node;
node→link = node;
]
else { /* 리스트가 공백이 아닌 경우, 리스트의 뒤에 새로운 항목을 삽입한다. */
node→link = last→link;
last→link = node;
last = node;
}
}
void cerase(polyPointer ptr)
{ /* ptr이 가리키는 원형 리스트 삭제 */
polyPointer temp;
if(ptr) {
temp = ptr→link; /* ① */
ptr→link = avail; /* ② avail은 가용공간 리스트 */
avail = temp; /* ③ */
ptr = NULL;
}
}