SlideShare a Scribd company logo
CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT Chương 8: Sắp thứ tự
Khái niệm Sắp thứ tự: Đầu vào: một danh sách Đầu ra: danh sách có thứ tự tăng (hoặc giảm) trên khóa Phân loại: Sắp thứ tự ngoại (external sort): tập tin Sắp thứ tự nội (internal sort): bộ nhớ Giả thiết:  Sắp thứ tự nội Sắp tăng dần
Insertion sort
Insertion sort - Danh sách liên tục
Giải thuật insertion sort – Danh sách liên tục Algorithm  Insertion_sort Input:  danh sách cần sắp thứ tự Output:  danh sách đã được sắp thứ tự 1.  for  first_unsorted = 1 to size //Tìm vị trí hợp lý để chèn giá trị đang có vào 1.1.  current = list[first_unsorted] 1.2.  position = first_unsorted 1.3.  while  (position>0  and  list[position - 1] > current) //Dời chỗ các phần tử lớn về sau 1.3.1.  list[position] = list[position - 1] 1.3.2.  position = position - 1 //Chép phần tử trước đó vào đúng vị trí của nó 1.4.  list[position - 1] = current End  Insertion_sort
Mã C++ Insertion sort – Danh sách liên tục template  < class  Record> void  Sortable_list<Record>  ::  insertion_sort( ) { int  first_unsorted ;  //  position of first unsorted entry int  position ;  //  searches sorted part of list Record current ;  //  holds the entry temporarily removed from list for  (first_unsorted = 1 ;  first_unsorted < count ;  first_unsorted++) if  (entry[first_unsorted] < entry[first_unsorted − 1]) { position = first_unsorted ; current = entry[first_unsorted] ;  //  Pull unsorted entry out of the list. do  {  //  Shift all entries until the proper position is found. entry[position] = entry[position − 1] ; position−− ;  //  position is empty. }  while  (position > 0 && entry[position − 1] > current) ; entry[position] = current ; } }
Insertion sort – DSLK
Giải thuật Insertion sort - DSLK Algorithm  Insertion_sort Input:  danh sách cần sắp thứ tự và có ít nhất 1 phần tử Output:  danh sách đã được sắp thứ tự 1.  last_sorted = head //Đi dọc danh sách liên kết 2.  while  (last_sorted chưa là phần tử cuối) 2.1.  first_unsorted là phần tử kế của last_sorted //Chèn vào đầu? 2.2.  if  (dữ liệu của first_unsorted < dữ liệu của head) //Chèn vào đầu 2.2.1.  Gỡ first_unsorted ra khỏi danh sách 2.2.2.  Nối first_unsorted vào đầu danh sách 2.2.3.  head = first_unsorted
Giải thuật Insertion sort – DSLK (tt.) 2.3.  else   //Tìm vị trí hợp lý để chèn giá trị đang có vào 2.3.1. tailing = head 2.3.2. current là phần tử kế của tailing 2.3.3.  while  (dữ liệu của first_unsorted > dữ liệu của current) 2.3.3.1.  Di chuyển tailing và current đến phần tử kế 2.3.4.  if  (first_unsorted chính là current) 2.3.4.1.  last_sorted = current  //Đã đúng vị trí rồi 2.3.5.  else   2.3.4.1.  Gỡ first_unsorted ra khỏi danh sách 2.3.4.2.  Nối first_unsorted vào giữa tailing và current 2.4.  Di chuyển last_sorted đến phần tử kế End  Insertion_sort
Mã C++ Insertion sort - DSLK template  < class  Record> void  Sortable_list<Record>  ::  insertion_sort( ) { Node <Record> *first_unsorted ,  *last_sorted ,  *current ,  *trailing ;  if  (head != NULL) { last_sorted = head ; while  (last_sorted->next != NULL) { first_unsorted = last sorted->next ; if  (first_unsorted->entry < head->entry) { last_sorted->next = first_unsorted->next ; first_unsorted->next = head ; head = first_unsorted ;  } else  { trailing = head ; current = trailing->next ; while  (first_unsorted->entry > current->entry) { trailing = current ; current = trailing->next ; }
Mã C++ Insertion sort – DSLK (tt.) if  (first_unsorted == current) last_sorted = first_unsorted ; else  { last_sorted->next = first_unsorted->next ; first_unsorted->next = current ; trailing->next = first_unsorted ; } } } } }
Đánh giá Insertion sort Danh sách có thứ tự ngẫu nhiên: So sánh trung bình là n 2 /4 +  O (n) Dời chỗ trung bình là n 2 /4 +  O (n) Danh sách có thứ tự tăng dần: tốt nhất So sánh n-1 lần Dời chỗ 0 lần Danh sách có thứ tự giảm dần: tệ nhất So sánh n 2 /2 +  O (n) lần Dời chỗ n 2 /2 +  O (n) lần
Selection sort
Selection sort – Danh sách liên tục
Giải thuật Selection sort Algorithm  Selection_sort Input:  danh sách cần sắp thứ tự Output:  danh sách đã được sắp thứ tự 1.  for  position = size − 1  downto  0 //Tìm vị trí phần tử có khóa lớn nhất trong phần chưa sắp thứ tự 1.1.  max = 0  //Giả sử phần tử đó ở tại 0 1.2.  for  current = 1  to  position  //Xét các phần tử còn lại 1.2.1.  if  (list[current] > list[max])  //Nếu có phần tử nào lớn hơn 1.2.1.1.  max = current  //thì giữ lại vị trí đó //Đổi chỗ phần tử này với phần tử đang xét 1.3.  temp = list[max] 1.4.  list[max] = list[position] 1.5.  list[position] = temp End  Selection_sort
Mã C++ Selection sort template  < class  Record> void  Sortable_list<Record>  ::  selection_sort( ) { Record temp ; for  ( int  position = count − 1 ;  position > 0 ;  position−−) { int  max = 0 ; for  ( int  current = 1 ;  current <= position ;  current++) if  (entry[max] < entry[current]) largest = current ; temp = entry[max] ; entry[max] = entry[position] ; entry[position] = temp ; } }
Đánh giá Selection sort Danh sách bất kỳ Số lần so sánh: n(n-1)/2 Số lần dời chỗ: 3n So sánh với insertion sort:
Bubble sort 6 4 7 2 3 4 6 2 3 7 Bước 1 Bước 2 Bước 3 Bước 4 4 2 3 6 7 2 3 4 6 7 sorted sorted sorted sorted
Giải thuật Bubble sort Algorithm  Bubble_sort Input:  danh sách cần sắp thứ tự Output:  danh sách đã được sắp thứ tự 1.  for  step = 1  to  size-1 //Với mỗi cặp phần tử kề bất kỳ, sắp thứ tự chúng. //Sau mỗi bước phần tử cuối của danh sách hiện tại là lớn nhất, //vì vậy được trừ ra cho bước kế tiếp 1.1.  for  current = 1  to  (size - step) //Nếu cặp phần tử kề hiện tại không đúng thứ tự 1.1.1.  if  (list[current] < list[current-1])  //Đổi chỗ chúng 1.1.1.1.  temp = list[current] 1.1.1.2.  list[current] = list[current-1] 1.1.1.3.  list[current-1] = temp End  Bubble_sort
Mã C++ Bubble sort template  < class  Record> void  Sortable_list<Record>  ::  bubble_sort( ) { Record temp ; for  ( int  position = count − 1 ;  position > 0 ;  position−−) for  ( int  current = 1 ;  current < position ;  current++) if  (entry[current] < entry[current-1]) { temp = entry[current] ; entry[current] = entry[current-1] ; entry[current-1] = temp ; } }
Bubble sort là exchange sort Algorithm  Exchange_sort Input:  danh sách cần sắp thứ tự Output:  danh sách đã được sắp thứ tự 1.  exchanged = true 2.  while  exchanged //Giả sử lần lặp này không có sự đổi chỗ thì nó đã có thứ tự 2.1.  exchanged = false 2.2.  for  current = 1  to  size – 1 //Nếu cặp này không có thứ tự thì đổi chỗ và ghi nhận lại 2.2.1.  if  (list[current] < list[current-1])  2.2.1.1.  exchange (current, current-1) 2.2.1.2.  exchanged = true End  Exchange_sort
Đánh giá Bubble sort Số lần so sánh: n(n-1)/2 Số lần dời chỗ: Danh sách có thứ tự tăng dần: tốt nhất là 0 lần Danh sách có thứ tự giảm dần: tệ nhất là 3*n(n-1)/2
Chia để trị Ý tưởng: Chia danh sách ra làm 2 phần Sắp thứ tự riêng cho từng phần Trộn 2 danh sách riêng đó thành danh sách có thứ tự Hai giải thuật: Merge sort:  Chia đều thành 2 danh sách Sắp thứ tự riêng Trộn lại Quick sort: Chia thành 3 phần: nhỏ, giữa (pivot), lớn Sắp thứ tự riêng
Đánh giá sơ giải thuật chia để trị Giả sử 2 danh sách có số phần tử là n’ = n/2 Dùng insertion sort riêng cho từng mảnh Trộn 2 danh sách tốn (n’ + n’) = n lần so sánh Số lần so sánh tổng cộng: 2*((n/2) 2 /2 +  O (n/2)) + n = n 2 /4 +  O (n) So sánh với insertion sort là n 2 /2 +  O (n) Có vẻ nhanh hơn
Merge sort Start 26  33 29  35 26  29  33  35 12  19  22 12  19  22  26  29  33  35 12  19 Finish Trộn Trộn Trộn Trộn Trộn Trộn 26  33  35  29  19  12  22 26 33 26  33 35  29 35 29 26  33  35  29 19  12  22 19 12 19  12 22
Đánh giá Merge sort Độ phức tạp: Có tối đa  lgn  mức Ở mỗi mức, cần trộn n phần tử Hạn chế: Danh sách liên tục: di chuyển các phần tử nhiều Nên dùng trong DSLK
Giải thuật Merge sort - DSLK Algorithm  Merge_sort Input:  danh sách cần sắp thứ tự Output:  danh sách đã được sắp thứ tự 1.  if  (có ít nhất 2 phần tử) //Chia danh sách ra 2 phần bằng nhau: 1.1.  second_half = divide_from (sub_list) //Sắp xếp riêng từng phần 1.2.  Call  Merge_sort với sub_list 1.3.  Call  Merge_sort với second_half //Trộn hai phần này với nhau 1.4.  Call  Merge với sub_list và second_half End  Merge_sort
Mã C++ Merge sort template  < class  Record> void  Sortable_list<Record>  ::  recursive_merge_sort (Node<Record> * &sub_list) { if  (sub_list != NULL && sub_list->next != NULL) { Node<Record> *second_half = divide_from(sub_list) ; recursive_merge_sort(sub_list) ; recursive_merge_sort(second_half) ; sub_list = merge(sub_list ,  second_half) ; } }
Chia đôi DSLK 3 9 4 8 sub_list 3 9 4 8 midpoint position second_half
Giải thuật chia đôi DSLK Algorithm  divide_from Input:  danh sách cần chia đôi Output:  hai danh sách dài gần bằng nhau 1.  if  (có ít nhất 1 phần tử) //Dùng một con trỏ di chuyển nhanh gấp đôi con trỏ còn lại 1.1.  midpoint = sub_list 1.2.  position là phần tử kế của midpoint 1.3.  while  (position is not NULL) 1.3.1.  Di chuyển position đến phần tử kế 2 lần 1.3.2.  Di chuyển midpoint đến phần tử kế 1.4.  Cắt danh sách ra 2 phần tại vị trí này End  divide_from
Mã C++ chia đôi DSLK template  < class  Record> Node<Record> *Sortable_list<Record>  ::  divide_from (Node<Record> *sub_list) { Node<Record> *position ,  *midpoint ,  *second_half ; if  ((midpoint = sub_list) == NULL)  return  NULL ; position = midpoint->next ; while  (position != NULL) { position = position->next;  //Di chuyển một lần if  (position != NULL) {  //Dừng ngay trước điểm giữa midpoint = midpoint->next ; position = position->next ;   //Di chuyển lần thứ hai } } second_half = midpoint->next ;  //Phần sau là sau điểm dừng midpoint->next = NULL ;   //Tách đôi danh sách return  second_half ; }
Trộn 2 DSLK có thứ tự 1 7 5 second 3 9 4 8 first ? Dummy node combined last
Giải thuật trộn hai DSLK có thứ tự Algorithm  Merge Input:  hai DSLK first và second có thứ tự Output:  một DSLK có thứ tự 1.  last_sorted là một node giả 2.  while  (first và second khác NULL)  //Cả hai vẫn còn 2.1.  if  (dữ liệu của first nhỏ hơn dữ liệu của second) 2.1.1.  Nối first vào sau last_sorted  //Gỡ phần tử từ  2.1.2.  last_sorted là first  //DSLK 1 2.1.3.  Chuyển first đến phần tử kế  //gắn vào kết quả 2.2.  else 2.2.1.  Nối second vào sau last_sorted  //Gỡ phần tử từ   2.2.2.  last_sorted là second  //DSLK 2 2.2.3.  Chuyển second đến phần tử kế  //gắn vào kết quả 2.3.  if  (danh sách first còn) 2.3.1.  Nối first vào sau last_sorted 2.4.  else 2.4.1.  Nối second vào sau last_sorted End  Merge
Mã C++ trộn hai DSLK có thứ tự template  < class  Record> Node<Record> *Sortable_list<Record>  :: merge(Node<Record> *first ,  Node<Record> *second) { Node<Record> combined, *last_sorted = &combined; while  (first != NULL && second != NULL) { if  (first->entry <= second->entry) { last_sorted->next = first ; last_sorted = first ;  first = first->next ; }  else  { last_sorted->next = second ; last_sorted = second ;  second = second->next ;  } } if  (first == NULL) last_sorted->next = second ; else last_sorted->next = first ; return  combined . next ; }
Quick sort Sort (26, 33, 35, 29, 19, 12, 22) Sort (19, 12, 22) Sort (33, 35, 29) Combine into (12, 19, 22, 26, 29, 33, 35) Phân thành (19, 12, 22) và (33,35,29) với pivot=26 Phân thành (12) và (22) với pivot=19 Phân thành (29) và (35) với pivot=33 Sort (12) Sort (22) Combine into (12, 19, 22) Sort (29) Sort (35) Combine into (29, 33, 35)
Giải thuật Quick sort Algorithm  quick_sort Input:  danh sách cần sắp xếp Output:  danh sách đã được sắp xếp 1.  if  (có ít nhất 2 phần tử) //Phân hoạch danh sách thành 3 phần: //- Phần nhỏ hơn phần tử giữa //- Phần tử giữa //- Phần lớn hơn phần tử giữa 1.1.  Phân hoạch danh sách ra 3 phần 1.2.  Call  quick_sort cho phần bên trái 1.3.  Call  quick_sort cho phần bên phải //Chỉ cần ghép lại là thành danh sách có thứ tự End  quick_sort
Mã C++ Quick sort trên danh sách liên tục template  < class  Record> void  Sortable_list<Record>  ::  recursive_quick_sort( int  low , int  high) { //Phần được sắp xếp trong danh sách từ vị trí low đến vị trí high int  pivot_position ; if  (low < high) { //pivot_postition là vị trí của phần tử giữa pivot_position = partition(low ,  high) ; recursive_quick_sort(low ,  pivot_position − 1) ; recursive_quick_sort(pivot_position + 1 ,  high) ; //Danh sách kết quả đã có thứ tự trong khoảng từ low đến high } }
Phân hoạch cho quick sort
Phân hoạch cho quick sort (tt.)
Giải thuật phân hoạch Algorithm  partition Input:  danh sách cần phân hoạch từ low đến high Output:  đã phân hoạch làm 3 phần, vị trí pivot được ghi nhận //Chọn phần tử tại vị trí giữa là phần tử pivot và chuyển về đầu 1.  swap list[low], list[(low+high)/2] 2.  pivot = list[low] 3.  last_small = low 4.  for  index = low+1  to  high  //Quét qua tất cả các phần tử còn lại 4.1.  if  list[index] < pivot 4.1.1.  last_small = last_small + 1 4.1.2.  swap list[last_small], list[index]  //Chuyển qua phần nhỏ hơn 5.  swap list[last_small], list[low]  //Trả phần tử pivot về lại chính giữa 6.  Vị trí pivot chính là last_small End  partition
Mã C++ phân hoạch template  < class  Record> int  Sortable_list<Record>  ::  partition( int  low , int  high) { //Giả sử hàm swap (ind1, ind2) sẽ đổi chỗ 2 phần tử tại 2 vị trí đó Record pivot ; swap(low ,  (low + high)/2) ; pivot = entry[low] ; int  last_small = low ; for  ( int  index = low + 1 ;  index <= high ;  index++) if  (entry[index] < pivot) { last_small = last_small + 1 ; swap(last_small ,  index) ; } swap(low ,  last_small) ; return  last_small ; }
Ví dụ quick sort 19 35 33 26 29 12 22 recursive_quick_sort(0,6) pivot_position = partition(0,6) = 3 pivot index 26 recursive_quick_sort(0,2) recursive_quick_sort(4,6) 0 1 2 3 4 5 6 low=0 high=6 mid=(low+high)/2=3 last_small pivot_position
Ví dụ quick sort (tt.) 22 19 12 recursive_quick_sort(0,2) pivot_position = partition(0,2) = 1 index pivot 19 recursive_quick_sort(0,0) recursive_quick_sort(2,2) (Không làm gì cả) 26 29 33 35 0 1 2 3 4 5 6 low=0 high=2 mid=(low+high)/2=1 last_small pivot_position
Ví dụ quick sort (tt.) 29 33 35 recursive_quick_sort(4,6) pivot_position = partition(4,6) = 5 index pivot 33 recursive_quick_sort(4,4) recursive_quick_sort(6,6) (Không làm gì cả) 26 12 19 22 0 1 2 3 4 5 6 low=4 high=6 mid=(low+high)/2=5 last_small pivot_position
Các trường hợp của Quick sort
Đánh giá Quick sort Trường hợp xấu nhất: Một bên rỗng và một bên là n-1 phần tử => n(n-1)/2 Chọn phần tử pivot: Đầu (hay cuối): trường hợp xấu xảy ra khi danh sách đang có thứ tự (hoặc thứ tự ngược) Ở trung tâm, hoặc ngẫu nhiên: trường hợp xấu khó xảy ra Trường hợp trung bình: C( n ) = 2 n  ln  n + O ( n )  ≈  1.39  n  lg  n  +  O ( n )
Heap và Heap sort Heap (định nghĩa lại): Danh sách có n phần tử (từ 0 đến n-1) a k   ≥ a 2k+1  và  a k   ≥ a 2k+2  (a k  lớn nhất trong 3 phần tử) Đặc tính: a 0  là phần tử lớn nhất Danh sách chưa chắc có thứ tự Nửa sau của danh sách bất kỳ thỏa định nghĩa heap Heap sort: Lấy a 0  ra, tái tạo lại heap => Phần tử lớn nhất Lấy a 0  mới ra, tái tạo lại heap => Phần tử lớn kề …
Giải thuật Heap sort Algorithm  heap_sort Input:  danh sách cần sắp xếp có n phần tử Output:  danh sách đã sắp thứ tự //Xây dựng heap ban đầu 1.  Call  build_heap //Lần lượt lấy phần tử đầu ra đem về cuối danh sách hiện tại //rồi xây dựng heap trở lại 2.  for  index = size-1  to  0  //index là vị trí cuối của phần còn lại 2.1.  swap list[0], list[index]   //Đổi phần tử lớn nhất về cuối //Xây dựng lại heap với số phần tử giảm đi 1 2.2.  Call  rebuild_heap  index-1 End  heap_sort
Mã C++ Heap sort template  < class  Record> void  Sortable_list<Record>  ::  heap_sort( ) { Record current ; //Xây dựng heap ban đầu build_heap( ) ; for  ( int  last_unsorted = count − 1 ;  last_unsorted > 0 ;  last_unsorted−−) { //Giữ lại phần tử cuối cũ current = entry[last_unsorted] ; //  Extract last entry from list. //Chép phần tử đầu (lớn nhất) về vị trí này entry[last_unsorted] = entry[0] ; //Xây dựng lại heap bằng cách chèn phần tử current vào đúng vị trí insert_heap(current ,  0 ,  last_unsorted − 1) ; } }
Biểu diễn Heap Dạng cây nhị phân: Node gốc là a 0 2 node con của phần tử a k  là 2 phần tử a 2k+1  và a 2k+2 Ở mức cuối cùng, các node lấp đầy từ bên trái sang bên phải (cây nhị phân gần đầy đủ) 0  1  2  3  4  5  6  7  8
Ví dụ Heap sort y r p d f b k a c current 0 1 2 3 4 5 6 7 8 y r p d f b k a c
Ví dụ Heap sort (tt.) r f p d c b k a y current 0 1 2 3 4 5 6 7 8 r f p d c b k a y
Ví dụ Heap sort (tt.) p f k d c b a r y current 0 1 2 3 4 5 6 7 8 p f k d c b a r y
Ví dụ Heap sort (tt.) k f b d c a p r y current 0 1 2 3 4 5 6 7 8 k f b d c a p r y
Ví dụ Heap sort (tt.) f d b a c k p r y current 0 1 2 3 4 5 6 7 8 f d b a c k p r y
Ví dụ Heap sort (tt.) d c b a f k p r y current 0 1 2 3 4 5 6 7 8 d c b a f k p r y
Ví dụ Heap sort (tt.) c a b d f k p r y current 0 1 2 3 4 5 6 7 8 c a b d f k p r y
Ví dụ Heap sort (tt.) b a c d f k p r y current 0 1 2 3 4 5 6 7 8 b a c d f k p r y
Giải thuật tái tạo lại heap Algorithm  insert_heap Input:  danh sách là heap trong khoảng từ low+1 đến high, current là giá trị cần thêm vào Output:  danh sách là heap trong khoảng từ low đến high 1.  Bắt đầu kiểm tra tại vị trí low 2.  while  (chưa kiểm tra xong đến high) 2.1.  Tìm lớn nhất trong bộ ba phần tử current, list[2k+1], list[2k+2] 2.2.  if   (phần tử đó là current) 2.2.1.  Ngừng vòng lặp 2.3.  else 2.3.1.  Dời phần tử lớn nhất lên vị trí hiện tại 2.3.2.  Kiểm tra bắt đầu từ vị trí của phần tử lớn nhất này 3.  Đưa current vào vị trí đang kiểm tra End  insert_heap
Mã C++ tái tạo lại heap template  < class  Record> void  Sortable_list<Record>  :: nsert_heap( const  Record &current , int  low , int  high) { int  large = 2 * low + 1;  //P.tử lớn giả sử là tại 2k+1 while  (large <= high) { if  (large < high && entry[large] < entry[large + 1]) large++ ;  //P.tử lớn tại 2k+2 if  (current >= entry[large]) break;   //Nếu current là lớn nhất thì thôi else  { entry[low] = entry[large] ;   //Không thì đẩy p.tử lớn nhất lên low = large ;  //rồi tiếp tục kiểm tra về sau large = 2 * low + 1 ; } } entry[low] = current ;   //Đây là vị trí thích hợp cho current }
Giải thuật xây dựng heap ban đầu Algorithm  build_heap Input:  danh sách bất kỳ cần biến thành heap Output:  danh sách đã là heap //Nửa sau của 1 danh sách bất kỳ thỏa tính chất của heap //Ta tìm cách xây dựng heap ngược từ giữa về đầu 1.  for  low = size/2  downto  0 //Từ vị trí low+1 đến cuối danh sách đang là heap 1.1. current = list[low] ; //Xây dựng lại heap trong khoảng [low, size-1] 1.2.  Call  insert_heap với current, low và   size − 1 End  build_heap
Mã C++ xây dựng heap ban đầu template  < class  Record> void  Sortable_list<Record>  ::  build_heap( ) { //Nửa sau của 1 danh sách bất kỳ thỏa tính chất của heap //Ta tìm cách xây dựng heap ngược từ giữa về đầu for  ( int  low = count/2 − 1 ;  low >= 0 ;  low−−) { Record current = entry[low] ; insert_heap(current ,  low ,  count − 1) ; } }
Ví dụ xây dựng heap ban đầu p c y d f b k a r Bước 1 p c y r f b k a d Bước 2 p c y r f b k a d Bước 3 p r y c f b k a d Bước 3’ p r y d f b k a c Bước 4 y r p d f b k a c 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8
Đánh giá Heap sort Trường hợp xấu nhất: C = 2 n  lg  n +   O ( n ) M =  n  lg  n +   O ( n ) So với Quick sort Trung bình: chậm hơn quick sort Xấu nhất:  O ( n  lg  n ) < n(n-1)/2

More Related Content

PPT
Ctdl C07
PPT
Ctdl C06
PPT
Ctdl C11
PPT
Ctdl C09
PDF
Cau truc dl_va_giai_thuat_bai1[1] - copy
PPT
Ctdl C10
DOC
Bài tập CTDL và GT 3
PDF
Bài tập CTDL và GT 1
Ctdl C07
Ctdl C06
Ctdl C11
Ctdl C09
Cau truc dl_va_giai_thuat_bai1[1] - copy
Ctdl C10
Bài tập CTDL và GT 3
Bài tập CTDL và GT 1

What's hot (17)

PPT
Gioi Thieu
PDF
Bài 6: Các cấu trúc dữ liệu đặc biệt: ngăn xếp, hàng đợi, cây - Giáo trình FPT
DOC
Bài tập CTDL và GT 12
PPT
Chuong 2 Tim Kiem N Sap Xep
PDF
Bài 7: Danh sách liên kết (LINKED LIST) và tập hợp (SET) - Giáo trình FPT
PPT
Session 19
PDF
Bài 4: ARRAY VÀ ARRAYLIST - Giáo trình FPT
PPT
Ctdl c4-cay
PDF
Bài tập CTDL và GT 7
PDF
Cấu trúc dữ liệu kiểu danh sách liên kết
PDF
ctdl&amp;gt 04-list_don
PDF
Bai3 timkiemsapxep
PDF
Ctdl c2
PPT
Chuong 2
PPT
Chuong 2 phan tich cac thuat toan sap xep va tim kiem
PPT
Sap xep va tim kiem
PPT
Chg2 danh sach
Gioi Thieu
Bài 6: Các cấu trúc dữ liệu đặc biệt: ngăn xếp, hàng đợi, cây - Giáo trình FPT
Bài tập CTDL và GT 12
Chuong 2 Tim Kiem N Sap Xep
Bài 7: Danh sách liên kết (LINKED LIST) và tập hợp (SET) - Giáo trình FPT
Session 19
Bài 4: ARRAY VÀ ARRAYLIST - Giáo trình FPT
Ctdl c4-cay
Bài tập CTDL và GT 7
Cấu trúc dữ liệu kiểu danh sách liên kết
ctdl&amp;gt 04-list_don
Bai3 timkiemsapxep
Ctdl c2
Chuong 2
Chuong 2 phan tich cac thuat toan sap xep va tim kiem
Sap xep va tim kiem
Chg2 danh sach
Ad

Viewers also liked (20)

PPT
Ctdl C04
PPT
Ctdl C05
PDF
Giáo trình cấu trúc dữ liệu và giải thuật của lê minh hoàng
PPT
Ctdl C01
PDF
Slide báo cáo cuối kì system hacking-Trần Nguyễn Lộc
PPT
Ctdl C02
PDF
System hacking_Athena
PDF
Security Bootcamp 2013 - Giải pháp phát hiện xâm nhập mạng không dây - WIDS -...
PPT
Wireless
PPT
Ctdl C03
PPTX
man in the middle
PDF
Bài 4: Bảo mật máy chủ, ứng dụng, dữ liệu và mạng - Giáo trình FPT
DOCX
tìm hiểu các lỗ hổng bảo mật
PDF
Chương 6 Bảo mật - Giáo trình FPT
PPTX
Man In The Middle - Hacking Illustrated
PDF
Bài 7: Xác thực và quản lý tài khoản - Giáo trình FPT
PDF
Bài 5: Quản trị một mạng an toàn và Bảo mật các mạng không dây - Giáo trình FPT
PDF
Bài 3: Tấn công vào ứng dụng và mạng, đánh giá khả năng thiệt hại và làm giảm...
PDF
Bài 2: Phần mềm độc hại và các dạng tấn công sử dụng kỹ nghệ xã hội - Giáo tr...
Ctdl C04
Ctdl C05
Giáo trình cấu trúc dữ liệu và giải thuật của lê minh hoàng
Ctdl C01
Slide báo cáo cuối kì system hacking-Trần Nguyễn Lộc
Ctdl C02
System hacking_Athena
Security Bootcamp 2013 - Giải pháp phát hiện xâm nhập mạng không dây - WIDS -...
Wireless
Ctdl C03
man in the middle
Bài 4: Bảo mật máy chủ, ứng dụng, dữ liệu và mạng - Giáo trình FPT
tìm hiểu các lỗ hổng bảo mật
Chương 6 Bảo mật - Giáo trình FPT
Man In The Middle - Hacking Illustrated
Bài 7: Xác thực và quản lý tài khoản - Giáo trình FPT
Bài 5: Quản trị một mạng an toàn và Bảo mật các mạng không dây - Giáo trình FPT
Bài 3: Tấn công vào ứng dụng và mạng, đánh giá khả năng thiệt hại và làm giảm...
Bài 2: Phần mềm độc hại và các dạng tấn công sử dụng kỹ nghệ xã hội - Giáo tr...
Ad

Similar to Ctdl C08 (20)

PPT
Chuong 2 Tim Kiem N Sap Xep
PDF
Ctdl lab07-cac thuat-toan_sap_xep
PPT
Timkiem&sapxep
PDF
Bai10 stack queue
PDF
Tablists help
PDF
Thuật toán ứng dụng - Tìm kiếm và sắp xếp
PDF
Bai3 timkiem sapxep
PDF
cau-truc-du-lieu-va-giai-thuat_pham-the-bao_slides---danh-sach.pdf
PPT
C2 sap xep
PDF
Tìm kiếm và sắp nội
PDF
Baigiang ctdl
PPT
Chuong 2 - PYTHON - List.ppt zzzzzzzzzzz
PDF
CTDL_02_SXTK Cấu trúc dữ liệu và giải thuật
PPTX
Giao trinh Stack va Queue trong DSA.pptx
PPT
Chap2 new (tran dai's conflicted copy 2013 04-02)
PPT
Chap2 new
PDF
02 stack queue
PPTX
Danh sách liên kết là 1 cấu trúc dữ liệu được sử dụng để lưu trữ 1 tập hợp cá...
PPTX
Cấu trúc dữ liệu và giải thuật C3__SapXep_new.pptx
PDF
csdl bai-thuchanh_02
Chuong 2 Tim Kiem N Sap Xep
Ctdl lab07-cac thuat-toan_sap_xep
Timkiem&sapxep
Bai10 stack queue
Tablists help
Thuật toán ứng dụng - Tìm kiếm và sắp xếp
Bai3 timkiem sapxep
cau-truc-du-lieu-va-giai-thuat_pham-the-bao_slides---danh-sach.pdf
C2 sap xep
Tìm kiếm và sắp nội
Baigiang ctdl
Chuong 2 - PYTHON - List.ppt zzzzzzzzzzz
CTDL_02_SXTK Cấu trúc dữ liệu và giải thuật
Giao trinh Stack va Queue trong DSA.pptx
Chap2 new (tran dai's conflicted copy 2013 04-02)
Chap2 new
02 stack queue
Danh sách liên kết là 1 cấu trúc dữ liệu được sử dụng để lưu trữ 1 tập hợp cá...
Cấu trúc dữ liệu và giải thuật C3__SapXep_new.pptx
csdl bai-thuchanh_02

Recently uploaded (20)

PPTX
Bài 9.4 TUYẾN SINH DỤC NAM VÀ NU CẤU TẠO VÀ CHỨC NĂNG
PDF
CHUYÊN ĐỀ DẠY THÊM HÓA HỌC LỚP 11 CẢ NĂM THEO FORM THI MỚI BGD - CÓ ÔN TẬP + ...
PPTX
White and Purple Modern Artificial Intelligence Presentation.pptx
DOCX
Cao Thuy Linh-San pham cuoi khoa.- bồi dưỡng thường xuyêndocx
PDF
BÁO CÁO THỰC TẬP KỸ SƯ 2 ĐỀ TÀI TÌM HIỂU QUY TRÌNH CÔNG NGHỆ SẢN XUẤT BÁNH SN...
PDF
BÀI HỌC ÔN TẬP CHO THI NỘI DUNG MÔN HOẠCH ĐỊNH
PPTX
Flashcard giải pháp đơn giản – trực quan – hiệu quả, giúp học từ vựng theo t...
PPTX
Direct Marketing- chieu thi truyen thong
DOCX
6.CQ_KT_Ke toan tai chinh 2_Pham Thi Phuong Thao.docx
PDF
BÀI TẬP TEST FOR UNIT TIẾNG ANH LỚP 8 GLOBAL SUCCESS CẢ NĂM THEO TỪNG ĐƠN VỊ ...
PDF
12894-44864-1-CE-1037-1038_Văn bản của bài báo.pdf
PPTX
CHƯƠNG I excel,,,,,,,,,,,,,,,,,,,,,,,,,,
PDF
CHUYÊN ĐỀ DẠY THÊM HÓA HỌC LỚP 12 CẢ NĂM THEO FORM THI MỚI BGD - CÓ ÔN TẬP + ...
PDF
TeétOrganicChemistryFromVietNamVeryHardd
PDF
GIẢI PHÁP NÂNG CAO CÔNG TÁC CHỦ NHIỆM QUA CÁC TIẾT SINH HOẠT THEO CHỦ ĐỀ NHẰ...
PPTX
Triết học: Vận dụng nguyên tắc phát triển trong nhận thức và hoạt động thực...
PPTX
Chương 5 của Tâm lí học - Tâm Lí Học Giáo Dục Đạo Đức
PPTX
14. thoát vị bẹn nghẹt bệnh học ngoại khoa.pptx
PDF
CHUYÊN ĐỀ DẠY THÊM HÓA HỌC LỚP 10 CẢ NĂM THEO FORM THI MỚI BGD - CÓ ÔN TẬP + ...
PDF
bo-trac-nghiem-toan-11 dành cho cả năm học
Bài 9.4 TUYẾN SINH DỤC NAM VÀ NU CẤU TẠO VÀ CHỨC NĂNG
CHUYÊN ĐỀ DẠY THÊM HÓA HỌC LỚP 11 CẢ NĂM THEO FORM THI MỚI BGD - CÓ ÔN TẬP + ...
White and Purple Modern Artificial Intelligence Presentation.pptx
Cao Thuy Linh-San pham cuoi khoa.- bồi dưỡng thường xuyêndocx
BÁO CÁO THỰC TẬP KỸ SƯ 2 ĐỀ TÀI TÌM HIỂU QUY TRÌNH CÔNG NGHỆ SẢN XUẤT BÁNH SN...
BÀI HỌC ÔN TẬP CHO THI NỘI DUNG MÔN HOẠCH ĐỊNH
Flashcard giải pháp đơn giản – trực quan – hiệu quả, giúp học từ vựng theo t...
Direct Marketing- chieu thi truyen thong
6.CQ_KT_Ke toan tai chinh 2_Pham Thi Phuong Thao.docx
BÀI TẬP TEST FOR UNIT TIẾNG ANH LỚP 8 GLOBAL SUCCESS CẢ NĂM THEO TỪNG ĐƠN VỊ ...
12894-44864-1-CE-1037-1038_Văn bản của bài báo.pdf
CHƯƠNG I excel,,,,,,,,,,,,,,,,,,,,,,,,,,
CHUYÊN ĐỀ DẠY THÊM HÓA HỌC LỚP 12 CẢ NĂM THEO FORM THI MỚI BGD - CÓ ÔN TẬP + ...
TeétOrganicChemistryFromVietNamVeryHardd
GIẢI PHÁP NÂNG CAO CÔNG TÁC CHỦ NHIỆM QUA CÁC TIẾT SINH HOẠT THEO CHỦ ĐỀ NHẰ...
Triết học: Vận dụng nguyên tắc phát triển trong nhận thức và hoạt động thực...
Chương 5 của Tâm lí học - Tâm Lí Học Giáo Dục Đạo Đức
14. thoát vị bẹn nghẹt bệnh học ngoại khoa.pptx
CHUYÊN ĐỀ DẠY THÊM HÓA HỌC LỚP 10 CẢ NĂM THEO FORM THI MỚI BGD - CÓ ÔN TẬP + ...
bo-trac-nghiem-toan-11 dành cho cả năm học

Ctdl C08

  • 1. CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT Chương 8: Sắp thứ tự
  • 2. Khái niệm Sắp thứ tự: Đầu vào: một danh sách Đầu ra: danh sách có thứ tự tăng (hoặc giảm) trên khóa Phân loại: Sắp thứ tự ngoại (external sort): tập tin Sắp thứ tự nội (internal sort): bộ nhớ Giả thiết: Sắp thứ tự nội Sắp tăng dần
  • 4. Insertion sort - Danh sách liên tục
  • 5. Giải thuật insertion sort – Danh sách liên tục Algorithm Insertion_sort Input: danh sách cần sắp thứ tự Output: danh sách đã được sắp thứ tự 1. for first_unsorted = 1 to size //Tìm vị trí hợp lý để chèn giá trị đang có vào 1.1. current = list[first_unsorted] 1.2. position = first_unsorted 1.3. while (position>0 and list[position - 1] > current) //Dời chỗ các phần tử lớn về sau 1.3.1. list[position] = list[position - 1] 1.3.2. position = position - 1 //Chép phần tử trước đó vào đúng vị trí của nó 1.4. list[position - 1] = current End Insertion_sort
  • 6. Mã C++ Insertion sort – Danh sách liên tục template < class Record> void Sortable_list<Record> :: insertion_sort( ) { int first_unsorted ; // position of first unsorted entry int position ; // searches sorted part of list Record current ; // holds the entry temporarily removed from list for (first_unsorted = 1 ; first_unsorted < count ; first_unsorted++) if (entry[first_unsorted] < entry[first_unsorted − 1]) { position = first_unsorted ; current = entry[first_unsorted] ; // Pull unsorted entry out of the list. do { // Shift all entries until the proper position is found. entry[position] = entry[position − 1] ; position−− ; // position is empty. } while (position > 0 && entry[position − 1] > current) ; entry[position] = current ; } }
  • 8. Giải thuật Insertion sort - DSLK Algorithm Insertion_sort Input: danh sách cần sắp thứ tự và có ít nhất 1 phần tử Output: danh sách đã được sắp thứ tự 1. last_sorted = head //Đi dọc danh sách liên kết 2. while (last_sorted chưa là phần tử cuối) 2.1. first_unsorted là phần tử kế của last_sorted //Chèn vào đầu? 2.2. if (dữ liệu của first_unsorted < dữ liệu của head) //Chèn vào đầu 2.2.1. Gỡ first_unsorted ra khỏi danh sách 2.2.2. Nối first_unsorted vào đầu danh sách 2.2.3. head = first_unsorted
  • 9. Giải thuật Insertion sort – DSLK (tt.) 2.3. else //Tìm vị trí hợp lý để chèn giá trị đang có vào 2.3.1. tailing = head 2.3.2. current là phần tử kế của tailing 2.3.3. while (dữ liệu của first_unsorted > dữ liệu của current) 2.3.3.1. Di chuyển tailing và current đến phần tử kế 2.3.4. if (first_unsorted chính là current) 2.3.4.1. last_sorted = current //Đã đúng vị trí rồi 2.3.5. else 2.3.4.1. Gỡ first_unsorted ra khỏi danh sách 2.3.4.2. Nối first_unsorted vào giữa tailing và current 2.4. Di chuyển last_sorted đến phần tử kế End Insertion_sort
  • 10. Mã C++ Insertion sort - DSLK template < class Record> void Sortable_list<Record> :: insertion_sort( ) { Node <Record> *first_unsorted , *last_sorted , *current , *trailing ; if (head != NULL) { last_sorted = head ; while (last_sorted->next != NULL) { first_unsorted = last sorted->next ; if (first_unsorted->entry < head->entry) { last_sorted->next = first_unsorted->next ; first_unsorted->next = head ; head = first_unsorted ; } else { trailing = head ; current = trailing->next ; while (first_unsorted->entry > current->entry) { trailing = current ; current = trailing->next ; }
  • 11. Mã C++ Insertion sort – DSLK (tt.) if (first_unsorted == current) last_sorted = first_unsorted ; else { last_sorted->next = first_unsorted->next ; first_unsorted->next = current ; trailing->next = first_unsorted ; } } } } }
  • 12. Đánh giá Insertion sort Danh sách có thứ tự ngẫu nhiên: So sánh trung bình là n 2 /4 + O (n) Dời chỗ trung bình là n 2 /4 + O (n) Danh sách có thứ tự tăng dần: tốt nhất So sánh n-1 lần Dời chỗ 0 lần Danh sách có thứ tự giảm dần: tệ nhất So sánh n 2 /2 + O (n) lần Dời chỗ n 2 /2 + O (n) lần
  • 14. Selection sort – Danh sách liên tục
  • 15. Giải thuật Selection sort Algorithm Selection_sort Input: danh sách cần sắp thứ tự Output: danh sách đã được sắp thứ tự 1. for position = size − 1 downto 0 //Tìm vị trí phần tử có khóa lớn nhất trong phần chưa sắp thứ tự 1.1. max = 0 //Giả sử phần tử đó ở tại 0 1.2. for current = 1 to position //Xét các phần tử còn lại 1.2.1. if (list[current] > list[max]) //Nếu có phần tử nào lớn hơn 1.2.1.1. max = current //thì giữ lại vị trí đó //Đổi chỗ phần tử này với phần tử đang xét 1.3. temp = list[max] 1.4. list[max] = list[position] 1.5. list[position] = temp End Selection_sort
  • 16. Mã C++ Selection sort template < class Record> void Sortable_list<Record> :: selection_sort( ) { Record temp ; for ( int position = count − 1 ; position > 0 ; position−−) { int max = 0 ; for ( int current = 1 ; current <= position ; current++) if (entry[max] < entry[current]) largest = current ; temp = entry[max] ; entry[max] = entry[position] ; entry[position] = temp ; } }
  • 17. Đánh giá Selection sort Danh sách bất kỳ Số lần so sánh: n(n-1)/2 Số lần dời chỗ: 3n So sánh với insertion sort:
  • 18. Bubble sort 6 4 7 2 3 4 6 2 3 7 Bước 1 Bước 2 Bước 3 Bước 4 4 2 3 6 7 2 3 4 6 7 sorted sorted sorted sorted
  • 19. Giải thuật Bubble sort Algorithm Bubble_sort Input: danh sách cần sắp thứ tự Output: danh sách đã được sắp thứ tự 1. for step = 1 to size-1 //Với mỗi cặp phần tử kề bất kỳ, sắp thứ tự chúng. //Sau mỗi bước phần tử cuối của danh sách hiện tại là lớn nhất, //vì vậy được trừ ra cho bước kế tiếp 1.1. for current = 1 to (size - step) //Nếu cặp phần tử kề hiện tại không đúng thứ tự 1.1.1. if (list[current] < list[current-1]) //Đổi chỗ chúng 1.1.1.1. temp = list[current] 1.1.1.2. list[current] = list[current-1] 1.1.1.3. list[current-1] = temp End Bubble_sort
  • 20. Mã C++ Bubble sort template < class Record> void Sortable_list<Record> :: bubble_sort( ) { Record temp ; for ( int position = count − 1 ; position > 0 ; position−−) for ( int current = 1 ; current < position ; current++) if (entry[current] < entry[current-1]) { temp = entry[current] ; entry[current] = entry[current-1] ; entry[current-1] = temp ; } }
  • 21. Bubble sort là exchange sort Algorithm Exchange_sort Input: danh sách cần sắp thứ tự Output: danh sách đã được sắp thứ tự 1. exchanged = true 2. while exchanged //Giả sử lần lặp này không có sự đổi chỗ thì nó đã có thứ tự 2.1. exchanged = false 2.2. for current = 1 to size – 1 //Nếu cặp này không có thứ tự thì đổi chỗ và ghi nhận lại 2.2.1. if (list[current] < list[current-1]) 2.2.1.1. exchange (current, current-1) 2.2.1.2. exchanged = true End Exchange_sort
  • 22. Đánh giá Bubble sort Số lần so sánh: n(n-1)/2 Số lần dời chỗ: Danh sách có thứ tự tăng dần: tốt nhất là 0 lần Danh sách có thứ tự giảm dần: tệ nhất là 3*n(n-1)/2
  • 23. Chia để trị Ý tưởng: Chia danh sách ra làm 2 phần Sắp thứ tự riêng cho từng phần Trộn 2 danh sách riêng đó thành danh sách có thứ tự Hai giải thuật: Merge sort: Chia đều thành 2 danh sách Sắp thứ tự riêng Trộn lại Quick sort: Chia thành 3 phần: nhỏ, giữa (pivot), lớn Sắp thứ tự riêng
  • 24. Đánh giá sơ giải thuật chia để trị Giả sử 2 danh sách có số phần tử là n’ = n/2 Dùng insertion sort riêng cho từng mảnh Trộn 2 danh sách tốn (n’ + n’) = n lần so sánh Số lần so sánh tổng cộng: 2*((n/2) 2 /2 + O (n/2)) + n = n 2 /4 + O (n) So sánh với insertion sort là n 2 /2 + O (n) Có vẻ nhanh hơn
  • 25. Merge sort Start 26 33 29 35 26 29 33 35 12 19 22 12 19 22 26 29 33 35 12 19 Finish Trộn Trộn Trộn Trộn Trộn Trộn 26 33 35 29 19 12 22 26 33 26 33 35 29 35 29 26 33 35 29 19 12 22 19 12 19 12 22
  • 26. Đánh giá Merge sort Độ phức tạp: Có tối đa lgn mức Ở mỗi mức, cần trộn n phần tử Hạn chế: Danh sách liên tục: di chuyển các phần tử nhiều Nên dùng trong DSLK
  • 27. Giải thuật Merge sort - DSLK Algorithm Merge_sort Input: danh sách cần sắp thứ tự Output: danh sách đã được sắp thứ tự 1. if (có ít nhất 2 phần tử) //Chia danh sách ra 2 phần bằng nhau: 1.1. second_half = divide_from (sub_list) //Sắp xếp riêng từng phần 1.2. Call Merge_sort với sub_list 1.3. Call Merge_sort với second_half //Trộn hai phần này với nhau 1.4. Call Merge với sub_list và second_half End Merge_sort
  • 28. Mã C++ Merge sort template < class Record> void Sortable_list<Record> :: recursive_merge_sort (Node<Record> * &sub_list) { if (sub_list != NULL && sub_list->next != NULL) { Node<Record> *second_half = divide_from(sub_list) ; recursive_merge_sort(sub_list) ; recursive_merge_sort(second_half) ; sub_list = merge(sub_list , second_half) ; } }
  • 29. Chia đôi DSLK 3 9 4 8 sub_list 3 9 4 8 midpoint position second_half
  • 30. Giải thuật chia đôi DSLK Algorithm divide_from Input: danh sách cần chia đôi Output: hai danh sách dài gần bằng nhau 1. if (có ít nhất 1 phần tử) //Dùng một con trỏ di chuyển nhanh gấp đôi con trỏ còn lại 1.1. midpoint = sub_list 1.2. position là phần tử kế của midpoint 1.3. while (position is not NULL) 1.3.1. Di chuyển position đến phần tử kế 2 lần 1.3.2. Di chuyển midpoint đến phần tử kế 1.4. Cắt danh sách ra 2 phần tại vị trí này End divide_from
  • 31. Mã C++ chia đôi DSLK template < class Record> Node<Record> *Sortable_list<Record> :: divide_from (Node<Record> *sub_list) { Node<Record> *position , *midpoint , *second_half ; if ((midpoint = sub_list) == NULL) return NULL ; position = midpoint->next ; while (position != NULL) { position = position->next; //Di chuyển một lần if (position != NULL) { //Dừng ngay trước điểm giữa midpoint = midpoint->next ; position = position->next ; //Di chuyển lần thứ hai } } second_half = midpoint->next ; //Phần sau là sau điểm dừng midpoint->next = NULL ; //Tách đôi danh sách return second_half ; }
  • 32. Trộn 2 DSLK có thứ tự 1 7 5 second 3 9 4 8 first ? Dummy node combined last
  • 33. Giải thuật trộn hai DSLK có thứ tự Algorithm Merge Input: hai DSLK first và second có thứ tự Output: một DSLK có thứ tự 1. last_sorted là một node giả 2. while (first và second khác NULL) //Cả hai vẫn còn 2.1. if (dữ liệu của first nhỏ hơn dữ liệu của second) 2.1.1. Nối first vào sau last_sorted //Gỡ phần tử từ 2.1.2. last_sorted là first //DSLK 1 2.1.3. Chuyển first đến phần tử kế //gắn vào kết quả 2.2. else 2.2.1. Nối second vào sau last_sorted //Gỡ phần tử từ 2.2.2. last_sorted là second //DSLK 2 2.2.3. Chuyển second đến phần tử kế //gắn vào kết quả 2.3. if (danh sách first còn) 2.3.1. Nối first vào sau last_sorted 2.4. else 2.4.1. Nối second vào sau last_sorted End Merge
  • 34. Mã C++ trộn hai DSLK có thứ tự template < class Record> Node<Record> *Sortable_list<Record> :: merge(Node<Record> *first , Node<Record> *second) { Node<Record> combined, *last_sorted = &combined; while (first != NULL && second != NULL) { if (first->entry <= second->entry) { last_sorted->next = first ; last_sorted = first ; first = first->next ; } else { last_sorted->next = second ; last_sorted = second ; second = second->next ; } } if (first == NULL) last_sorted->next = second ; else last_sorted->next = first ; return combined . next ; }
  • 35. Quick sort Sort (26, 33, 35, 29, 19, 12, 22) Sort (19, 12, 22) Sort (33, 35, 29) Combine into (12, 19, 22, 26, 29, 33, 35) Phân thành (19, 12, 22) và (33,35,29) với pivot=26 Phân thành (12) và (22) với pivot=19 Phân thành (29) và (35) với pivot=33 Sort (12) Sort (22) Combine into (12, 19, 22) Sort (29) Sort (35) Combine into (29, 33, 35)
  • 36. Giải thuật Quick sort Algorithm quick_sort Input: danh sách cần sắp xếp Output: danh sách đã được sắp xếp 1. if (có ít nhất 2 phần tử) //Phân hoạch danh sách thành 3 phần: //- Phần nhỏ hơn phần tử giữa //- Phần tử giữa //- Phần lớn hơn phần tử giữa 1.1. Phân hoạch danh sách ra 3 phần 1.2. Call quick_sort cho phần bên trái 1.3. Call quick_sort cho phần bên phải //Chỉ cần ghép lại là thành danh sách có thứ tự End quick_sort
  • 37. Mã C++ Quick sort trên danh sách liên tục template < class Record> void Sortable_list<Record> :: recursive_quick_sort( int low , int high) { //Phần được sắp xếp trong danh sách từ vị trí low đến vị trí high int pivot_position ; if (low < high) { //pivot_postition là vị trí của phần tử giữa pivot_position = partition(low , high) ; recursive_quick_sort(low , pivot_position − 1) ; recursive_quick_sort(pivot_position + 1 , high) ; //Danh sách kết quả đã có thứ tự trong khoảng từ low đến high } }
  • 38. Phân hoạch cho quick sort
  • 39. Phân hoạch cho quick sort (tt.)
  • 40. Giải thuật phân hoạch Algorithm partition Input: danh sách cần phân hoạch từ low đến high Output: đã phân hoạch làm 3 phần, vị trí pivot được ghi nhận //Chọn phần tử tại vị trí giữa là phần tử pivot và chuyển về đầu 1. swap list[low], list[(low+high)/2] 2. pivot = list[low] 3. last_small = low 4. for index = low+1 to high //Quét qua tất cả các phần tử còn lại 4.1. if list[index] < pivot 4.1.1. last_small = last_small + 1 4.1.2. swap list[last_small], list[index] //Chuyển qua phần nhỏ hơn 5. swap list[last_small], list[low] //Trả phần tử pivot về lại chính giữa 6. Vị trí pivot chính là last_small End partition
  • 41. Mã C++ phân hoạch template < class Record> int Sortable_list<Record> :: partition( int low , int high) { //Giả sử hàm swap (ind1, ind2) sẽ đổi chỗ 2 phần tử tại 2 vị trí đó Record pivot ; swap(low , (low + high)/2) ; pivot = entry[low] ; int last_small = low ; for ( int index = low + 1 ; index <= high ; index++) if (entry[index] < pivot) { last_small = last_small + 1 ; swap(last_small , index) ; } swap(low , last_small) ; return last_small ; }
  • 42. Ví dụ quick sort 19 35 33 26 29 12 22 recursive_quick_sort(0,6) pivot_position = partition(0,6) = 3 pivot index 26 recursive_quick_sort(0,2) recursive_quick_sort(4,6) 0 1 2 3 4 5 6 low=0 high=6 mid=(low+high)/2=3 last_small pivot_position
  • 43. Ví dụ quick sort (tt.) 22 19 12 recursive_quick_sort(0,2) pivot_position = partition(0,2) = 1 index pivot 19 recursive_quick_sort(0,0) recursive_quick_sort(2,2) (Không làm gì cả) 26 29 33 35 0 1 2 3 4 5 6 low=0 high=2 mid=(low+high)/2=1 last_small pivot_position
  • 44. Ví dụ quick sort (tt.) 29 33 35 recursive_quick_sort(4,6) pivot_position = partition(4,6) = 5 index pivot 33 recursive_quick_sort(4,4) recursive_quick_sort(6,6) (Không làm gì cả) 26 12 19 22 0 1 2 3 4 5 6 low=4 high=6 mid=(low+high)/2=5 last_small pivot_position
  • 45. Các trường hợp của Quick sort
  • 46. Đánh giá Quick sort Trường hợp xấu nhất: Một bên rỗng và một bên là n-1 phần tử => n(n-1)/2 Chọn phần tử pivot: Đầu (hay cuối): trường hợp xấu xảy ra khi danh sách đang có thứ tự (hoặc thứ tự ngược) Ở trung tâm, hoặc ngẫu nhiên: trường hợp xấu khó xảy ra Trường hợp trung bình: C( n ) = 2 n ln n + O ( n ) ≈ 1.39 n lg n + O ( n )
  • 47. Heap và Heap sort Heap (định nghĩa lại): Danh sách có n phần tử (từ 0 đến n-1) a k ≥ a 2k+1 và a k ≥ a 2k+2 (a k lớn nhất trong 3 phần tử) Đặc tính: a 0 là phần tử lớn nhất Danh sách chưa chắc có thứ tự Nửa sau của danh sách bất kỳ thỏa định nghĩa heap Heap sort: Lấy a 0 ra, tái tạo lại heap => Phần tử lớn nhất Lấy a 0 mới ra, tái tạo lại heap => Phần tử lớn kề …
  • 48. Giải thuật Heap sort Algorithm heap_sort Input: danh sách cần sắp xếp có n phần tử Output: danh sách đã sắp thứ tự //Xây dựng heap ban đầu 1. Call build_heap //Lần lượt lấy phần tử đầu ra đem về cuối danh sách hiện tại //rồi xây dựng heap trở lại 2. for index = size-1 to 0 //index là vị trí cuối của phần còn lại 2.1. swap list[0], list[index] //Đổi phần tử lớn nhất về cuối //Xây dựng lại heap với số phần tử giảm đi 1 2.2. Call rebuild_heap index-1 End heap_sort
  • 49. Mã C++ Heap sort template < class Record> void Sortable_list<Record> :: heap_sort( ) { Record current ; //Xây dựng heap ban đầu build_heap( ) ; for ( int last_unsorted = count − 1 ; last_unsorted > 0 ; last_unsorted−−) { //Giữ lại phần tử cuối cũ current = entry[last_unsorted] ; // Extract last entry from list. //Chép phần tử đầu (lớn nhất) về vị trí này entry[last_unsorted] = entry[0] ; //Xây dựng lại heap bằng cách chèn phần tử current vào đúng vị trí insert_heap(current , 0 , last_unsorted − 1) ; } }
  • 50. Biểu diễn Heap Dạng cây nhị phân: Node gốc là a 0 2 node con của phần tử a k là 2 phần tử a 2k+1 và a 2k+2 Ở mức cuối cùng, các node lấp đầy từ bên trái sang bên phải (cây nhị phân gần đầy đủ) 0 1 2 3 4 5 6 7 8
  • 51. Ví dụ Heap sort y r p d f b k a c current 0 1 2 3 4 5 6 7 8 y r p d f b k a c
  • 52. Ví dụ Heap sort (tt.) r f p d c b k a y current 0 1 2 3 4 5 6 7 8 r f p d c b k a y
  • 53. Ví dụ Heap sort (tt.) p f k d c b a r y current 0 1 2 3 4 5 6 7 8 p f k d c b a r y
  • 54. Ví dụ Heap sort (tt.) k f b d c a p r y current 0 1 2 3 4 5 6 7 8 k f b d c a p r y
  • 55. Ví dụ Heap sort (tt.) f d b a c k p r y current 0 1 2 3 4 5 6 7 8 f d b a c k p r y
  • 56. Ví dụ Heap sort (tt.) d c b a f k p r y current 0 1 2 3 4 5 6 7 8 d c b a f k p r y
  • 57. Ví dụ Heap sort (tt.) c a b d f k p r y current 0 1 2 3 4 5 6 7 8 c a b d f k p r y
  • 58. Ví dụ Heap sort (tt.) b a c d f k p r y current 0 1 2 3 4 5 6 7 8 b a c d f k p r y
  • 59. Giải thuật tái tạo lại heap Algorithm insert_heap Input: danh sách là heap trong khoảng từ low+1 đến high, current là giá trị cần thêm vào Output: danh sách là heap trong khoảng từ low đến high 1. Bắt đầu kiểm tra tại vị trí low 2. while (chưa kiểm tra xong đến high) 2.1. Tìm lớn nhất trong bộ ba phần tử current, list[2k+1], list[2k+2] 2.2. if (phần tử đó là current) 2.2.1. Ngừng vòng lặp 2.3. else 2.3.1. Dời phần tử lớn nhất lên vị trí hiện tại 2.3.2. Kiểm tra bắt đầu từ vị trí của phần tử lớn nhất này 3. Đưa current vào vị trí đang kiểm tra End insert_heap
  • 60. Mã C++ tái tạo lại heap template < class Record> void Sortable_list<Record> :: nsert_heap( const Record &current , int low , int high) { int large = 2 * low + 1; //P.tử lớn giả sử là tại 2k+1 while (large <= high) { if (large < high && entry[large] < entry[large + 1]) large++ ; //P.tử lớn tại 2k+2 if (current >= entry[large]) break; //Nếu current là lớn nhất thì thôi else { entry[low] = entry[large] ; //Không thì đẩy p.tử lớn nhất lên low = large ; //rồi tiếp tục kiểm tra về sau large = 2 * low + 1 ; } } entry[low] = current ; //Đây là vị trí thích hợp cho current }
  • 61. Giải thuật xây dựng heap ban đầu Algorithm build_heap Input: danh sách bất kỳ cần biến thành heap Output: danh sách đã là heap //Nửa sau của 1 danh sách bất kỳ thỏa tính chất của heap //Ta tìm cách xây dựng heap ngược từ giữa về đầu 1. for low = size/2 downto 0 //Từ vị trí low+1 đến cuối danh sách đang là heap 1.1. current = list[low] ; //Xây dựng lại heap trong khoảng [low, size-1] 1.2. Call insert_heap với current, low và size − 1 End build_heap
  • 62. Mã C++ xây dựng heap ban đầu template < class Record> void Sortable_list<Record> :: build_heap( ) { //Nửa sau của 1 danh sách bất kỳ thỏa tính chất của heap //Ta tìm cách xây dựng heap ngược từ giữa về đầu for ( int low = count/2 − 1 ; low >= 0 ; low−−) { Record current = entry[low] ; insert_heap(current , low , count − 1) ; } }
  • 63. Ví dụ xây dựng heap ban đầu p c y d f b k a r Bước 1 p c y r f b k a d Bước 2 p c y r f b k a d Bước 3 p r y c f b k a d Bước 3’ p r y d f b k a c Bước 4 y r p d f b k a c 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8
  • 64. Đánh giá Heap sort Trường hợp xấu nhất: C = 2 n lg n + O ( n ) M = n lg n + O ( n ) So với Quick sort Trung bình: chậm hơn quick sort Xấu nhất: O ( n lg n ) < n(n-1)/2