Sắp xếp chèn so với Thuật toán sắp xếp bong bóng


85

Tôi đang cố gắng hiểu một vài thuật toán sắp xếp, nhưng tôi đang đấu tranh để thấy sự khác biệt trong thuật toán sắp xếp bong bóng và sắp xếp chèn.

Tôi biết cả hai đều là O (n 2 ), nhưng có vẻ như với tôi rằng sắp xếp bong bóng chỉ làm bong bóng giá trị lớn nhất của mảng lên đầu cho mỗi lần vượt qua, trong khi sắp xếp chèn chỉ nhấn chìm giá trị thấp nhất xuống dưới cùng mỗi lần vượt qua. Không phải họ làm cùng một điều nhưng theo các hướng khác nhau?

Đối với sắp xếp chèn, số lượng so sánh / hoán đổi tiềm năng bắt đầu từ 0 và tăng lên mỗi lần (tức là 0, 1, 2, 3, 4, ..., n) nhưng đối với sắp xếp bong bóng, hành vi tương tự cũng xảy ra, nhưng ở cuối việc sắp xếp (tức là n, n-1, n-2, ... 0) bởi vì sắp xếp bong bóng không còn cần phải so sánh với các phần tử cuối cùng khi chúng được sắp xếp.

Tuy nhiên, đối với tất cả những điều này, có vẻ như một sự đồng thuận rằng nói chung loại chèn tốt hơn. bất cứ ai đó có thể trả lời tôi tại sao?

Chỉnh sửa: Tôi chủ yếu quan tâm đến sự khác biệt trong cách hoạt động của các thuật toán, chứ không phải quá nhiều về hiệu quả hay độ phức tạp tiệm cận của chúng.


1
Điều này cũng được ghi lại ở những nơi khác: ví dụ: xem en.wikipedia.org/wiki/Sorting_algorithm . Không có ý nghĩa gì để trùng lặp ở đây và một câu trả lời tốt sẽ được mở rộng.
Bathsheba

@Bathsheba 75 người đã ủng hộ và 88k người đã xem câu hỏi dường như không đồng ý; )
parsecer

@parsecer: Ha! Bây giờ tôi sẽ phải xem lại các câu trả lời. Câu trả lời được ủng hộ cao nhất hiện tại rất hữu ích; không chắc chắn về những người khác. Đây là một số điểm đại diện bị mất khi phản đối câu trả lời. Khẳng định "Đó là lý do tại sao sắp xếp chèn nhanh hơn sắp xếp bong bóng" trong câu trả lời được chấp nhận là không nhất thiết đúng.
Bathsheba

@Bathsheba Ồ không
parsecer

Câu trả lời:


38

Trong sắp xếp bong bóng ở bước lặp thứ i, bạn có tổng số ni-1 lần lặp bên trong (n ^ 2) / 2, nhưng trong sắp xếp chèn, bạn có tối đa lần lặp thứ i ở bước thứ i, nhưng trung bình là i / 2, vì bạn có thể dừng vòng lặp bên trong trước đó, sau khi bạn tìm thấy vị trí chính xác cho phần tử hiện tại. Vì vậy, bạn có (tổng từ 0 đến n) / 2 là (n ^ 2) / 4 tổng;

Đó là lý do tại sao sắp xếp chèn nhanh hơn sắp xếp bong bóng.


2
Tôi nghĩ rằng giải thích thuật toán ở khắp mọi nơi trên mạng.
sasha.sochka

3
vâng, nhưng có vẻ như OP vẫn doesnt chênh lệch đánh bắt trong các cơ chế
UmNyobe

15
Bạn có thể giả sử rằng tôi hiểu các nguyên tắc cơ bản . Những gì tôi muốn là một sự so sánh, và điều này thực sự khá tốt. Vì vậy, ý tưởng là trong khi sắp xếp chèn làm cho phần tử thứ i chìm xuống và sắp xếp bong bóng làm cho nó nổi bong bóng, sắp xếp chèn không làm cho nó giảm xuống dưới cùng, nó chỉ làm cho nó rơi vào đúng vị trí trong phần đã được sắp xếp. Vì vậy, nó ít so sánh / hoán đổi hơn. Có đúng không?
Migwell

