Giải Thuật Bubble Sort Giải thuật Bucket Sort hay Bin Sort Giải Thuật Heap Sort Giải thuật Insert Sort Giải Thuật Interchange Sort Giải Thuật Merge Sort Giải Thuật Quick Sort Giải Thuật Radix Sort Giải Thuật Selection Sort Giải Thuật Shell Sort Ý tưởng thuật toán • Ta chọn phần tử nhỏ nhất trong N phần tử ban đầu, đưa phần tử này về đầu dãy hiện hành. • Sau đó, ta không quan tâm đến nó nữa, ta xem dãy hiện hành chỉ còn N1 phần tử của dãy ban đầu tính từ vị trí thứ 2. • Cứ vậy, cho đến khi dãy hiện hành chỉ còn 1 phần tử, ta được 1 dãy sắp tăng. Mã CODE void SelectionSort(int arr,int spt) { int i,j,min; for(i = 0;i < spt 1; i++) { min = i; for ( int j = i+1; j < spt; j++) { if (arrj < arrmin) { swap( arrmin, arrj ); } } } } Ví dụ minh họa Độ phức tạp o Để chọn được phần tử nhỏ nhất, ta cần duyệt qua n phần tử (tốn n1 phép so sánh) và sau đó hoán vị nó với phần tử đầu tiên của dãy hiện hành. Để tìm phần tử nhỏ nhất tiếp theo, ta cần duyệt qua n1 phần tử (tốn n2 phép so sánh). Cứ như vậy, ta thấy ngay thuật toán sẽ tốn (n1) + (n2) + … + 1 = n(n1)2 = O(n2) phép so sánh. o Mỗi lần duyệt, ta luôn phải hoán vị 1 lần (1 hoán vị tương đương với 3 phép gán), nghĩa là thuật toán sẽ tốn 3(n1) + 3(n2) + … + 3 = 3n(n1)2 = O(n2) phép gán. Tổng kết lại, ta luôn có độ phức tạp của thuật toán Selection Sort là O(n2) trong mọi trường hợp. Sưu Tầm Giải Thuật Merge Sort Ý tưởng thuật toán + Cho dãy ban đầu a1, a2, …, an. Ta luôn có thể coi nó là tập hợp liên tiếp của các dãy có thứ tự. Ta gọi các dãy có thứ tự này là các dãy con. + Trong phương pháp Merge Sort, vấn đề là ta tìm cách phân hoạch dãy ban đầu thành các dãy con. Sau khi phân hoạch xong, dãy ban đầu sẽ được tách thành hai dãy phụ theo nguyên tắc phân phối luân phiên dãy con. Sau đó, ta trộn từng cặp dãy con của hai dãy phụ thành một dãy con của dãy ban đầu. Ta nhận thấy số dãy con của dãy ban đầu lúc này giảm đi ít nhất là một nửa. Cứ thế sau một số bước, ta sẽ nhận được dãy ban đầu với số dãy con bằng 1, có nghĩa là ta đã sắp xếp xong. + Trộn trực tiếp: đây là phương pháp trộn đơn giản nhất. Việc phân hoạch dãy ban đầu đơn giản như sau: Với dãy ban đầu có n phân tử, ta cứ phân hoạch thành n dãy con. Vì rằng mỗi dãy con chỉ có 1 phần tử nên nó là dãy có thứ tự. Cứ mỗi lần tách – trộn, chiều dài của dãy con sẽ được nhân đôi. Mã CODE void Merge( int A , int a , int c , int b) { int i = a; int j = c + 1; int k = 0; int n = b a + 1; int Bn; while (( i < c +1 ) ( j < b +1 )) if ( A i < Aj) Bk ++ = Ai ++; else Bk ++ = Aj ++; while ( i < c + 1) Bk ++ = Ai++; while ( j < b +1) Bk ++ = A j ++; i = a; for ( k = 0 ; k < n ; k ++) Ai ++ = B k; } void MergeSort( int A , int a, int b) { if (a < b) { int c = (a + b)2; MergeSort(A,a,c); MergeSort(A,c+1,b); Merge(A,a,c,b); } } Ví dụ minh họa Độ phức tạp T(n)= C1 nếu n=1 2T()+C2n nếu n>1 Vì T()=21T()+C2 Nên T(n)= 2 21T()+C2 + C2n = 4T()+C2n+C2n = 4T()+2C2n = 22T()+2C2n Vì T()=21T()+C2 Nên T(n) = 23T()+3C2n T(n) = 2iT()+iC2n Giả sử n=2k Logarit 2 vế log22k=log2n k=log2n T(n)= nT(1) + log2nC2n Độ phức tạp : O(nlog2n) Sưu Tầm
Trang 1Giải Thuật Selection Sort
Ý tưởng thuật toán
Ta chọn phần tử nhỏ nhất trong N phần tử ban đầu, đưa phần tử này về đầu dãy hiện hành
Sau đó, ta không quan tâm đến nó nữa, ta xem dãy hiện hành chỉ còn N-1 phần tử của dãy ban đầu tính từ vị trí thứ 2
Cứ vậy, cho đến khi dãy hiện hành chỉ còn 1 phần tử, ta được 1 dãy sắp tăng
void SelectionSort(int arr[],int spt)
{
int i,j,min;
for(i = 0;i < spt -1; i++)
{
min = i;
for ( int j = i+1; j < spt; j++)
{
if (arr[j] < arr[min])
{
swap( arr[min], arr[j] );
}
}
}
Trang 2 Ví dụ minh họa
Độ phức tạp
o Để chọn được phần tử nhỏ nhất, ta cần duyệt qua n phần tử (tốn n-1 phép so sánh) và sau đó hoán vị nó với phần tử đầu tiên của dãy hiện hành Để tìm phần tử nhỏ nhất tiếp theo, ta cần duyệt qua n-1 phần tử (tốn n-2 phép so sánh) Cứ như vậy, ta thấy ngay thuật toán sẽ tốn (n-1) + (n-2) + … + 1 = n(n-1)/2 = O(n2) phép so sánh
o Mỗi lần duyệt, ta luôn phải hoán vị 1 lần (1 hoán vị tương đương với 3 phép gán), nghĩa là thuật toán sẽ tốn 3(n-1) + 3(n-2) +
… + 3 = 3n(n-1)/2 = O(n2) phép gán
Tổng kết lại, ta luôn có độ phức tạp của thuật toán Selection Sort là O(n 2 ) trong mọi trường hợp.
Sưu Tầm
Giải Thuật Merge Sort
Ý tưởng thuật toán
+ Cho dãy ban đầu a1, a2, …, an Ta luôn có thể coi nó là tập hợp liên tiếp của các dãy có thứ tự Ta gọi các dãy có thứ tự này là các dãy con.
+ Trong phương pháp Merge Sort, vấn đề là ta tìm cách phân hoạch dãy ban đầu thành các dãy con Sau khi phân hoạch xong, dãy ban đầu sẽ được tách thành hai dãy phụ theo nguyên tắc phân phối luân phiên dãy con Sau đó, ta trộn từng cặp dãy con của hai dãy phụ thành một dãy con của dãy ban đầu Ta nhận thấy số dãy con của dãy ban đầu lúc này giảm đi ít nhất là một nửa Cứ thế sau một số bước, ta sẽ nhận được dãy ban đầu với số dãy con bằng 1, có nghĩa
là ta đã sắp xếp xong.
+ Trộn trực tiếp: đây là phương pháp trộn đơn giản nhất Việc phân hoạch dãy ban đầu đơn giản như sau: Với dãy ban đầu có n phân tử,
ta cứ phân hoạch thành n dãy con Vì rằng mỗi dãy con chỉ có 1
Trang 3phần tử nên nó là dãy có thứ tự Cứ mỗi lần tách – trộn, chiều dài của dãy con sẽ được nhân đôi.
Mã CODE
void Merge( int A[] , int a , int c , int b)
{
int i = a;
int j = c + 1;
int k = 0;
int n = b - a + 1;
int B[n];
while (( i < c +1 ) && ( j < b +1 ))
if ( A [i] < A[j])
B[k ++] = A[i ++];
else
B[k ++] = A[j ++];
while ( i < c + 1)
B[k ++] = A[i++];
while ( j < b +1)
B[k ++] = A[ j ++];
i = a;
for ( k = 0 ; k < n ; k ++)
A[i ++] = B [k];
}
Trang 4void MergeSort( int A[ ], int a, int b) {
if (a < b)
{
int c = (a + b)/2;
MergeSort(A,a,c);
MergeSort(A,c+1,b);
Merge(A,a,c,b);
}
}
Ví dụ minh họa
Độ phức tạp
T(n)= C1 nếu n=1 2T()+C2n nếu n>1
Vì T()=21T()+C2*
Nên T(n)= 2[ 21T()+C2*] + C2n = 4T()+C2n+C2n
= 4T()+2C2n
Trang 5= 22T()+2C2n
Vì T()=21T()+C2*
Nên T(n) = 23T()+3C2n
T(n) = 2iT()+iC2n
Giả sử n=2k
Logarit 2 vế log22k=log2n
k=log2n
T(n)= nT(1) + log2n*C2n
Độ phức tạp : O(nlog 2 n)
Sưu Tầm
Giải Thuật Heap Sort
Ý tưởng thuật toán
Để tìm phần tử nhỏ nhất ở bước i, phương pháp sắp xếp chọn trực tiếp
đã không tận dụng được các thông tin đã có được do các phép so sánh
ở bước i-1 Phương pháp Heap Sort khắc phục được nhược điểm này
o Định nghĩa heap:
Giả sử xét trường hợp sắp xếp tăng dần, khi đó Heap được định nghĩa là một dãy các phần tử al, ,ar thoã các quan hệ sau với mọi i [l,r]
ai a2i
ai a2i+1 (ai,a2i), (ai,a2i+1) là các cặp phần tử liên đới
o Tính chất của heap:
Tính chất 1: Nếu al,.,ar là một Heap thì khi cắt bỏ một số phần tử ở hai đầu của Heap thì dãy con còn lại vẫn là một Heap
Tính chất 2: Nếu các phần tử a1, ,an là một Heap thì
Trang 6phần tử a1 (đầu heap) luôn là phần tử lớn nhất trong Heap.
Tính chất 3: Mọi dãy al,al+1,…,ar với 2l > r là một Heap
o Giải thuật
Giải thuật heap sort gồm hai giai đoạn sau:
Giai đoạn 1: Hiệu chỉnh dãy số ban đầu thành Heap
Giai đoạn 2: Sắp xếp dãy số dựa trên Heap
o Bước 1:Đưa phần tử lớn nhất về vị trí đứng ở cuối dãy
r = n;
Hoán vị (a1,ar)
o Bước 2: Loại bỏ phần tử lớn nhất ra khỏi Heap r=r-1;
Hiệu chỉnh phần còn lại của dãy từ al đến ar thành một Heap
o Bước 3:Nếu r >1 ( heap còn phần tử) : lặp lại bước 2
Ngược lại: dừng
o Dựa vào tính chất 3, ta có thể thực hiện giai đoạn 1 bằng cách bắt đầu từ heap mặc nhiên an/2+1, an/2+2,…,an, lần lượt thêm vào các phần tử an/2, an/2-1,…,a1 ta sẽ nhận được Heap theo mong muốn Như vậy giải đoạn 1 tương đương với n/2 lần thực hiện bước 2 của giai đoạn 2
o Cài đặt
o Để cài đặt Heap sort cần xây dựng một số thủ tục phụ trợ:
1.Thủ tục hiệu chỉnh một dãy a l ,a r thành heap
o Giả sử có al,al+1,…ar, trong đó đoạn al+1,…ar, đã là một heap ta cần xây dựng al,al+1,…,ar thành một heap để làm điều này ta lần lượt xét quan hệ của một phần tử ai nào đó với các phần tử liên đới của nó trong dãy là a2i và a2i+1, nếu nó vi phạm quan hệ của heap thì đổi chổ ai với phần tử liên đới thich hợp của nó – việc đổi này
có thể gây phản ứng dây chuyền
2.Hiệu chỉnh a o , ,a n-1 thành heap.
Cho một dãy bất kỳ al,…,ar , theo tính chất 3 ta có dãy
bên trái của heap hiện hành và hiệu chỉnh lại dãy
an/2,an/2+1, ,ar thành heap
void Tao_heap(int a[], int Left,int Right, int &gan, int &ss)
{
int khonglantruyen =0 , max;
gan ++;
do
{
ss++ ;
if( (2*Left) == Right) // co 1 lien doi
{
max = 2*Left;
gan++ ;
}
ss++;
Trang 7if((2*Left) < Right) // co 2 Leftien doi
{
ss++;
if(a[2*Left - 1] > a[2*Left]) // tim max 2 lien doi
{
max = 2*Left; gan ++;
}
else
{
max = 2*Left+1; gan++;
}
}
ss++;
if(a[max -1] > a[Left -1]) // dua phan tu max ve dau
{
hoanvi(&a[Left -1],&a[max -1]); gan+=3;
Left = max; gan++;
khonglantruyen =0; gan++;
}
else
{
khonglantruyen = 1;
gan ++;
}
ss++;gan++;
}
while ( (2*Left <= Right) && (khonglantruyen == 0) );
}
void Heap_sort(int a[],int n, int &gan, int &ss)
{
int Right, Left;
for(Right=n , gan++, ss++ ; Right>1 ; Right , gan++) // ss++ la lan dau tien ss dieu kien, lan sau khong con gia tri nua
{
for(Left = Right/2, gan++ , ss++ ; Left>=1 ; Left , gan++) // Tim phan tu lon nhat ve dau {
Tao_heap(a,Left,Right,gan,ss);
ss++; // So sanh dieu kien vong lap 2
}
hoanvi(&a[0],&a[Right-1]); gan+=3;
ss++; // So sanh dieu kien vong lap 1
}
}
Ví dụ minh họa
Cho 1 dãy gồm các số nguyên : 5 6 1 9 8 6
a[0] a[1] a[2] a[3] a[4] a[5]
Trang 81
2
3
4
5
6
7
8
9
10
11
12
13
14
Trang 916
17
Độ phức tạp
Trường hợp tốt nhất : dãy đã được sắp xếp sẵn=> độ phức tạp là O(1)
Trường hợp xấu nhất : O(nlog2n)
Sưu Tầm
Giải Thuật Tìm Kiếm Nhị Phân
Ý tưởng thuật toán
Tiến hành so sánh phần tử cần tìm cho trước với phần tử nằm ở vị trí giữa của dãy tìm kiếm , dựa vào kết quả so sánh này để quyết định giới hạn dãy tìm kiếm ở bước tiếp theo là nửa trên hay nửa dưới của phần tử giữa được so sánh cho đến khi đoạn so sánh bằng 0
Mã CODE
int timnhiphan(int a[], int n, int x)
{
int left=0 ; right=n-1 ;
int mid ;
Trang 10do {
mid=(left+right)/2 ;
if(x==a[mid]) return mid ;
else if(x<a[mid]) right =mid-1 ;
else left=mid+1 ;
} while(left<=right) ;
return -1 ;
}
Ví dụ minh họa
Cho dãy số a : 12 8 2 14 3 5
Tìm x=3
left =0, right=5, mid=3
x=3
left =4, right=5, mid=4
x=3
Tìm thấy x=3
Trang 11 Độ phức tạp
Trường hợp tốt nhất a[mid]= x
T(n)=T(1) O(1)
Trường hợp xấu nhất O(log2n)
Sưu Tầm
Giải Thuật Tìm Kiếm Tuyến Tính(tuần tự)
Ý tưởng thuật toán
Tìm kiếm tuyến tính là một kỹ thuật đơn giản.Thuật toán tiến hành so sánh phần
tử đã cho trước với các phần tử thứ nhất ,thứ hai … của mảng cho đến khi tìm
thấy phần tử hoặc đã tìm hết mảng mà không thấy phần tử
Mã CODE
int TimTuyenTinh(int a[],int n,int x)
{
int i=0 ;
a[n]=x ;
while(a[i] !=x) i++ ;
if(i==n) return -1 ;
else
return i ;
}
Ví dụ minh họa
Trang 12Cho dãy số a : 12 8 2 14 3 5
Tìm x=3
i=0
x=3
i=1
x=3
i=2
x=3
i=3
x=3
Trang 13i=4
x=3
Tìm thấy x=3
Độ phức tạp
Trường hợp tốt nhất a1= x T(n)=T(1) O(1)
Trường hợp xấu nhất không tìm thấy phần tử x
T(n)=T(n) O(n)
Sưu Tầm
Link tham khảo: https://sites.google.com/site/nguoisaigonblog/giai-thuat-sap-xep-tinh-te