Cài đặt từ điển bằng bảng băm mở

Một phần của tài liệu Giáo Trình Cấu Trúc Dữ Liệu Và Thuật Toán (Trang 70 - 72)

a) Định nghĩa bảng băm mở

Tư tưởng cơ bản của bảng Băm là: Phân chia một tập hợp đã cho thành một số cố định các lớp (N lớp) được đánh số 0, 1, …, N-1. Sử dụng mảng T với chỉ số chạy từ 0 đến N-1. Mỗi thành phần T[i] chứa một con trỏ, trỏ tới phần tử đầu tiên của danh sách chứa các phần tử của tập hợp thuộc lớp thứ i. Các phần tử của tập hợp thuộc mỗi lớp được tổ chức dưới dạng một danh sách liên kết, mỗi danh sách được gọi là con tr“rổ” , T được gọi là bảng Băm (hash table).

Việc chia các phần tử của tập hợp vào các lớp được thực hiện bời hàm băm (hash function) h. Nil nil 0 1 n-1 Hình 1: Cấu trúc bảng băm mở Nil

b) Hàm băm:

Hàm băm là một ánh xạ từ tập dữ liệu A đến các số nguyên 0..N-1: h : A → 0..N-1;

Theo đó giả sử x  A thì h(x) là một số nguyên sao cho: 0≤h(x) ≤N-1. Có 2 tiêu chuẩn chính để lựa chọn một hàm băm:

+ Hàm băm phải cho phép tính được dễ dàng và nhanh chóng giá trị Băm của mỗi khoá

+ Nó phải phân bố đều các khoá vào các rổ

Có nhiều cách để xây dựng hàm băm, cách đơn giản nhất là ‘nguyên hóa x ‘ và sau đó lấy h(x) = x % N. Ví dụ, cho tập hợp A = {1, 5, 7, 2, 5, 15}. Bảng băm là mảng gồm 5 phần tử và hàm băm h(x) = x % 5; Ta có bảng băm lưu trữ A như sau :

Hàm băm có thể được thiết kế như sau

int h(X: KeyTypedef struct) {

H = X%B; };

Ví dụ: Viết một hàm Băm trong Pascal (sử dụng phương pháp lấy phần dư) để băm các khoá là các xâu ký tự có độ dài 10 thành các giá trị từ 1 đến N-1

#define B ? / * s u i t a b l e value f o r B * /

int f ( char *key ) { i n t i , sum; sum = 0 ; for ( i = 0 ; i < s t r l e n ( key ) ; i ++ ) sum += key [ i ] ; return ( sum % B ) ; }

c) Cài đặt từ điển bởi bảng băm mở:

Mỗi phần tử trong “rổ” có thể được mô tả theo cấu trúc sau:

typedef struct c e l l

Bảng băm mở

Bảng băm chứa các con trỏ, trỏ tới các phần tử đầu mỗi danh sách

{

char *key ;

/ * ot he r u s e f u l i n f o * /

struct c e l l *next ; } NodeT;

Sau đó, con trỏ đầu mỗi rổ là:

NodeT *BucketTable[ B ] ;

d) Cài đặt các phép toán trên từ điển

1 - Khởi tạo bảng băm mở rỗng

Lúc này tất cả các “rổ” là rỗng nên ta gán tất cả các con trỏ trỏ đến đầu các danh sách trong mỗi rổ là null.

2 - Kiểm tra một thành viên có trong từ điển không

Để kiểm tra xem phần tử x nào đó có trong từ điển hay không, ta giá trị băm (h(x)) của nó. Theo cấu trúc của bảng băm thì khoá x sẽ nằm trong “rổ” được trỏ bởi T[h(x)]. Như vậy để tìm khoá x trước hết ta phải tính h(x) sau đó duyệt danh sách của “rổ” được trỏ bởi T[h(x)] để tìm x.

3 - Thêm một phần tử vào từ điển

Để thêm một phần tử có khóa x vào từ điển ta phải tính h(x) để xác định xem nó sẽ được thêm vào “rổ”/ “lớp” nào. Vì ta không quan tâm đến thứ tự các phần tử trong mỗi “rổ” nên ta đ ể đ ơ n g i ả n t a thêm phần tử mới ngay đầu “rổ” này. 5 - Xoá một phần tử trong từ điển

Xoá một phần tử x trong từ điển, ta làm như sau: - Tính giá trị băm h(x)

- Kiểm tra xem phần tử x có thuộc “lớp” được trỏ bởi T[h(x)] không? Nếu có thì loại bỏ phần tử này. Khi loại x cần phân biệt x nằm ở đầu “lớp” và x không nằm ở đầu “ lớp”.

Một phần của tài liệu Giáo Trình Cấu Trúc Dữ Liệu Và Thuật Toán (Trang 70 - 72)

Tải bản đầy đủ (PDF)

(76 trang)