1
Gì? "Vì vậy, bạn có (tổng từ 0 đến n) / 2 là (n ^ 2) / tổng 4" Điều đó yêu cầu một số bùng nổ, làm ơn! 0 + 1 + 2 + 3 + 4 + 5 = 15; 15/2 = 7,5; 7,5 * 4 = 30; sqrt (30) = gibberish
John Smith

@JohnSmith Tôi tin rằng có một lỗi nhỏ trong câu trả lời. Tổng từ 1 đến n là n * (n + 1) / 2 vì nó là một số tam giác. Tra cứu số tam giác để giải thích thêm. Vì vậy, số chia cho 2 chỉ là n * (n + 1) / 2.
CognizantApe

121

Sắp xếp chèn

Sau khi tôi lặp đi lặp lại là người đầu tiên tôi yếu tố được sắp xếp.

Trong mỗi lần lặp, phần tử tiếp theo được chuyển qua phần được sắp xếp cho đến khi nó đến đúng vị trí:

sorted  | unsorted
1 3 5 8 | 4 6 7 9 2
1 3 4 5 8 | 6 7 9 2

4 được đặt trong phần được sắp xếp

Mã giả:

for i in 1 to n
    for j in i downto 2
        if array[j - 1] > array[j]
            swap(array[j - 1], array[j])
        else
            break

Sắp xếp bong bóng

Sau khi tôi lặp lại, phần tử thứ i cuối cùng là lớn nhất và được sắp xếp theo thứ tự.

Trong mỗi lần lặp, hãy sàng lọc qua phần chưa được sắp xếp để tìm phần lớn nhất.

unsorted  | biggest
3 1 5 4 2 | 6 7 8 9
1 3 4 2 | 5 6 7 8 9

Số 5 bị sủi bọt ra khỏi phần chưa được sắp xếp

Mã giả:

for i in 1 to n
    for j in 1 to n - i
         if array[j] > array[j + 1]
             swap(array[j], array[j + 1])

Lưu ý rằng các triển khai điển hình kết thúc sớm nếu không có hoán đổi nào được thực hiện trong một trong các lần lặp của vòng lặp ngoài (vì điều đó có nghĩa là mảng đã được sắp xếp).

Sự khác biệt

Trong phân loại chèn, các phần tử được sắp xếp nổi bong bóng vào phần đã sắp xếp, trong khi trong sắp xếp bong bóng, các phần tử tối đa được đặt trong phần không được sắp xếp.


10
Cảm ơn, điều này rất rõ ràng! Tôi nghĩ điều chính tôi cần làm nổi bật là câu lệnh break trong Insertion Sort có nghĩa là nó có thể kết thúc sớm mỗi lần lặp lại: tức là khi nó đã tìm thấy vị trí của nó trong phần được sắp xếp. Sắp xếp bong bóng yêu cầu việc hoán đổi tiếp tục cho đến khi phần tử lớn nhất trong phần chưa được sắp xếp đến phần được sắp xếp, vì vậy sẽ không bao giờ kết thúc sớm. Đó là một bản tóm tắt tuyệt vời mặc dù, vì vậy 1
Migwell

4
Tôi nghĩ rằng đây nên là câu trả lời tốt nhất :)
Adelin

2
Cộng 1 cho độ rõ ràng, giá trị giáo khoa cho các bất biến vòng lặp chính của mỗi thuật toán. Thật tiếc vì nó không chứa sự so sánh rõ ràng về độ phức tạp (được biểu thị dưới dạng hàm của n ), dù sao thì tôi coi đây là một câu trả lời tốt hơn câu được chấp nhận, vì từ đó tôi có thể thấy sự khác biệt.
Honza Zidek

