intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

PHÉP BIẾN ĐỔI KHÓA – HÀM BĂM

Chia sẻ: 123968574 123968574 | Ngày: | Loại File: PDF | Số trang:42

185
lượt xem
21
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Băm là phương pháp rất thích hợp để cài đặt tập hợp có số phần tử lớn và thời gian cần thiết để thực hiện các phép toán từ điển, ngay cả trong trường hợp xấu nhất, là tỉ lệ với cỡ của tập hợp. Chúng ta sẽ đề cập tới hai phương pháp băm khác nhau. Một gọi là băm mở cho phép sử dụng một không gian không hạn chế để lưu giữ các phần tử của tập hợp. Phương pháp băm khác được gọi là băm đóng sử dụng một không gian cố định do đó tập...

Chủ đề:
Lưu

Nội dung Text: PHÉP BIẾN ĐỔI KHÓA – HÀM BĂM

  1. PHÉP BIẾN ĐỔI KHÓA – HÀM BĂM Băm là phương pháp rất thích hợp để cài đặt tập hợp có số phần tử lớn và thời gian cần thiết để thực hiện các phép toán từ điển, ngay cả trong trường hợp xấu nhất, là tỉ lệ với cỡ của tập hợp. Chúng ta sẽ đề cập tới hai phương pháp băm khác nhau. Một gọi là băm mở cho phép sử dụng một không gian không hạn chế để lưu giữ các phần tử của tập hợp. Phương pháp băm khác được gọi là băm đóng sử dụng một không gian cố định do đó tập hợp được cài đặt phải có cỡ vượt qua không gian cho phép $1. Khái niệm băm và hàm băm. 1.1. Băm mở và hàm băm. a. Băm mở. Nội dung cơ bản của băm mở là phân chia tập hợp đã cho thành một số cố định các lớp. Chẳng hạn ta muốn phân thành N lớp được đánh số 0,1,..,N-1. Ta 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] cúa mảng được nói đến như một rổ đựng 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 tổ chức dưới dạng một danh sách liên kết. Do T[i] sẽ chứa con trỏ trỏ đến danh sách của lớp i. b. Bảng băm. Ta gọi mảng T mà mỗi phần tử của nó như là một rổ đựng các phần tử của tập hợp thuộc lớp tương ứng là bảng băm. Việc phân 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 h. c. Hàm băm. Nếu x là một giá trị khoá của phần tử nào đó của tập hợp thì h(x) là chỉ số nào đó của mảng T và ta gọi h(x) là giá trị băm (hash value) của x. Như vậy h là ánh xạ từ tập hợp các khoá K vào tập hợp { 0,1,…,N-1}. $.2. Các phương pháp lựa chọn, thiết kế hàm băm và giải quyết va chạm. 2.1. Các phương pháp lựa chọn, thiết kế hàm băm Có hai tiêu chuẩn chính để lựa chọn hàm băm. Trước hết nó phải cho phép tính được dễ dàng và nhanh chóng giá trị băm của mỗi khoá. Thứ hai, nó phải phân bố
  2. đều các khóa vào các rổ. Trên thực tế tiêu chuẩn thứ hai rất khó được thực hiện. Sau đây chúng ta đưa ra một số phương pháp thiết kế hàm băm. a. Phương pháp cắt bỏ. Giả sử khoá là số nguyên (nếu khoá không phải là số nguyên, ta xét đến các mã số của chúng). Ta sẽ bỏ đi một phần nào đó của khóa, và lấy phần còn lại lám giá trị băm của khoá. Chẳng hạn nếu khoá là các số nguyên gồm 10 chữ số và bảng băm gồm 1000 thành phần, khi đó ta có thể lấy chữ số thứ nhất, thứ ba và thứ bảy từ bên trái làm giá trị băm. Ví dụ: h(7103592810) = 720. Phương pháp cắt bỏ rất đơn giản nhưng nó thường không phân bố đều các khoá. b. Phương pháp gấp. Giả sử khoá là số nguyên. Ta phân chia khóa thành một số phần, sau đó kết hợp các phần lại bằng một cách nào đó (phép cộng hoặc phép nhân) để nhận giá trị băm. Nếu khoá là số nguyên 10 chữ số ta phân thành các nhóm ba ba hai hai chữ số từ bên trái, cộng các nhóm với nhau sau đó cắt cụt nếu cần thiết, ta sẽ nhận được giá trị của hàm băm. Ví dụ: số 7103592810 được biến đổi thành 710+359+28+10 = 1107, do đó ta có giá trị băm là 107. Vì mọi thông tin trong khoá đều được phản ánh vào giá trị băm, nên phương pháp gấp cho phân bố đều các khoá hơn phương pháp cắt bỏ. c. Phương pháp sử dụng phép toán lấy dư. Giả sử khoá là số nguyên và ta muốn chia tập hợp các khoá thành n lớp. Chia số nguyên cho n rồi lấy phần dư làm giá trị băm. Điều này trong Pascal được thực hiện bằng phép toán mod. Tính phân bố đều các khoá của hàm băm được xác định bằng phương pháp này phụ thuộc nhiều vào việc chọn n. Tốt nhất chọn n là số nguyên tố. Chẳng hạn thay cho việc chọn n = 1000 ta sẽ chọn n = 997 hoặc n = 1009. Ví dụ viết một hàm băm trong Pascal để băm các khoá là các xâu kí tự có độ dài 10 thành các giá trị từ 0…n-1. Type keytype = string[10]; Function h(x: keytype):0..n-1;
  3. Var i, sum:integer ; Begin Sum:=0; For i=1 to 10 do Sum=sum + ord(x[i]); h:= sum mod n; end. Trong hàm băm trên, ta đã chuyển đổi các xâu kí tự thánh các số nguyên bằng cách lấy tổng số của các mã số của từng kí tự trong xâu dùng hàm ord(c) để lấy mã số của kí tự c. 0 1 2 2.2. Bảng băm đóng. Trong bảng băm mở, mỗi thành phần T[i] của bảng lưu trữ con trỏ trỏ tới danh sách các phần tử của tập hợp được đưa vào lớp thứ i (i = 0,…,N-1). a. Băm đóng. Khác với bảng băm mở, trong bảng băm đóng, mỗi phần tử của tập lưu giữ trong chính các thành phần T[i] của mảng. Do đó ta có thể khai báo kiểu dữ liêụ từ điển được cài đặt bởi bảng băm đóng như sau:
  4. Type Dictionary = array [0..N-1] of keytype; Keytype là kiểu dữ liệu của khoá của các phần tử trong từ điển. 2.3. Phân tích, đánh giá và minh họa phương pháp băm. a. Phân tich đánh giá. Trong tất cả những thuật toán được xét từ trước tới nay, việc định vị một mục được xác định bởi một dãy các so sánh. Trong mỗi trường hợp, mục cần tìm được so sánh nhiều lần với các mục ở những vị trí nào đó trong cấu trúc. Đối với nhóm n mục, phép tìm kiếm tuyến tính đòi hỏi O(n) lần so sánh, trong khi đó phép tìm kiếm nhị phân chỉ cần O(log n) lần so sánh. Trong một số trường hợp, những thuật toàn này thực hiện còn quá chậm. Ví dụ, bảng các kí hiệu được lập bởi bộ dịch lưu trữ các định danh và những thông tin về chúng. Vận tốc xây dựng và tìm kiếm trong bảng này quyết định vận tốc dịch. Một cấu trúc dữ liệu thực hiện tìm kiếm nhanh hơn, được gọi là bảng băm (hash T), trong đó vị trí cuả một mục được xác định trực tiếp bằng một hàm của chính nó chứ không phải bằng một dãy các so sánh thử và sai (trial-and-error). Thời gian gian cần thiết để định vị một mục trong bảng băm trong trường hợp tốt nhất là O(1), nghĩa là nó là một hằng số và không phụ thuộc vào số các mục được lưu trữ. b. Ví dụ minh họa. Để minh hoạ, giả sử rằng cần lưu trữ 25 số nguyên trên đoạn 0..999 trong bảng băm. Có thể cài đặt bảng băm này bằng một mảng T các số nguyên được đánh chỉ số trên đoạn 0..999, trong đó mỗi phần tử của mảng được khởi động tại một giá trị câm nào đó, chẳng hạn như tại 1. Nếu ta dùng mỗi số nguyên i trong tập hợp đó làm chỉ số, nghĩa là nếu ta lưu trữ i trong T[i], ta có thể định vị một số nguyên number cho trước chỉ bằng cách kiểm tra T[number] =number hay không. Hàm h được định nghĩa bởi h(i)=i xác định vị trí của mục i trong bảng băm. Hàm băm trong vị dụ này thực hiện tìm kiếm một cách lý tưởng vì thời gian cần thiết để tìm kiếm một giá trị cho trước trong báng là hằng số; chỉ cần thử một vị trí. Như vậy, sơ đồ này hiêu quả về tính thời gian, nhưng không hiệu quả về không gian, chỉ 25 trong số 1000 vị trí khả dĩ được dùng để lưu trư các mục còn 975 vị trí còn lại không được dùng do đó đã lãng phí 97,5% không gian, chỉ dùng 2,5%.
  5. Vì có thể lưu trữ 25 giá trị ở 25 vị trí ta có thể sử dụng tốt hơn bằng cách dùng mảng T được đánh chỉ số trên đoạn từ 0 đến 24. Dĩ nhiên là không thể dùng hàm băm ban đầu h(i)=i được nữa. Thay vào đó ta có thể dùng: h(i)=i mod 25 Vì hàm này luôn luôn có miền giá trị là những số nguyên trên đoạn từ 0 đến 24. Như vậy số nguyên 52 sẽ được lưu trữ ở T[2] vì h(52)= 52 mod 25 = 2. Tương tự với các số nguyên 129; 500 ; 73; 49 sẽ được lưu tại các vị trí 4, 0, 23 và 24 theo thứ tự đó. T[0] 500 -1 T[1] 52 T[2] T[3] -1 129 T[4] -1 T[5] . . . . 273 T[23] 49 T[24] Với ví dụ trên nếu lấy hàm h[i]:=i mod 25 thì sẽ xẩy ra hiện tượng gọi là sự va chạm. vì nếu 77 được lưu trữ, nó sẽ được đặt vào vị trí h(77)= 77 mod 25 = 2, nhưng vị trí này đã bị chiếm bởi 52. Cũng bằng cách đó, nhiều giá trị khác có thể trùng vào một vị trí cho trước,ví dụ,2,27,102 và trong thực tế tất cả các số nguyên dạng 25k + 2 đều được lưu trữ tại vị trí 2. Dĩ nhiên là cần phải có một cách nào đó để giải quyết những va chạm này. $3. Các phương pháp xử lý va chạm. 3.1.Phương pháp thăm dò tuyến tính. a. Nội dung. Trong sơ đồ này, phép tuyến tính trong bảng bắt đầu từ chỗ có va chạm và tiếp tục dò đền khi tìm thấy một khe trống có thể lưu trữ được, va chạm với giá trị 52 ở vị trí 2, một cách đơn giản là ta đặt 77 ở giá trị 3; để chèn 102,
  6. chúng ta đi theo dãy thăm dò gồm các vị trí 2, 3, 4 và 5 để xác định vị trí đầu tiên có thể dùng được và lưu trữ 102 ở T[5]. Khi đặt đến cuối bảng, ta lại tiếp tục ở vị trí đầu tiên. Ví dụ, 123 được lưu trữ ở vị trí 1 vì nó va chạm với 273 ở vị trí 23, và dãy thăm dò 23, 24, 0, 1 xác định khe rỗng đầu tiên ở vị trí 1. 500 T[0] T[1] 123 T[2] 52 T[3] 77 T[4] 129 T[5] 102 . . . . 273 T[23] 49 T[24] Để xác định một giá trị cho trước có nằm trong bảng băm này hay không, trước hết ta dùng hàm băm để tính vị trí có thể tính trong bảng xẩy ra các khả năng: + Thứ nhất, nếu vị trí này rỗng (chứa -1), ta có thể kết luận ngay rằng giá tri này không có trong bảng. +Thứ hai, nếu vị trí này chứa giá trị nói trên, ta biết ngay rằng là đã tìm ra. +Thứ ba, vị trí này có một giá trị khác với giá trị đang tìm do sự va chạm gây ra bởi cách lập bảng. Trong trường hợp này ta thực hiện tìm kiếm tuyến tính “vòng” tại vị trí này, và tiếp tục cho đến khi tìm thấy giá trị đó hoặc đạt đến vị trí rỗng hay vị trí khởi đầu, điều này chỉ ra rằng mục cần tìm không có trong bảng. Như vậy thời gian tìm kiếm trong hai trường hợp đầu là hằng số, còn trong trường hợp thứ ba không phải thế. Nếu bảng gần đầy, ta phải thử hầu hết các vị trí trước khi tìm ra mục đó hay trước khi kết luận rằng mục đó không có trong bảng. Để làm tốt hơn việc tìm kiếm, ta có thể thực hiện ba việc dưới đây: - Mở rộng kích thước của bảng. - Dùng phương pháp khác để giải quyết va chạm. - Dùng một hàm băm khác. b. Nhận xét.
  7. - Việc làm cho kích thước của bảng bằng số các mục được lưu trữ như trong ví dụ đầu tiên không thực tế lắm, nhưng nếu dùng bảng nhỏ hơn có khả năng dẫn tới va chạm. Trong thực tế, ngay cả khi có thể l ưu trữ nhiều hơn hẳn số mục cần thiết vẫn có khả năng xảy ra va chạm. Ví dụ, với bảng băm gồm 365 vị trí lưu trữ 23 mục được chọn ngẫu nhiên, xác xuất xảy ra va chạm là lớn hơn 0.5 (Điều này liên quan đến bài toán sinh nhật: xác xuất để ít nhất 2 trong 23 người có cùng ngày sinh là lớn hơn 50%). Như vậy rõ ràng rằng việc chờ đợi một bảng băm hoàn thiện không bị va chạm là không xác đáng. Thay vào đó, chúng ta phải thoả mãn với với số va chạm đủ ít. Những nghiên cứu thực nghiệm cho phép chúng ta dùng những bảng có độ dài khoảng từ 1.5 đến 2 lần số mục cần lưu trữ. - Cách thứ hai để hoàn thiện việc tìm kiếm là thiết kế một phương pháp xử lý va chạm tốt hơn. Trong sơ đồ thăm dò tuyến tính, khi xảy ra va chạm, giá trị va chạm được lưu trữ ỏ những vị trí được để dành cho các mục băm trực tiếp đến các vị trí ấy. Lối tiếp cận “lấy của Peter để trả cho Paul” này làm tăng xác xuất xảy ra va chạm, như vậy làm cho vấn đề phức tạp hơn. 3.2. Phương pháp dây chuyền(chaining). Phương pháp này dùng các danh sách liên kết để lưu trữ các giá trị. Trong phương pháp này, ứng với một địa chỉ của bảng ta có một danh sách liên kết chứa các phần tử có khóa khác nhau mà có cùng một địa chỉ. Để minh họa, giả sử ta muốn lưu trữ một nhóm các tên. Ta có thể dùng mảng T chứa các con trỏ được đánh chỉ số trên đoạn ‘A’..’Z’, lúc đầu là rỗng, và dùng hàm băm h(Name) = Name[1]. Ví dụ ‘Adam,John’ và ‘Doe,Mary’ được lưu trữ trong các nút được chỉ bởi T[‘A’] và T[‘D']: T[‘A”] ● Adams,Joh T[‘B’] T[‘C’] T[‘D’] T[‘E’] ● Doe, Mary T[‘F’] . . T[‘Y’] T[‘Z’]
  8. Khi xảy ra va chạm, ta chèn mục mới vào vị trí thích hợp của danh sách liên kết . Ví dụ, vì h(‘Davis, Joe’) = h(‘Doe, Mary’) = ‘D’, va chạm xảy ra khi ta muốn lưu trữ tên ‘Davis, Joe’, ta đưa thêm một nút mới chứa tên này vào danh sách liên kết được ghi bởi T[‘D’]: T[‘A”] ● Adams,John T[‘B’] T[‘C’] T[‘D’] T[‘E’] ● ● Davis, Joe Doe, Mary T[‘F’] . . . . T[‘Y’] T[‘Z’] a. Khai báo. Type ref=^node; Node=record Key:integer; Info:integer; Next:ref; end; Var heads : aray[0..M-1] of ref; t,z: ref; T[0] ● ● ● T[1] ● ● ● T[2] T[3] T[4] ● T[4] . z . . . ● ● ● T[M-2] ● ● ● T[M-1]
  9. b. Khởi tạo bảng băm.Mảng heads chứa các con trỏ đấu chỉ vào danh sách liên kết. Phép khởi tạo bảng băm cho các phần tử đầu chỉ đến phần tử cầm canh z Procedure Initialize; Var i:integer; Begin New(z); Z^.next:=z; ● For i:=1 to M-1 do z . . Begin New(heads[i]; heads[i]^.next:=z; end; end; c. Thêm một khóa mới vào bảng băm. - Hàm Them_moi(k,heads[k mod M]) thực hiện thêm phần tử có khóa k vào danh sách liên kết của bảng băm. - Các danh sách liên kết thuộc vùng tràn đã có thứ tự. - Nếu đã có nhiều phần tử cùng khóa thì phần tử mới là đầu bảng băm. - Giá trị của hàm là địa chỉ của phần tử mới thêm vào. Function THEM_MOI(k:integer; u:ref): ref; Var x,p:ref; Begin Z^.key:=k; { gán k cho phần tử cầm canh} {Timf khóa k trong danh sách liên kết có con trỏ đầu là p} p:=u^.next { u là phần tử đứng ngay trước p} while p.key
  10. THEM_MOI:=x; End; ● ● ● ● ● ● ● x ● . z . ● ● ● ● ● ● Nút màu vàng là nút cuối cùng có khóa nhỏ hơn k. Ghi chú: - Nút màu xanh có khóa >= khoa k. - Nút màu đỏ là nút x có khoa k. - d. Tìm kiềm khpóa trong bảng băm. - Hàm TIM_KHOA(k,heads[k mod M]) thực hiện tìm phần tử đầu tiên có khóa k. - Để tìm tiếp các phần tử tiếp có khóa k ta gán u:=TIM_KHOA(k,u) cho đến khi u=z. - Giá trị của hàm là địa chỉ của phần tử tìm thấy hoặc phần tử cầm canh z. Function TIM_KHOA(k:integer; u:ref): ref; Var x,p:ref; {Tìm một khóa trong ds liên kết} Begin Z^.key:=k; { gán k cho phần tử cầm canh} repeat u:=u^.next; until k
  11. C N z z E E E P z z G R z H S z I z z 3.3. Phương pháp nối kết hợp nhất. a.Đạt vấn đề. Giả sử các khóa có giá trị hàm băm và giá trị thêm vào như sau: Khóa: A B C D Hash: 1 21 1 Khi thêm khóa A vào bảng vì H(A)=1 là vị trí trống nên ta thêm ngay tại vị trí số 2. Khi thêm C vào bảng vì H(C)=1 trùng với H(A) nên đụng độ nên ta tìm kiếm vị trí trống đầu tiên từ dưới lên để đặt C vào (ta đặt vào vị trí M) và cho next của vị trí 1 chỉ vào M. Khi thêm khóa D, v ị trí của H(D)=1, vì rằng 1 đã chứa A ta đi theo vùng next của vị trí này và đến M nhưng vì M đã chứa khoa C và vùng next của khóa này chưa có (0) nên ta thêm khóa D vào vị trí M-1 và cho next của vị trí M chỉ đến vị trí M-1. 0 A 1 B 2 . . M-1 D MC b. Khai báo và khởi tạo bảng băm. - Const free= maxint; Type=record Key:integer; Next:integer; End; Var T:aray[0..M] of Item; r:integer;
  12. - Procedure Initialize; var i:integer; Begin For i:=0 to M do T[i].key:=free; R:=M+1; End; c. Thêm một khóa vào bảng băm. - Hàm THEM_KHOA(k:integer) thực hiện việc thêm khóa k vào bảng băm. - Giá trị của hàm trả về vị trí của phần tử thêm vào hoặc 0 nếu bảng băm đầy. - Nếu đã có khóa k ở trong bảng thì hàm cho biết vị trí của khóa này trong bảng băm mà không thêm vào khóa này. - Phần tử ở vị trí 0 luôn là vị trí trống, nó được sử dụng để đảm bảo việc tìm kiếm luôn kết thúc thành công, nó đống vai trò như phần tử cầm canh. Function THEM_KHOA(k:integer):integer; Var i,j :integer; Begin I:=H(k)+1; {0
  13. if (i0) and (T[i].keyk) then begin T[i].key:=k; T[i].next:=0; End; THEM_KHOA:=i; End; c)Phương pháp băm kép: Ví dụ, ta có thể dùng một mảng các con trỏ chỉ đến các nút gốc của các cây tìm kiếm nhị phân và dúng các thủ tục chèn và tìm kiếm ở phần trước. Một sơ đồ phổ biến khác, gọi là băm kép sẽ được mô tả tương tự như phương pháp dò tuyến tính, chỉ khác là thay vì kiểm tra mỗi phần tử liên tiếp tại vị trí xung đột đó, do đó số lần dò sẽ giảm đi so với dò tuyến tính, chúng ta dùng một hàm băm thứ hai. Chú ý, hàm băm thứ hai h2 phải được chọn cẩn thận ở một vài khía cạnh, nếu không thì chương trình có thể không hoạt động tốt. Yếu tố thứ ba trong việc thiết kế bảng băm là việc chọn bảng băm. Dĩ nhiên là dáng điệu của hàm này ảnh hưởng đến tần số va chạm. Ví dụ, hàm băm h(Name) = Name[1] ở ví dụ trước không phải là sự chọn lựa tốt vì một vài kí tự như các chữ đầu của tên xuất hiện nhiều lần hơn các kí tự khác. Do đó danh sách liên kết của các tên bắt đầu bằng ‘S’ sẽ dài hơn nhiều so với các danh sách chứa những tên bắt đầu bằng ‘Z’. “Hiệu ứng chùm” này làm cho việc tìm kiếm các tên bắt đầu bằng S lâu hơn bắt đầu bằng Z. Một hàm băm tốt hơn phân phối đến các tên trong bảng băm có thể là giá trị “trung bình” của các kí tự đầu và cuối trong tên. h(Name) = chr(ord( FirstLetter ) + ord(LastLetter) div 2) hoặc có thể dùng gía trị trung bình của tất cả các kí tự. Tuy nhiên hàm băm không được quá phức tạp để việc tính nó có thể chấp nhận được. Một hàm băm lý tưởng dễ tính và rải đều các mục trong bảng băm làm giảm xác xuất va chạm đến giá trị nhỏ nhất. Mặc dù không có phương pháp băm nào hoàn thiện trong mọi trường hợp, một phương pháp thông dụng hiện thời là băm ngẫu nhiên kỹ thuật tạo số ngẫu nhiên để rải đều các mục trong bảng băm “một cách ngẫu nhiên”. Trước hết mục đó được chuyển sang một số nguyên lớn ngẫu nhiên bằng cách dùng một lệnh, chẳng hạn như: RandomInt := (( 25173 * Item ) + 13849) mod 65536
  14. Và gía trị này được chia theo môđun kích thước bảng để xác định vị trí của mục: Location := RandomInt mod TSize; Có thể dùng hàm băm này với các mục không phải là số nguyên nếu trước hết ta mã hoá những mục này như là những số nguyên; ví dụ, một tên có thể được mã hoá như tổng của các mã số ASCII của một vài hoặc tất cả các giá trị của kí tự đó. Chương trình giải quyết một số bài toán về hàm băm: Bài 1: dùng bảng băm với 11 vị trí và hàm băm h(i)=I mod 11 ,hãy chỉ ra bang băm nhận được sau khi chèn các số nguyên sau theo thư tự : 26, 42, 5, 44, 92, 59, 40, 36, 12, 60, 80. Dùng : a. Thăm dò tuyến tính b. Phương pháp dâu truyền Để giai quyết va chạm.
  15. để giải quyết bài toán trên ta xây dựng hàm băm và bảng băm với kích thước 100 và chọn m=97 thay vì 11 .Như vậy chúng ta có thể nhập được tối đa 100 phần tử Xây dựng thủ tục tìm kiếm để thấy được ưu điểm của việc sử dụng bảng băm lưu trữ các phần tử: Do các phần tử được lưu vào bảng băm tai vị trí úng với giá trị băm (khoá) của nó nên chúng ta không cần phải sắp xếp -> rút ngắn được thời gian cũng như số lượng phép toán trong quá trình tim kiếm Chương trình: program tp; {uses crt;} const m=97; var n,i,dai,kq,j:integer; {"dai" la bien do do dai cua xau} x,a,tk: string ; {"tk" la bien chi xau can tim kiem} bangbam : array[0..101] of string; ch:char; function h( var x:string) :integer; var tong,j:integer; begin dai:=length(x); tong:=0; for j:=1 to dai do tong:=tong+ ord(x[j]); h:= tong mod m; end; procedure timkiem; begin writeln; writeln('nhap chuoi can tim'); readln(tk); writeln('gia tri bam cua ',tk,' la ',h(tk)); if bangbam[h(tk)]=tk then begin writeln('co chuoi ',tk,' trong co so du lieu'); writeln('vi tri cua chuoi ',tk,' trong co so du lieu la',h(tk));
  16. end else begin i:=h(tk); repeat i:=i+1; until (i=99) or( bangbam[i]=tk); if i=99 then writeln('khong co chuoi ',tk,' trong co so du lieu') else begin writeln('co chuoi ',tk,' trong co so du lieu'); writeln('chuoi ', tk, ' thuoc vi tri thu ',i,' trong bang bam ') ; writeln('vi tri cua chuoi tren khac voi gia tri bam la do da xay ra va cham '); end; end; end; begin {CHUONG TRINH CHINH } writeln('ban muon nhap bao nhieu phan tu? chu y "NHAP DANG SO "!'); readln(n); while n>100 do begin writeln(' so phan tu ma ban nhap vao la qua lon !nhap lai voi so phan tu nho hon 100'); readln(n); end ; for i:=0 to 100 do bangbam[i]:=''; for i:=0 to n-1 do begin writeln('nhap gia tri thu',i+1); readln(a); if bangbam[h(a)]='' then
  17. begin bangbam[h(a)]:=a ; writeln('gia tri cua ',a,' trong bang bam la',h(a)); end else if bangbam[h(a)]=a then begin repeat writeln('da co sau tren trong co so du lieu ! de nghi nhap mot sau khac') ; readln(a); until bangbam[h(a)]='' ; bangbam[h(a)]:=a; writeln('gia tri bam cua sau da nhap la ',h(a)); end else if bangbam[h(a)]a then begin writeln('da xay ra va cham tai vi tri ',h(a),' trong bang bam'); j:=h(a) ; repeat j:=j+1 ; until bangbam[j]=''; bangbam[j]:=a; writeln('gia tri bam cua chuoi ',a,' sau khi giai quyet va cham la ',j); end; end; writeln('ban co muon thuc hien thao tac tim kiem khong? Y\N'); readln(ch); if ((ch='Y') or (ch = 'y')) then timkiem ; readln; end.
  18. Bµi tËp 1 gi¶i b»ng ph­¬ng ph¸p d©y truyÒn program bai1; type banghi=record ten:string; end; elementtype=banghi; point=^usernode; usernode=record data:elementtype; next:point; end; bangbam=array[0..12] of point; var f:text; userRec:banghi; userT:bangbam; found:boolean; loc:integer; p:point; ten:string; c:char; dem:integer; procedure khoitao(var T:bangbam); var i:integer; begin for i:=0 to 12 do T[i]:=nil; end;
  19. function hambam(ten:string):integer; var tong:integer; i:integer; begin tong:=0; for i:=1 to length(ten) do tong:=tong+ord(ten[i]); hambam:=tong mod 11; end; procedure timkiem(T:bangbam;item:elementtype); begin loc:=hambam(item.ten); p:=T[loc]; found:=false; dem:=1; while not found and (pnil) do if p^.data.ten=item.ten then begin found:=true; writeln('da co o vi tri ',loc,'-',dem); end else begin dem:=dem+1; p:=p^.next; end; end; procedure nhap(var T:bangbam;item:elementtype);
  20. begin timkiem(T,item); if found=false then begin new(p); p^.data:=item; p^.next:=T[loc]; T[loc]:=p; writeln('da dien vao vi tri ',loc,'-',dem); end; end; procedure ghi; var i:integer; begin for i:=1 to 11 do begin write('',i,': '); begin p:=userT[i]; while pnil do begin write('',p^.data.ten,' '); p:=p^.next; end; writeln; end; end; end; procedure doc;
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2