30/09/2018, 19:22

Giải thích giúp em về thuật toán sắp xếp nhanh (quicksort)?

Mấy anh ơi!
Có ai giải thích giúp em thuật toán quicksort (cụ thể là chỗ hàm void partition) này được không ạ?
Mặc dù em biết cơ chế hoạt động của thuật toán, nhưng sao code lại khác hoàn toàn với cách em nghĩ?
Em lấy lòng biết ơn khi các anh đã vào đây để đọc, nếu ai đó giúp em thì em cảm ơn người đó nhiều lắm!
Đây là video minh họa quicksort:

#include <stdio.h>

void quickSort( int[], int, int);
int partition( int[], int, int);


void main() 
{
	int a[] = { 7, 12, 1, -2, 0, 15, 4, 11, 9};

	int i;
	printf("

Unsorted array is:  ");
	for(i = 0; i < 9; ++i)
		printf(" %d ", a[i]);

	quickSort( a, 0, 8);

	printf("

Sorted array is:  ");
	for(i = 0; i < 9; ++i)
		printf(" %d ", a[i]);

}



void quickSort( int a[], int l, int r)
{
   int j;

   if( l < r ) 
   {
   	// divide and conquer
	    j = partition( a, l, r);
	   quickSort( a, l, j-1);
	   quickSort( a, j+1, r);
   }
	
}



int partition( int a[], int l, int r) {
   int pivot, i, j, t;
   pivot = a[l];
   i = l; j = r+1;
		
   while( 1)
   {
   	do ++i; while( a[i] <= pivot && i <= r );
   	do --j; while( a[j] > pivot );
   	if( i >= j ) break;
   	t = a[i]; a[i] = a[j]; a[j] = t;
   }
   t = a[l]; a[l] = a[j]; a[j] = t;
   return j;
}
viết 21:22 ngày 30/09/2018

Mình hiểu cái thuật toán này như sau. Trong một dãy 9 phần tử a[0…8] mình chọn bất kì 1 con pivot (chốt). Như vậy pivot chia dãy này thành 2 phần. Mình bắt đầu tuyển chọn sao cho tất cả các số bên trái pivot thì nhỏ hơn pivot hay a[l] <= pivot (l của left, bên trái). Tất cả các số bên phải pivot thì lớn hơn pivot hay a[r] > pivot (r của right, bên phải). Như vậy ta được 2 dãy mà: dãy đầu tiên <= pivot < dãy thứ 2. Cứ tiếp tục sắp xếp như vậy với 2 dãy đã chia mình sẽ sắp xếp được cả dãy.

Trong hàm partition ở trên không chọn bất kì số nào mà đơn giản lấy luôn số đầu tiên. Và mình thấy nó làm y hệt như cái clip @@. Nhưng có thể tóm tắt lại là hàm do-while đầu tiền dừng tại a[3] = 8 vì không nhỏ hơn chốt = 3. Hàm do-while thứ 2 dừng lại tại ´a[5] = 2´ vì không lớn hơn chốt =3. Tiếp đó đổi vị trí a[3]a[5] cho nhau qua trung gian là biến t.

Còn trong quickSort thì như nói ở trên đầu tiên chia làm 2 phần phân biệt rồi lại sắp xếp phần bên trái với quickSort(a, l, j-1) và phần bên phải với qickSort(a, j+1, r).

Theo mình hiểu là như thế

Lưu Nguyễn Phát viết 21:36 ngày 30/09/2018

t = a[l]; a[l] = a[j]; a[j] = t;

Tại sao cái này lại xuất hiện hai lần vậy anh?
Một cái trong while và ngoài while

Văn Dương viết 21:29 ngày 30/09/2018

Thực sự thì mình không thấy “quick” ở chỗ nào cả.

Đạt Đỗ viết 21:33 ngày 30/09/2018

Nhanh ở chổ đệ quy mỗi lần chọn pivot nó chia dãy ra làm 2 sắp sắp, rồi 1 nữa tiếp tục chia làm 2, …

Văn Dương viết 21:36 ngày 30/09/2018

Vậy làm sao chọn pivot để chia ra làm 2. Nếu pivot là max hoặc min thì sao ?

Lưu Nguyễn Phát viết 21:26 ngày 30/09/2018

Bên dưới là video về tốc độ sắp xếp của các thuật toán khác nhau. Quicksort giữ ngôi vị đứng đầu
Bạn hãy tham khảo :))

Văn Dương viết 21:24 ngày 30/09/2018

Không biết thế nào chứ chắc phải code thực tế đo thời gian mới tin

Đạt Đỗ viết 21:26 ngày 30/09/2018

pivot muốn chọn sao cung được hết, nhưng phổ biết là từng cặp số từ trái qua, nào lớn thì lấy
ví dụ 3 4 9 8 1 2, thì chọn 4 4 3 2 1 4 5 9 thì chọn 4 5 5 7 2 10 4 thì chọn 7

Nguyễn Văn Dũng viết 21:22 ngày 30/09/2018

Sao cái quick sort lại nhanh nhất được nhỉ. Mình thấy nó cứ cùi cùi thế nào ấy.

viết 21:30 ngày 30/09/2018

Sau khi mình dùng xong 1 cái chốt thì mình lại dùng cái chốt khác. Cái ngoài vòng While là phục vụ cho việc chuyển sang chốt mới là số đầu tiên của dãy bên trái, để mình làm tiếp tục sắp xếp dãy bên trái. Như trong clip là sô 3 nghỉ rồi bây giờ đến lượt số 2 bắt đầu hoạt động.

Trần Xuân Tân viết 21:37 ngày 30/09/2018

thuật toán nhanh nhưng khó hiểu qua

cescnghia viết 21:25 ngày 30/09/2018

Hello bạn, mình coi clip và mình sửa lại method partition theo như cái clip nó làm:

// hàm trả về vị trí của pivot 
int partition(int* a, int l, int r) {
   int pivot = a[r]; //chọn pivot là phần tử cuối cùng của mảng      
   int pos = l - 1;  //pos = vị trí của pivot (giá trị trả về)

   for(int i = l; i < r; i++)
       if (a[i] <= pivot){ // pivot lớn hơn a[i]  
   	    pos = pos+1; //=> tăng vị trí của pivot lên 1
   	    exchange(a, pos, i);
      }
   // đã tìm đc vị trí của pivot rồi thì phải để pivot vào vị trí của nó !!!
   exchange(a, pos+1, r);

   return pos+1;
}

void exchange(int* a, int i, int j){
	int temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}

Nó dễ hiểu hơn rất nhiều và hy vọng giúp đc bạn

Nguyễn Minh Tuấn viết 21:23 ngày 30/09/2018

Bạn nhìn quen quen :)))

Phan Đình Dân viết 21:26 ngày 30/09/2018

chạy visuastudio không báo lỗi chỉ có cánh báo mà chạy ko dduoc. đau đầu quá

rogp10 viết 21:30 ngày 30/09/2018

Chọn random nếu phá được random để DoS thì lạy nó luôn

Bài liên quan
0