Tôi có thể hỏi tại sao bạn lại hoán đổi mục của mình trong mã Chèn giả ở mỗi bước không? if (a [j-1]> a [j]) then a [j] = a [j-1] ELSE if (a [j-1] <e && a [j]> e) than a [j] = e; ngắt; , trong đó e là mục cần được sắp xếp. Với giải pháp này, bạn không phải hoán đổi các mục đã được sắp xếp mà chỉ cần sao chép chúng. Mong được bạn giải thích, vì tôi hơi bối rối.
Karoly

@Karoly, tôi chọn phiên bản của mình vì nó đơn giản hơn. Của bạn hơi nhanh hơn, thật tốt khi bạn chỉ ra nó. Wikipedia mô tả cả hai phiên bản.
tom

16

Một sự khác biệt khác, tôi không thấy ở đây:

Sắp xếp bong bóng3 lần gán giá trị cho mỗi lần hoán đổi : trước tiên bạn phải tạo một biến tạm thời để lưu giá trị bạn muốn đẩy về phía trước (số 1), thay vì bạn phải viết biến hoán đổi khác vào vị trí bạn vừa lưu giá trị của (số 2) và sau đó bạn phải viết biến tạm thời của mình ở vị trí khác (số 3). Bạn phải làm điều đó cho từng vị trí - bạn muốn tiếp tục - để sắp xếp biến của bạn vào đúng vị trí.

Với sắp xếp chèn, bạn đặt biến của mình để sắp xếp trong một biến tạm thời và sau đó đặt tất cả các biến trước vị trí đó 1 vị trí lùi lại, miễn là bạn đến đúng vị trí cho biến của mình. Điều đó tạo ra 1 chỉ định giá trị cho mỗi vị trí . Cuối cùng, bạn ghi biến tạm thời của mình vào vị trí.

Điều đó cũng làm cho giá trị thấp hơn nhiều.

Đây không phải là lợi ích tốc độ mạnh nhất, nhưng tôi nghĩ nó có thể được đề cập.

Tôi hy vọng, tôi đã thể hiện bản thân có thể hiểu được, nếu không, xin lỗi, tôi không phải là người Anh


1
"và sau đó đặt tất cả các biến ở phía trước vị trí đó 1 điểm về phía sau" - và điều đó không yêu cầu một tải các phép gán, để thay đổi dữ liệu? (giả sử dù sao thì dữ liệu cũng được lưu trữ liền kề, không phải là danh sách được liên kết)
Mark K Cowan

@MarkKCowan, vâng, đó là nơi sắp xếp chèn thực hiện gán cho mỗi 'vị trí' như người dùng ở trên đặt nó. Về cơ bản, sắp xếp chèn có thể được viết với một phép gán trong vòng lặp bên trong, trong khi bubbleort có 3 phép gán trong vòng lặp bên trong.
JSQuareD 21/07/17

9

Ưu điểm chính của sắp xếp chèn là nó là thuật toán trực tuyến. Bạn không cần phải có tất cả các giá trị khi bắt đầu. Điều này có thể hữu ích khi xử lý dữ liệu đến từ mạng hoặc một số cảm biến.

Tôi có cảm giác rằng điều này sẽ nhanh hơn các n log(n)thuật toán thông thường khác . Bởi vì sự phức tạp sẽ là n*(n log(n))ví dụ: đọc / lưu trữ từng giá trị từ stream ( O(n)) và sau đó sắp xếp tất cả các giá trị ( O(n log(n))) dẫn đếnO(n^2 log(n))

Ngược lại, sử dụng Insert Sort cần O(n)đọc các giá trị từ luồng và O(n)đặt giá trị vào đúng vị trí, do đó, nó O(n^2)chỉ. Ưu điểm khác là bạn không cần bộ đệm để lưu trữ các giá trị, bạn sắp xếp chúng ở đích cuối cùng.


Nếu việc truyền dữ liệu theo thứ tự là một thứ gì đó khác ngoài việc chỉ đơn giản là quét một mảng, bạn có thể sắp xếp nhanh chóng hiệu quả hơn nhiều. ví dụ: chèn các phần tử vào cây nhị phân khi bạn nhận được chúng. Điều này cung cấp cho bạn O(n log(n))tổng số công việc đã thực hiện để có một bộ sưu tập được sắp xếp ở mọi bước trên đường đi. ( O(m)Truyền theo thứ tự tại bất kỳ thời điểm nào là ). Nếu bạn chỉ cần một kết quả được sắp xếp ở cuối, nhưng muốn tính toán sắp xếp chồng chéo với thời gian truyền dữ liệu, một Heap có thể tốt. (Và hoạt động tại chỗ, như sắp xếp chèn).
Peter Cordes

