Phần tử cuối cùng có giá trị x hoặc không tìm thấy xN+1 Xấu nhất Phần tử đầu tiên có giá trị x 1 Tốt nhất Giải thích Số lần so sánh Trường hợp Độ phức tạp thuật toán Tn=On... Tìm kiếm nh
Trang 1Cấu trúc dữ liệu và giải thuật
(Data structure and Algorithms)
Trang 2Tìm kiếm và sắp xếp
Chương II.
Trang 3I CÁC GIẢI THUẬT TÌM KIẾM NỘI
1 Tìm kiếm tuyến tính
2 Tìm kiếm nhị phân
II CÁC GIẢI THUẬT SẮP XẾP NỘI
1 Chọn trực tiếp (Selection sort)
2 Chèn trực tiếp (Insertion sort)
3 Đổi chỗ trực tiếp (Interchange sort)
4 Nổi bọt (Buble sort)
5 Sắp xếp cây (Heap sort)
6 Sắp xếp dựa trên phân hoạch (Quick sort)
7 Sắp xếp trộn trực tiếp (Merge sort )
Trang 4I CÁC GIẢI THUẬT TÌM KIẾM NỘI
1 Tìm kiếm tuyến tính
2 Tìm kiếm nhị phân
Trang 5* Bài toán tìm kiếm
• Cho dãy n phần tử, giả sử chúng được lưu trữ dưới dạng mảng a[1],
a[2], …., a[n], và các phần tử là số tự nhiên.
• Hãy tìm vị trí của phần tử có giá trị là x trong mảng
•Có 2 phương pháp tìm kiếm:
Tìm kiến tuyến tính Tìm kiếm nhị phân
Trang 61 Tìm kiếm tuyến tính
Các bước tiến hành như sau:
Bước 1 : i:=1; // bắt đầu từ phần tử đầu tiên của dãy
Bước 2 : So sánh a[1] với x, có 2 khả năng
a[i]=x: Tìm thấy Dừng
a[i] <>x: Sang Bước 3
Bước 3 : i:=i+1; // xét tiếp phần tử kế trong mảng
Nếu i>n: Hết mảng không tìm thấy Dừng
Ngược lại: Lặp lại Bước 2.
a Tư tưởng giải thuật
Tiến hành so sánh x lần lượt với phần tử thứ nhất, thứ 2, …., của mảng cho đến
khi gặp được phần tử có khoá cần tìm, hoặc tìm hết mảng mà không thấy x.
Trang 76 1
5 8
2 12
Hãy tìm phần tử x=8
Trang 81 Tìm kiếm tuyến tính
b Ví dụ:
15 4
6 1
5 8
2
12
X=8
i=1 : a[1 ]<> 8
Trang 91 Tìm kiếm tuyến tính
b Ví dụ:
15 4
6 1
5 8
2
12
X=8
i=2 : a[2]<>8
Trang 101 Tìm kiếm tuyến tính
b Ví dụ:
15 4
6 1
5
8
2 12
X=8
i=3 : a[3]=8=x
• Kết quả: Tìm thấy x=8 ở vị trí thứ 3 !
Trang 11c Thuật toán
1 Tìm kiếm tuyến tính
Function TuyenTinh (A, n, X)
{Nếu tìm thấy X, hàm trả về giá trị là vị trí của x trong dãy, ngược lại trả về giá trị 0}
Begin
1) { Khởi đầu}
i:=1;
2) {Tìm khoá x trong dãy}
While (a[i] <>x) and (i<n) do i:=i+1;
3) {Tìm thấy hay không}
If i=n+1 then return(0) Else return(i)
End;
Trang 12d Nhận xét
1 Tìm kiếm tuyến tính
Mỗi lần thực hiện lặp while phải tiến hành kiểm tra 2 điểm kiện i<n và a[i]<>x
Nhưng thực ra chỉ cần kiểm tra điều kiện a[i]<>x bằng cách sử dụng kỹ thuật lính canh.
Thuật toán cải tiến
Kỹ thuật lính canh : Đặt thêm phần tử x vào cuối mảng, như vậy bảo đảm luôn tìm được x trong mảng, sau đó dựa vào vị trí tìm để kết luận
4 6
1 5
8 2
Trang 13Phần tử cuối cùng có giá trị x hoặc không tìm thấy x
N+1 Xấu nhất
Phần tử đầu tiên có giá trị x
1 Tốt nhất
Giải thích
Số lần so sánh Trường hợp
Độ phức tạp thuật toán T(n)=O(n)
Trang 14a Tư tưởng giải thuật
2 Tìm kiếm nhị phân
• Áp dụng với những dãy đã có thứ tự (giả sử thứ tự tăng), các
phần tử trong dãy có quan hệ a i-1 <=a i <=a i+1
- Dãy a 1 , a 2 , …, a n đã được sắp xếp tăng dần, để tìm phần tử x, có thể
tiến hành như sau:
•Nếu x>a i : Thì x có thể xuất hiện trong đoạn [a i+1 , a n ]
•Nếu x<a i : Thì x có thể xuất hiện trong đoạn [a 1 , a i-1 ]
- Giải thuật tìm kiếm nhị phân sẽ tìm cách giới hạn phạm vi tìm kiếm x sau mỗi lần so sánh với 1 phần tử trong dãy Ý tưởng của giải thuật là tại mỗi bước tiến hành so sánh x với phần tử nằm ở vị trí giữa của dãy hiện hành, dựa vào kết qủa so ánh này để quyết định giới hạn dãy tìm kiếm ở bước kế tiếp là nửa trên hay nửa dưới của dãy hiện hành
Trang 15a Tư tưởng thuật toán
2 Tìm kiếm nhị phân
- Giả sử dãy tìm kiếm gồm các phần tử a[Left], …, a[Right] các
bước tiến hành như sau:
Bước 1 : left:=1; right:=N // Tìm kiếm trên tất cả các phần tử
Bước 2 : mid:= (left+right) div 2 // lấy mốc so sánh
So sánh a[mid] với x có 3 khả năng
Trang 168 6
5 4
2 1
Hãy tìm phần tử x=8
Trang 172 Tìm kiếm Nhị phân
b Ví dụ:
15 12
8 6
5
4 2
1
X=8
left=1; right=8; mid=4
•So sánh (x=8) > (a[mid]=5) Tìm kiếm nửa bên phải
left:=4+1=5
right:=8
mid:=(left+right) div 2=6
Trang 182 Tìm kiếm Nhị phân
b Ví dụ:
15 12
8
6 5
4 2
Trang 19c Thuật toán tìm kiếm nhị phân
Function NhiPhan (A, n, X)
{Cho dãy A gồm n phần tử tăng dấn Giải thuật này tìm xem trong dãy có phần tử nào có giá trị bằng X hay không Ở đây dùng các biến l, r, m để ghi nhận chỉ số phần tử đầu, phần tử cuối, phần tử giữa của dãy Nếu tìm kiếm được thoả, giá trị cho ra là vị trí của phần tử, nếu không thì cho ra giá trị 0}
Trang 20Phần tử đầu tiên có giá trị x
1 Tốt nhất
Giải thích
Số lần so sánh Trường hợp
Độ phức tạp thuật toán T(n)=O(log 2 n)
Trang 211 Chọn trực tiếp (Selection sort)
2 Chèn trực tiếp (Insertion sort)
3 Đổi chỗ trực tiếp (Interchange sort)
4 Nổi bọt (Buble sort)
5 Sắp xếp cây (Heap sort)
6 Sắp xếp dựa trên phân hoạch (Quick sort)
7 Sắp xếp trộn trực tiếp (Merge sort )
II CÁC GIẢI THUẬT SẮP XẾP NỘI
Trang 22II Sắp xếp
Sắp xếp là quá trình xử lý một danh sách các phần tử (hoặc các bản ghi) để đặt chúng theo thứ tự thoả mãn một tiêu chuẩn nào
đó dựa trên nội dung thông tin lưu giữ tại mỗi phần tử
Không mất tính tổng quát, giả sử mỗi phần tử trong danh sách
có một khoá để phân biệt, chúng ta sẽ tiến hành sắp xếp dãy khoá này.
Quy ước: Sắp xếp dãy số nguyên được lưu trữ bởi mảng
a[1], a[2], …, a[n]
Theo thứ tự tăng dần
Trang 231.Chọn trực tiếp
(Selection Sort)
Trang 24• Nguyên tắc cơ bản của phương pháp này là “ở lượt thứ i,
ta sẽ chọn trong dãy ai, ai+1, , an phần tử nhỏ nhất và đổi chỗ nó với ai“
• Như vậy sau j lượt, j khoá nhỏ hơn đã lần lượt ở các vị trí thứ nhất, thứ hai, …., thứ j theo đúng thứ tự sắp xếp.
1 Chọn trực tiếp
a Tư tưởng giải thuật
Trang 25a Tư tưởng giải thuật
Các bước tiến hành như sau:
Bước 1 : i:=1; // bắt đầu từ phần tử đầu tiên của dãy
Bước 2 : Tìm phần tử a[min] nhỏ nhất trong dãy hiện hành
Trang 27c Ví dụ: Sắp xếp dãy tăng dần
1 Chọn trực tiếp
Trang 361 Chọn trực tiếp
• Mảng đã sắp xếp xong !
Trang 382 Chèn trực tiếp
(Insertion sort)
Trang 392 Chèn trực tiếp (Insertion sort)
a Tư tưởng giải thuật
Giả sử có dãy A[1], A[2],…, A[n], trong đó i phần tử đầu A[1], …, A[i-1]
đã được sắp xếp
Ý tưởng chính của giải thuật là chèn phần tử A[i] vào vị trí thích hợp của đoạn đã được sắp xếp để được dãy A[1], A[2],…, A[i] có thứ tự
Cho dãy ban đầu A[1], …, A[n]
Có thể xem như đã có đoạn gồm 1 phần tử A[1] đã được sắp xếp, sau
đó ta thêm A[2] vào đoạn A[1] A[1], A[2] được sắp xếp, tiếp tục thêm
A[3] vào đoạn A[1], A[2], A[1], A[2], A[3] được sắp Tiếp tục cho đến khi thêm A[n] vào đoạn A[1], A[2],…, A[n-1] dãy ban đầu được sắp xếp
Trang 402 Chèn trực tiếp (Insertion sort)
a Tư tưởng giải thuật
Các bước tiến hành như sau:
Bước 1 : i:=2; // giả sử đoạn A[1] đã được sắp xếp
Bước 2 :
X=A[i]; // lưu trữ tạm thời giá trị A[i]
Tìm vị trí j thích hợp trong đoạn từ A[j] đến A[i-1] để chèn A[i] vào
Trang 41x := A[i]; {X lưu giá trị A[i] để tránh bị ghi đè khi
rời chỗ các phần tử } j:= i - 1;
while (j>=1) and (A[j]>x) do { Tìm vị trí cần chèn X }
Trang 42C Minh hoạ giải thuật – chèn trực tiếp
Sắp xếp dãy sau tăng dần
Trang 77d Đánh giá giải thuật
2 Chèn trực tiếp (Insertion sort)
Độ phức tạp thuật toán T(n)=O(n 2 )
Xấu nhất
Tốt nhất
Số phép gán
Số phép so sánh Trường hợp
Trang 793 Phương pháp nổi bọt
(Bubble sort)
Trang 80a Tư tưởng giải thuật
3 Phương pháp nổi bọt (Bubble sort)
• Xuất phát từ cuối dãy, đổi chỗ các cặp phần tử kề cận để đưa phần tử nhỏ hơn trong cặp phần tử đó về vị trí đúng đầu dãy hiện hành, sau đó không xét đến nó ở bước tiếp theo
• Do vậy ở lần xử lý thứ i sẽ có vị trí đầu dãy là i (phần tử ở vị trí i
ở đúng vị trí)
• Lặp lại quá trình trên cho đến khi không còn phần tử nào để xét
Trang 813 Phương pháp nổi bọt (Bubble sort)
a Tư tưởng giải thuật
Các bước tiến hành như sau:
Bước 1 : i:=1; // Lần xử lý đầu tiên
Bước 2 : j=N ; // duyệt từ cuối dãy ngược về vị trí i
Trong khi j<i thực hiện
Nếu A[j]<A[j-1] thì Đổi chỗ (A[j], A[j-1]):
j:=j-1;
Bước 3 : i :=i+1; // lần xử lý tiếp theo
Nếu i>N-1: Hết dãy Dừng
Ngược lại: Lặp lại bước 2.
Trang 82Procedure BubbleSort (A,n) ;
Begin
3 if A[j] < A[j-1] then
Trang 839
4 1 8
6
5 3
3 Phương pháp nổi bọt (Bubble sort)
Trang 849
4 1 8
6
5 3
Minh họa Bubble sort
i
j
i=1, j=7
Trang 859
4 1 8 6
5 3
Minh họa Bubble sort
i
j
•Đổi chỗ 3 cho 5 i=1, j=7
Trang 869
4 1 8 6
5 3
Minh họa Bubble sort
i
j
i=1, j=6
•Đổi chỗ 3 cho 6
Trang 879
4 1 8
6 5 3
Minh họa Bubble sort
i
j
i=1, j=6
Trang 889
4 1 8
6 5 3
Minh họa Bubble sort
i
j
i=1, j=5
• Đổi chỗ 3 cho 8
Trang 899
4 1
8 6 5 3
Minh họa Bubble sort
i
j
i=1, j=5
Trang 909
4 1
8 6 5 3
Minh họa Bubble sort
i
j
i=1, j=4
Trang 919
4 1
8 6 5 3
Minh họa Bubble sort
i
j
i=1, j=3
• Đổi chỗ 1 cho 4
Trang 929
4 1
8 6 5 3
Minh họa Bubble sort
i
j
Trang 939
4 1
8 6 5 3
Minh họa Bubble sort
i
j
i=1, j=2
• Đổi chỗ 1 cho 9
Trang 949 4 1
8 6 5 3
Minh họa Bubble sort
i j
Trang 959 4 1
8 6 5 3
Minh họa Bubble sort
i
j
•Phần tử nhỏ nhất được về đầy dãy
1 đã vào đúng vị trí
Trang 969 4 1
8 6 5 3
Minh họa Bubble sort
i
j
i=2, j=7
• Đổi chỗ 6 cho 5
Trang 979 4 1
8
6 5 3
Minh họa Bubble sort
i
j
i=2, j=7
Trang 989 4 1
8
6 5 3
Minh họa Bubble sort
i
j
i=2, j=6
• Đổi chỗ 5 cho 8
Trang 999 4 1
8 6
5 3
Minh họa Bubble sort
i
j
i=2, j=6
Trang 1009 4 1
8 6
5 3
Minh họa Bubble sort
i
j
i=2, j=5
Trang 1019 4 1
8 6
5 3
Minh họa Bubble sort
i
j
i=2, j=4
• Đổi chỗ 3 cho 4
Trang 1029
4 1
8 6
5 3
Minh họa Bubble sort
i j
i=2, j=3
Trang 1039
4 1
8 6
5 3
Minh họa Bubble sort
i j
i=2, j=3
• Đổi chỗ 3 cho 9
Trang 1049 4 1
8 6 5
3
Minh họa Bubble sort
i j
i=2, j=3
Trang 1059 4 1
8 6 5
Trang 1069 4 1
8 6 5
Trang 1079 4 1
8 6 5
Trang 1089 4 1
8 6 5
Trang 1099 4 1
8 6 5
Trang 1109 4 1
8 6 5
Trang 1119 4 1
8 6 5
3
Minh họa Bubble sort
i j
i=3, j=4
Trang 1129 4 1
8 6 5
Trang 1139 4 1
8 6 5
3
Minh họa Bubble sort
i
j
Trang 1149 4 1
8 6 5
3
Minh họa Bubble sort
i
j
Trang 1159 4 1
8 6 5
Trang 1169
4 1
8 6
5
3
Minh họa Bubble sort
i j
Trang 1179
4 1
8 6
Trang 1189
4 1
8 6
Trang 1199
4 1
8 6
5
3
Minh họa Bubble sort
i j
• Đổi chỗ 9 cho 6
Trang 1209
4 1
8
6 5
3
Minh họa Bubble sort
i j
Trang 1219
4 1
8
6 5
3
Minh họa Bubble sort
i j
6 đã vào đúng vị trí
Trang 1229
4 1
8
6 5
3
Minh họa Bubble sort
i j
• Đổi chỗ 9 cho 8
Trang 1239
4 1
8
6 5
3
Minh họa Bubble sort
i j
Trang 1249
4 1
8
6 5
3
Minh họa Bubble sort
• Sắp xếp thành công !
Trang 1253 Phương pháp nổi bọt (Bubble sort)
d Đánh giá thuật toán
Số lượng phép so sánh không phụ thuộc vào tình trạng ban
đầu của dãy
Số lượng phép hoán vị phụ thuộc vào kết quả so sánh
1 1
Trang 1263 Phương pháp nổi bọt (Bubble sort)
d Đánh giá thuật toán
• Nhược điểm : Không nhận diện được tình trạng dãy đã có
thứ tự Các phần tử nhỏ đưa về vị trí đúng rất nhanh, trong
khi các phần tử lớn lại được đưa về vị trí đúng rất chậm
• Cải tiến : Gải thuật ShakerSort (Sách giáo trình)
• Trong mỗi lần sắp xếp, duyệt mảng theo 2 lượt từ 2 phía
khác nhau:
• Lượt đi: Đẩy phần tử nhỏ về đầu mảng
• Lượt về: Đẩy phần tử lớn về cuối mảng
• Ghi nhận những đoạn đã sắp xếp nhằm tiết kiệm các phép so sánh thừa
Trang 1274 Phương pháp đổi chỗ trực tiếp
(Exchange sort)
Trang 1284 Phương pháp đổi chỗ trực tiếp (Exchange sort)
a Tư tưởng giải thuật
• Tại bước thứ i, xét phần tử thứ a[i].
•Với mỗi phần tử a[i], xét các phần tử a[j] nằm sau nó
(j=i+1…n) Nếu a[i]>a[j] thì đổi chỗ a[i] cho a[j]
•Lặp lại quá trình trên cho đến khi dãy được sắp xếp
Trang 1294 Phương pháp đổi chỗ trực tiếp (Exchange sort)
a Tư tưởng giải thuật
Các bước tiến hành như sau:
Bước 1 : i:=1; // bắt đầu từ phần tử đầu tiên của dãy
Bước 2 : j:=i+1 // Tìm phần tử a[j]<a[i]
Bước 3 : Trong khi j<=n thực hiện
Nếu a[j]<a[i]: Đổi chỗ (a[i], a[j]) j:=j+1
Bước 4 : i:=i+1;
Nếu i<=n : Lặp lại bước 2
Ngược lại: Dừng
Trang 132Đổi chỗ trực tiếp
i=1 j=2
Trang 133Đổi chỗ trực tiếp
Trang 134Đổi chỗ trực tiếp
Trang 135Đổi chỗ trực tiếp
Trang 136Đổi chỗ trực tiếp
Trang 137Đổi chỗ trực tiếp
Trang 138Đổi chỗ trực tiếp
Trang 139Đổi chỗ trực tiếp
Trang 140Đổi chỗ trực tiếp
i=2 j=3
Trang 141Đổi chỗ trực tiếp
Trang 142Đổi chỗ trực tiếp
Trang 143Đổi chỗ trực tiếp
Trang 144Đổi chỗ trực tiếp
Trang 145Đổi chỗ trực tiếp
Trang 146Đổi chỗ trực tiếp
Trang 147Đổi chỗ trực tiếp
Trang 148Đổi chỗ trực tiếp
Trang 149Đổi chỗ trực tiếp
Trang 150Đổi chỗ trực tiếp
Trang 151Đổi chỗ trực tiếp
Trang 152Đổi chỗ trực tiếp
Trang 153Đổi chỗ trực tiếp
Trang 154Đổi chỗ trực tiếp
i=4 j=5
Trang 155Đổi chỗ trực tiếp
Trang 156Đổi chỗ trực tiếp
Trang 157Đổi chỗ trực tiếp
Trang 158Đổi chỗ trực tiếp
Trang 159Đổi chỗ trực tiếp
Trang 160Đổi chỗ trực tiếp
i=5 j=6
Trang 161Đổi chỗ trực tiếp
Trang 162Đổi chỗ trực tiếp
Trang 163Đổi chỗ trực tiếp
Trang 164Đổi chỗ trực tiếp
Trang 165Đổi chỗ trực tiếp
Trang 166Đổi chỗ trực tiếp
Trang 167Đổi chỗ trực tiếp
i=7 j=8
Trang 168168Đổi chỗ trực tiếp
Trang 169Đổi chỗ trực tiếp
• Sắp xếp xong !
Trang 1701 1
Độ phức tạp thuật toán T(n)=O(n 2 )
4 Phương pháp đổi chỗ trực tiếp (Exchange sort)
Trang 1715 Sắp xếp dựa trên phân hoạch
(Quick sort)
Trang 1725 Sắp xếp dựa trên phân hoạch (Quick sort)
Trang 1735 Sắp xếp dựa trên phân hoạch (Quick sort)
• Cách thức phân hoạch là: Lấy một phần tử bất kỳ
làm khoá sau đó xét từ trái qua phải để tìm phần tử
lớn hơn nó, sau đó lại xét từ phải qua trái để tìm
phần tử nhỏ hơn nó rồi hoán vị 2 phần tử này: Quá
trình cứ thế tiếp tục cho đến khi phân hoạch xong
Thường chọn phần tử giữa dãy, đầu dãy hoặc cuối
dãy để làm mốc so sánh
Trang 1745 Sắp xếp dựa trên phân hoạch (Quick sort)
l≤k≤r;
X =a[k]; i:=l; j:=r;
Bước 2a: Trong khi a[i]< x , i=i+1;
Bước 2b: Trong khi a[j]>x, j:=j-1;
Bước 2c: Nếu i<j thì // a[j] ≤x≤a[i] mà a[j] đứng sau a[i]
Hoán vị(a[i], a[j])
+ Nếu i >=j: Dừng
• Giải thuật phân hoạch dãy a[1], …a[r] thành 3 dãy con
b Giải thuật:
Trang 1755 Sắp xếp dựa trên phân hoạch (Quick sort)
• Giải thuật Quicksort để sắp xếp dãy a[l], a[i+1], …, a[r] biểu
một cách đệ quy như sau:
Phân hoạch dãy a[1]….a[r] thành các dãy con
Dãy con 1: a[1]…a[j ]: Nhỏ hơn x;
Dãy con 2: a[j+1], …a[i-1] : Bằng x Dãy con 3: a[i], …, a[r] : Lớn hơn x
- Nếu l<j // dãy con 1 có nhiều hơn 1 phần tử
Phân hoạch dãy a[1], …, a[j]
- Nếu i<r // dãy con 3 có nhiều hơn 1 phần tử
Phân hoạch dãy a[i], …, a[r]
Trang 176Procedure QuickSort(A, l, r);
Begin
x=a[(l+r) div 2]; i:=l; j:=r;
While a[i]<x do i:=i+1;
While a[j]>x then j:=j-1;
If i<=j then Begin
Hoanvi (a[i], a[j]);
Giải thuật QuickSort được cài đặt đệ quy như sau:
5 Sắp xếp dựa trên phân hoạch (Quick sort)
Trang 189•Tiếp tục sắp xếp dãy bên trái
• x=a[(1+3) div 2]=a[2]
Trang 198Quick Sort
Trang 200Quick Sort
Trang 201Quick Sort
Trang 2025 Sắp xếp dựa trên phân hoạch (Quick sort)
d Đánh giá giải thuật
• Hiệu quả của giải thuật phụ thuộc vào việc chọn giá trị mốc (khoá)
• Trường hợp tốt nhất : Chọn được phần tử trung vị (phần tử lớn hơn hay bằng nửa số phần tử, và nhỏ hơn hay bằng nửa số phần
tử còn lại) làm mốc, khi đó dãy được phân chia thành 2 phần bằng nhau và cần log 2 (n) lần phân hoạch thì sắp xếp xong Ví dụ:
• Trường hợp xấu nhất : Chọn phần tử có giá trị nhỏ nhất hay lớn nhất làm mốc, khi đó dãy được phân chia thành 2 phần không
đều : một phần chỉ có 1 phần tử, phần kia có n-1 phần tử, do vậy
cần phân hoạch n lần mới sắp xếp xong Ví dụ:
Trang 203• Ngườ i ta chứng minh được rằng
Độ phức tạp thuật toán là T(n)=O(n.log2n)
5 Sắp xếp dựa trên phân hoạch (Quick sort)
d Đánh giá giải thuật
Trang 2045 Sắp xếp dựa trên phân hoạch (Quick sort)
e Bài tập: Sắp xếp dãy tăng dần
• Bằng cách:
1 Chọn phần tử giữa làm khoá
2 Chọn phần tử đầu dãy làm khoá
3 Chọn phần tử cuối dãy làm khoá
•Tìm số phép lần phân hoạch ở mỗi phương pháp