Dù sao, cả sắp xếp bong bóng hay sắp xếp chèn đều lý tưởng cho việc này với kích thước vấn đề đủ lớn để O(f(n))lớp phức tạp quan trọng hơn chi tiết triển khai và các yếu tố không đổi.
Peter Cordes

Sửa lại: Một đống không tốt cho việc này. Nó thực hiện hầu hết các công việc sắp xếp khi bạn loại bỏ các phần tử theo thứ tự đã sắp xếp, đó là lý do tại sao việc trồng trọt lại rẻ như vậy. Mục tiêu ở đây là hoàn thành phần lớn công việc vào thời điểm phần tử cuối cùng xuất hiện.
Peter Cordes

Dù sao, nếu bạn cần duy trì một mảng được sắp xếp để nchèn, thì thực sự nó sẽ tóm tắt thuật toán nào là tốt nhất để sắp xếp một mảng gần như được sắp xếp trong đó có một phần tử chưa được sắp xếp ở trên cùng. Nhiều O(n log(n))thuật toán sắp xếp nằm O(n)trong trường hợp gần như sắp xếp, vì vậy việc bạn cần sum(M=1..n, O(M * log(M)) )làm việc là không đúng . Điều đó thực sự sẽ xảy ra O(n^2 log(n)), nhưng với sự lựa chọn thuật toán phù hợp, chúng sẽ O(n^2)hoàn thành công việc. Tuy nhiên, Insertion-sort là hiệu quả nhất cho việc này.
Peter Cordes

7

Bubble Sort không trực tuyến (nó không thể sắp xếp một luồng đầu vào mà không biết sẽ có bao nhiêu mục) bởi vì nó không thực sự theo dõi tổng thể tối đa của các phần tử được sắp xếp. Khi một vật phẩm được đưa vào, bạn sẽ phải bắt đầu sủi bọt ngay từ đầu


4

Sắp xếp bong bóng tốt hơn là sắp xếp chèn chỉ khi ai đó đang tìm kiếm k phần tử hàng đầu từ một danh sách số lớn, tức là trong sắp xếp bong bóng sau k lần lặp bạn sẽ nhận được k phần tử hàng đầu. Tuy nhiên sau k lần lặp trong sắp xếp chèn, nó chỉ đảm bảo rằng k phần tử đó được sắp xếp.


2

Mặc dù cả hai loại đều là O (N ^ 2), các hằng số ẩn nhỏ hơn nhiều trong loại chèn. Hằng số ẩn đề cập đến số lượng thực tế các hoạt động nguyên thủy được thực hiện.

Khi sắp xếp chèn có thời gian chạy tốt hơn?

  1. Mảng gần như được sắp xếp-lưu ý rằng sắp xếp chèn thực hiện ít thao tác hơn trong trường hợp này, so với sắp xếp bong bóng.
  2. Mảng có kích thước tương đối nhỏ: sắp xếp chèn bạn di chuyển các phần tử xung quanh để đặt phần tử hiện tại. Điều này chỉ tốt hơn sắp xếp bong bóng nếu số lượng phần tử ít.

Lưu ý rằng sắp xếp chèn không phải lúc nào cũng tốt hơn sắp xếp bong bóng. Để tận dụng tối đa cả hai thế giới, bạn có thể sử dụng sắp xếp chèn nếu mảng có kích thước nhỏ và có thể hợp nhất sắp xếp (hoặc sắp xếp nhanh) cho các mảng lớn hơn.


2
Nếu số lượng phần tử không nhỏ, thì sắp xếp bong bóng sẽ tốt hơn như thế nào? Sự hiểu biết của tôi là việc bạn trượt trong IS hay hoán đổi trong BS sẽ phụ thuộc vào việc phần tử được so sánh là lớn hơn (IS) hay nhỏ hơn (BS) chứ không phụ thuộc vào số lượng phần tử. Xin vui lòng sửa cho tôi nếu sai.
Mustafa

0

Sắp xếp bong bóng gần như vô dụng trong mọi trường hợp. Trong các trường hợp sử dụng khi sắp xếp chèn có thể có quá nhiều hoán đổi, có thể sử dụng sắp xếp lựa chọn vì nó đảm bảo ít hơn N lần hoán đổi. Bởi vì sắp xếp lựa chọn tốt hơn sắp xếp bong bóng, sắp xếp bong bóng không có trường hợp sử dụng.


0

Số lần hoán đổi trong mỗi lần lặp lại

  • Insertion-sort thực hiện nhiều nhất 1 hoán đổi trong mỗi lần lặp .
  • Bubble-sort thực hiện hoán đổi từ 0 đến n trong mỗi lần lặp.

Truy cập và thay đổi phần được sắp xếp

  • Insertion-sort truy cập (và thay đổi khi cần) phần được sắp xếp để tìm vị trí chính xác của một số đang xét.
  • Khi được tối ưu hóa, Bubble-sort không truy cập vào những gì đã được sắp xếp.

Trực tuyến hay không

  • Insertion-sort đang trực tuyến. Điều đó có nghĩa là Insertion-sort nhận một đầu vào tại một thời điểm trước khi nó đặt vào vị trí thích hợp. Nó không phải chỉ để so sánh adjacent-inputs.
  • Bubble-sort không trực tuyến. Nó không hoạt động một đầu vào tại một thời điểm. Nó xử lý một nhóm đầu vào (nếu không phải tất cả) trong mỗi lần lặp. Bubble-sort chỉ so sánh và hoán đổiadjacent-inputs trong mỗi lần lặp lại.

0

sắp xếp chèn:

1. Trong phần chèn, hoán đổi sắp xếp là không cần thiết.

2. độ phức tạp thời gian của sắp xếp chèn là Ω (n) cho trường hợp tốt nhất và O (n ^ 2) trường hợp xấu nhất.

3. không phức tạp so với sắp xếp bong bóng.

4. ví dụ: chèn sách trong thư viện, sắp xếp thẻ.

sắp xếp bong bóng: 1. Bắt buộc phải thay đổi trong sắp xếp bong bóng.

2. độ phức tạp thời gian của sắp xếp bong bóng là Ω (n) cho trường hợp tốt nhất và O (n ^ 2) trường hợp xấu nhất.

3. phức tạp hơn so với sắp xếp chèn.


1
Làm thế nào mà hoán đổi không bắt buộc? Nó hoán đổi các phần tử để đưa một phần tử vào đúng vị trí. Và tôi sẽ không nói rằng loại bong bóng phức tạp hơn.
parsecer

-1

Sắp xếp chèn có thể được tiếp tục như " Tìm phần tử phải ở vị trí đầu tiên (tối thiểu), tạo một khoảng trống bằng cách dịch chuyển các phần tử tiếp theo và đặt nó ở vị trí đầu tiên. Tốt. Bây giờ hãy xem phần tử phải ở vị trí thứ 2. ... "và vân vân ...

Sắp xếp bong bóng hoạt động theo cách khác có thể được tiếp tục như " Miễn là tôi tìm thấy hai phần tử liền kề không đúng thứ tự, tôi hoán đổi chúng ".


Điều đó hữu ích với sắp xếp chèn, nhưng giải thích của bạn về sắp xếp bong bóng không bao gồm các vòng lặp thực tế, vì vậy tôi thực sự không thể so sánh chúng. Tôi sắp xếp chèn cũng có quy tắc hiệu quả. Miễn là tôi tìm thấy hai phần tử liền kề có thứ tự sai, tôi hoán đổi chúng , đó là cách các vòng lặp hoạt động sẽ khác.
Migwell

3
Đó không phải là sự lựa chọn sao?
harold

Oh yeah đó là sự thật ^
Migwell
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.