Một vòng lặp bất biến là gì?


268

Tôi đang đọc "Giới thiệu về thuật toán" của CLRS. Trong chương 2, các tác giả đã đề cập đến "bất biến vòng lặp". Một vòng lặp bất biến là gì?


4
Điều này có vẻ khá tốt để giải thích: cs.miami.edu/~burt/learning/Math120.1/Notes/LoopInvar.html
Tom Gullen


Chỉ trong trường hợp nếu ai đó muốn giải quyết vấn đề mã hóa thuật toán thực tế dựa trên khái niệm bất biến vòng lặp thì vui lòng tham khảo vấn đề này trên HackerRank. Họ cũng đã đề cập đến vấn đề sắp xếp chèn chỉ để chi tiết hóa khái niệm.
RBT

Người ta cũng có thể tham khảo các ghi chú ở đây để hiểu lý thuyết.
RBT

Câu trả lời:


345

Nói một cách đơn giản, bất biến vòng lặp là một số vị ngữ (điều kiện) giữ cho mỗi lần lặp của vòng lặp. Ví dụ: chúng ta hãy nhìn vào một forvòng lặp đơn giản trông như thế này:

int j = 9;
for(int i=0; i<10; i++)  
  j--;

Trong ví dụ này, điều đó đúng (với mỗi lần lặp) đó i + j == 9. Một bất biến yếu hơn mà cũng đúng là như vậy i >= 0 && i <= 10.


29
Đây là một ví dụ tuyệt vời. Nhiều lần khi tôi nghe một người hướng dẫn mô tả bất biến vòng lặp, nó chỉ đơn giản là "điều kiện vòng lặp", hoặc một cái gì đó tương tự. Ví dụ của bạn cho thấy rằng bất biến có thể nhiều hơn nữa.
Brian S

77
Tôi không thấy đây là một ví dụ hay bởi vì bất biến vòng lặp sẽ phần nào là mục tiêu của vòng lặp ... CLRS sử dụng nó để chứng minh tính đúng đắn của thuật toán sắp xếp. Đối với sắp xếp chèn, giả sử vòng lặp được lặp với i, ở cuối mỗi vòng lặp, mảng được sắp xếp cho đến phần tử thứ i.
Đụng độ

5
Vâng, ví dụ này không sai, nhưng chỉ là không đủ. Tôi quay lại @Clash, vì bất biến vòng lặp sẽ trình bày mục tiêu, không chỉ cho chính nó.
Jack

7
@Tomas Petricek - khi vòng lặp kết thúc, i = 10 và j = -1; vì vậy ví dụ bất biến yếu hơn mà bạn đưa ra có thể không đúng (?)
Raja

7
Mặc dù tôi đồng ý với các ý kiến ​​trên, tôi đã nêu lên câu trả lời này vì ... mục tiêu không được xác định ở đây. Xác định bất kỳ mục tiêu nào phù hợp và ví dụ này là tuyệt vời.
Flavius

119

Tôi thích định nghĩa rất đơn giản này: ( nguồn )

Bất biến vòng lặp là một điều kiện [trong số các biến chương trình] nhất thiết phải đúng ngay trước và ngay sau mỗi lần lặp của vòng lặp. (Lưu ý rằng điều này không nói gì về sự thật hoặc giả dối của nó thông qua một lần lặp.)

Chính nó, một bất biến vòng lặp không làm được gì nhiều. Tuy nhiên, với một bất biến thích hợp, nó có thể được sử dụng để giúp chứng minh tính đúng đắn của thuật toán. Ví dụ đơn giản trong CLRS có lẽ phải làm với việc sắp xếp. Ví dụ, hãy để bất biến vòng lặp của bạn giống như ở đầu vòng lặp, các imục đầu tiên của mảng này được sắp xếp. Nếu bạn có thể chứng minh rằng đây thực sự là một bất biến vòng lặp (nghĩa là nó giữ trước và sau mỗi lần lặp vòng lặp), bạn có thể sử dụng điều này để chứng minh tính đúng đắn của thuật toán sắp xếp: khi kết thúc vòng lặp, bất biến vòng lặp vẫn được thỏa mãn và bộ đếm ilà chiều dài của mảng. Do đó, các imục đầu tiên được sắp xếp có nghĩa là toàn bộ mảng được sắp xếp.

Một ví dụ đơn giản hơn: Loops bất biến, tính chính xác và dẫn xuất chương trình .

Cách tôi hiểu một bất biến vòng lặp là một công cụ chính thức, có hệ thống để lý luận về các chương trình. Chúng tôi đưa ra một tuyên bố duy nhất mà chúng tôi tập trung vào việc chứng minh sự thật và chúng tôi gọi đó là bất biến vòng lặp. Điều này tổ chức logic của chúng tôi. Mặc dù chúng ta cũng có thể tranh luận một cách không chính thức về tính đúng đắn của một số thuật toán, sử dụng một bất biến vòng lặp buộc chúng ta phải suy nghĩ rất cẩn thận và đảm bảo lý luận của chúng ta là kín gió.


10
Cần chỉ ra rằng "ngay sau mỗi lần lặp" bao gồm sau khi vòng lặp kết thúc - bất kể nó kết thúc như thế nào.
Robert S. Barnes

Cảm ơn rất nhiều vì câu trả lời này! Cái lớn nhất từ ​​nó là mục đích của việc bất biến vòng lặp này là để giúp chứng minh tính đúng đắn của thuật toán. Các câu trả lời khác chỉ tập trung vào bất biến vòng lặp là gì!
Neekey

39

Có một điều mà nhiều người không nhận ra ngay lập tức khi xử lý các vòng lặp và bất biến. Chúng bị lẫn lộn giữa bất biến vòng lặp và vòng lặp có điều kiện (điều kiện kiểm soát sự kết thúc của vòng lặp).

Như mọi người chỉ ra, bất biến vòng lặp phải đúng

  1. trước khi vòng lặp bắt đầu
  2. trước mỗi lần lặp của vòng lặp
  3. sau khi vòng lặp kết thúc

(mặc dù nó có thể tạm thời là sai trong phần thân của vòng lặp). Mặt khác, điều kiện vòng lặp phải là sai sau khi vòng lặp kết thúc, nếu không thì vòng lặp sẽ không bao giờ chấm dứt.

Do đó, bất biến vòng lặp và điều kiện vòng lặp phải là các điều kiện khác nhau.

Một ví dụ điển hình về bất biến vòng lặp phức tạp là tìm kiếm nhị phân.

bsearch(type A[], type a) {
start = 1, end = length(A)

    while ( start <= end ) {
        mid = floor(start + end / 2)

        if ( A[mid] == a ) return mid
        if ( A[mid] > a ) end = mid - 1
        if ( A[mid] < a ) start = mid + 1

    }
    return -1

}

Vì vậy, điều kiện vòng lặp có vẻ khá thẳng về phía trước - khi bắt đầu> kết thúc vòng lặp chấm dứt. Nhưng tại sao vòng lặp đúng? Vòng lặp bất biến chứng tỏ tính đúng đắn của nó là gì?

Bất biến là câu lệnh logic:

if ( A[mid] == a ) then ( start <= mid <= end )

Tuyên bố này là một tautology logic - nó luôn luôn đúng trong bối cảnh của vòng lặp / thuật toán cụ thể mà chúng tôi đang cố gắng chứng minh . Và nó cung cấp thông tin hữu ích về tính đúng đắn của vòng lặp sau khi nó kết thúc.

Nếu chúng ta trả về vì chúng ta đã tìm thấy phần tử trong mảng thì câu lệnh rõ ràng là đúng, vì nếu A[mid] == asau đó anằm trong mảng và midphải nằm giữa bắt đầu và kết thúc. Và nếu chấm dứt vòng lặp vì start > endsau đó không thể có số lượng như vậy start <= mid mid <= end và do đó chúng ta biết rằng báo cáo kết quả A[mid] == aphải là sai lầm. Tuy nhiên, kết quả là câu lệnh logic tổng thể vẫn đúng theo nghĩa rỗng. (Trong logic, câu lệnh if (false) thì (cái gì đó) luôn luôn đúng.)

Bây giờ những gì tôi đã nói về vòng lặp có điều kiện nhất thiết là sai khi vòng lặp kết thúc? Có vẻ như khi phần tử được tìm thấy trong mảng thì vòng lặp có điều kiện là đúng khi vòng lặp kết thúc!? Đó thực sự là không, bởi vì điều kiện vòng lặp ngụ ý là thực sự while ( A[mid] != a && start <= end )nhưng chúng tôi rút ngắn thử nghiệm thực tế vì phần đầu tiên được ngụ ý. Điều kiện này rõ ràng là sai sau vòng lặp bất kể vòng lặp kết thúc như thế nào.


Điều chắc chắn là sử dụng một câu lệnh logic như bất biến vòng lặp, bởi vì tất cả các câu lệnh logic có thể luôn luôn đúng, bất kể nó là điều kiện gì.
acgtyrant

Không có gì lạ, tôi nên nghĩ, vì không có gì đảm bảo có amặt trong đó A. Một cách không chính thức, "nếu khóa acó mặt trong mảng, nó phải xảy ra giữa startendbao gồm". Sau đó, nếu A[start..end]nó trống, điều đó akhông có trong A.
scanny

33

Các câu trả lời trước đã xác định một bất biến vòng lặp theo cách rất tốt.

Sau đây là cách các tác giả của CLRS sử dụng bất biến vòng lặp để chứng minh tính đúng đắn của Sắp xếp chèn.

Thuật toán sắp xếp chèn (như được đưa ra trong Sách):

INSERTION-SORT(A)
    for j ← 2 to length[A]
        do key ← A[j]
        // Insert A[j] into the sorted sequence A[1..j-1].
        i ← j - 1
        while i > 0 and A[i] > key
            do A[i + 1] ← A[i]
            i ← i - 1
        A[i + 1] ← key

Vòng lặp bất biến trong trường hợp này: Mảng con [1 đến j-1] luôn được sắp xếp.

Bây giờ hãy để chúng tôi kiểm tra điều này và chứng minh rằng thuật toán là chính xác.

Khởi tạo : Trước lần lặp đầu tiên j = 2. Vì vậy, mảng con [1: 1] là mảng cần kiểm tra. Vì nó chỉ có một yếu tố nên nó được sắp xếp. Như vậy bất biến được thỏa mãn.

Bảo trì : Điều này có thể được xác nhận dễ dàng bằng cách kiểm tra bất biến sau mỗi lần lặp. Trong trường hợp này, nó được thỏa mãn.

Chấm dứt : Đây là bước mà chúng tôi sẽ chứng minh tính đúng đắn của thuật toán.

Khi vòng lặp kết thúc thì giá trị của j = n + 1. Một lần nữa vòng lặp bất biến được thỏa mãn. Điều này có nghĩa là mảng con [1 đến n] nên được sắp xếp.

Đây là những gì chúng tôi muốn làm với thuật toán của chúng tôi. Do đó, thuật toán của chúng tôi là chính xác.


1
Đồng ý ... tuyên bố chấm dứt là rất quan trọng ở đây.
Gaurav Aradhye

18

Bên cạnh tất cả các câu trả lời hay, tôi đoán một ví dụ tuyệt vời từ Cách nghĩ về thuật toán, bởi Jeff Edmonds có thể minh họa rất rõ khái niệm này:

VÍ DỤ 1.2.1 "Thuật toán hai ngón tay Find-Max"

1) Thông số kỹ thuật: Một thể hiện đầu vào bao gồm danh sách L (1..n) của các phần tử. Đầu ra bao gồm một chỉ số i sao cho L (i) có giá trị tối đa. Nếu có nhiều mục có cùng giá trị này, thì bất kỳ mục nào trong số chúng được trả về.

2) Các bước cơ bản: Bạn quyết định phương pháp hai ngón tay. Ngón tay phải của bạn chạy xuống danh sách.

3) Thước đo tiến độ: Thước đo tiến độ là khoảng cách dọc theo danh sách ngón tay phải của bạn.

4) Vòng lặp bất biến: vòng lặp vòng lặp nói rằng ngón tay trái của bạn trỏ đến một trong những mục lớn nhất mà ngón tay phải của bạn gặp phải cho đến nay.

5) Các bước chính: Mỗi lần lặp, bạn di chuyển ngón tay phải xuống một mục trong danh sách. Nếu ngón tay phải của bạn bây giờ đang chỉ vào một mục lớn hơn thì mục nhập của ngón tay trái, sau đó di chuyển ngón tay trái của bạn để bằng ngón tay phải của bạn.

6) Tiến bộ: Bạn tiến bộ vì ngón tay phải của bạn di chuyển một mục.

7) Duy trì vòng lặp bất biến: Bạn biết rằng bất biến vòng lặp đã được duy trì như sau. Đối với mỗi bước, phần tử ngón tay trái mới là Max (phần tử ngón tay trái cũ, phần tử mới). Theo bất biến vòng lặp, đây là Max (Max (danh sách ngắn hơn), phần tử mới). Về mặt toán học, đây là Max (danh sách dài hơn).

8) Thiết lập bất biến vòng lặp: Ban đầu, bạn thiết lập bất biến vòng lặp bằng cách trỏ cả hai ngón tay vào phần tử đầu tiên.

9) Điều kiện thoát: Bạn đã hoàn thành khi ngón tay phải của bạn kết thúc việc duyệt qua danh sách.

10) Kết thúc: Cuối cùng, chúng tôi biết vấn đề được giải quyết như sau. Theo điều kiện xuất cảnh, ngón tay phải của bạn đã gặp phải tất cả các mục. Bằng bất biến vòng lặp, ngón tay trái của bạn chỉ điểm tối đa. Trả lại mục này.

11) Thời gian kết thúc và thời gian chạy: Thời gian cần thiết là một số lần không đổi độ dài của danh sách.

12) Các trường hợp đặc biệt: Kiểm tra xem điều gì xảy ra khi có nhiều mục có cùng giá trị hoặc khi n = 0 hoặc n = 1.

13) Chi tiết mã hóa và triển khai: ...

14) Bằng chứng chính thức: Tính chính xác của thuật toán tuân theo các bước trên.


Tôi nghĩ rằng câu trả lời này thực sự "đặt ngón tay" vào ý chính trực quan của một bất biến :).
Scanny

6

Cần lưu ý rằng Bất biến vòng lặp có thể giúp thiết kế các thuật toán lặp khi được coi là một khẳng định thể hiện mối quan hệ quan trọng giữa các biến phải đúng khi bắt đầu mỗi lần lặp và khi vòng lặp kết thúc. Nếu điều này giữ, tính toán đang trên đường đến hiệu quả. Nếu sai thì thuật toán đã thất bại.


5

Bất biến trong trường hợp này có nghĩa là một điều kiện phải đúng tại một điểm nhất định trong mỗi lần lặp.

Trong lập trình hợp đồng, bất biến là một điều kiện phải đúng (theo hợp đồng) trước và sau khi bất kỳ phương thức công khai nào được gọi.


4

Ý nghĩa của bất biến là không bao giờ thay đổi

Ở đây, bất biến vòng lặp có nghĩa là "Sự thay đổi xảy ra với biến trong vòng lặp (tăng hoặc giảm) không thay đổi điều kiện vòng lặp tức là điều kiện được thỏa mãn" để khái niệm bất biến vòng lặp xuất hiện


2

Thuộc tính vòng lặp bất biến là một điều kiện giữ cho mỗi bước thực hiện vòng lặp (nghĩa là đối với các vòng lặp, trong khi các vòng lặp, v.v.)

Điều này rất cần thiết cho một Bằng chứng bất biến vòng lặp, trong đó người ta có thể chỉ ra rằng một thuật toán thực thi chính xác nếu ở mỗi bước thực hiện của nó, thuộc tính bất biến vòng lặp này giữ.

Để thuật toán được chính xác, Vòng lặp bất biến phải giữ tại:

Khởi tạo (bắt đầu)

Bảo trì (mỗi bước sau)

Chấm dứt (khi nó kết thúc)

Điều này được sử dụng để đánh giá một loạt các thứ, nhưng ví dụ tốt nhất là các thuật toán tham lam cho biểu đồ có trọng số. Để một thuật toán tham lam mang lại một giải pháp tối ưu (một đường dẫn trên biểu đồ), nó phải đạt được kết nối tất cả các nút trong đường dẫn trọng lượng thấp nhất có thể.

Do đó, thuộc tính bất biến vòng lặp là đường dẫn được thực hiện có trọng số nhỏ nhất. Lúc đầu, chúng tôi chưa thêm bất kỳ cạnh nào, vì vậy thuộc tính này là đúng (trong trường hợp này không sai). Ở mỗi bước , chúng tôi đi theo cạnh trọng lượng thấp nhất (bước tham lam), vì vậy một lần nữa chúng tôi đang đi theo con đường trọng lượng thấp nhất. Cuối cùng , chúng tôi đã tìm thấy con đường có trọng số thấp nhất, vì vậy tài sản của chúng tôi cũng đúng.

Nếu một thuật toán không làm điều này, chúng tôi có thể chứng minh rằng nó không tối ưu.


1

Thật khó để theo dõi những gì đang xảy ra với các vòng lặp. Các vòng lặp không chấm dứt hoặc chấm dứt mà không đạt được hành vi mục tiêu của họ là một vấn đề phổ biến trong lập trình máy tính. Vòng lặp bất biến giúp. Bất biến vòng lặp là một tuyên bố chính thức về mối quan hệ giữa các biến trong chương trình của bạn, điều này đúng ngay trước khi vòng lặp được chạy (thiết lập bất biến) và lại đúng ở cuối vòng lặp, mỗi lần qua vòng lặp (duy trì bất biến ). Dưới đây là mô hình chung về việc sử dụng Vòng lặp bất biến trong mã của bạn:

... // Bất biến vòng lặp phải đúng ở đây
trong khi (ĐIỀU KIỆN KIỂM TRA) {
// đỉnh của vòng lặp
...
// dưới cùng của vòng lặp
// Bất biến vòng lặp phải đúng ở đây
}
// Chấm dứt + Vòng lặp bất biến = Mục tiêu
...
Giữa đỉnh và đáy của vòng lặp, phần đầu có lẽ được thực hiện để đạt được mục tiêu của vòng lặp. Điều này có thể làm phiền (làm sai) sự bất biến. Điểm của Vòng lặp bất biến là lời hứa rằng bất biến sẽ được khôi phục trước khi lặp lại thân vòng lặp mỗi lần. Có hai ưu điểm này:

Công việc không được chuyển sang đường tiếp theo theo những cách phụ thuộc dữ liệu phức tạp. Mỗi lần đi qua vòng lặp độc lập với tất cả những người khác, với sự bất biến phục vụ để liên kết các đường chuyền lại với nhau thành một tổng thể hoạt động. Lý do rằng vòng lặp của bạn hoạt động được giảm xuống thành lý do rằng bất biến vòng lặp được khôi phục với mỗi lần đi qua vòng lặp. Điều này phá vỡ hành vi tổng thể phức tạp của vòng lặp thành các bước đơn giản nhỏ, mỗi bước có thể được xem xét riêng. Điều kiện kiểm tra của vòng lặp không phải là một phần của bất biến. Nó là những gì làm cho vòng lặp chấm dứt. Bạn xem xét riêng hai điều: tại sao vòng lặp nên chấm dứt và tại sao vòng lặp đạt được mục tiêu khi nó chấm dứt. Vòng lặp sẽ chấm dứt nếu mỗi lần qua vòng lặp bạn di chuyển lại gần để thỏa mãn điều kiện kết thúc. Nó thường dễ dàng để đảm bảo điều này: vd bước một biến đếm cho đến khi nó đạt đến giới hạn trên cố định. Đôi khi lý do đằng sau chấm dứt là khó khăn hơn.

Bất biến vòng lặp phải được tạo để khi đạt được điều kiện chấm dứt và bất biến là đúng, thì mục tiêu đã đạt được:

bất biến + chấm dứt => mục tiêu
Cần thực hành để tạo ra các bất biến đơn giản và liên quan đến việc nắm bắt tất cả các mục tiêu đạt được ngoại trừ chấm dứt. Tốt nhất là sử dụng các ký hiệu toán học để diễn tả các bất biến vòng lặp, nhưng khi điều này dẫn đến các tình huống quá phức tạp, chúng ta dựa vào văn xuôi rõ ràng và lẽ thường.


1

Xin lỗi tôi không có quyền bình luận.

@Tomas Petricek như bạn đã đề cập

Một bất biến yếu hơn cũng đúng là i> = 0 && i <10 (vì đây là điều kiện tiếp tục!) "

Làm thế nào nó là một vòng lặp bất biến?

Tôi hy vọng tôi không sai, theo như tôi hiểu [1] , bất biến vòng lặp sẽ đúng ở đầu vòng lặp (Khởi tạo), nó sẽ đúng trước và sau mỗi lần lặp (Bảo trì) và nó cũng sẽ đúng sau chấm dứt vòng lặp (Chấm dứt) . Nhưng sau lần lặp cuối i trở thành 10. Vì vậy, điều kiện i> = 0 && i <10 trở thành sai và chấm dứt vòng lặp. Nó vi phạm thuộc tính thứ ba (Chấm dứt) của bất biến vòng lặp.

[1] http://www.win.tue.nl/~kbuchin/teaching/JBP030/notebooks/loop-invariants.html


Tôi đoán là điều này đúng bởi vì vòng lặp không thực sự thực thi trong các điều kiện đó.
muiiu

0

Bất biến vòng lặp là một công thức toán học như (x=y+1). Trong ví dụ đó, xybiểu diễn hai biến trong một vòng lặp. Xét hành vi thay đổi của các biến trong suốt hành của mã này, nó gần như không thể kiểm tra tất cả các khả năng xygiá trị và xem họ tạo ra bất kỳ lỗi. Hãy nói xlà một số nguyên. Số nguyên có thể giữ không gian 32 bit trong bộ nhớ. Nếu số lượng vượt quá, tràn bộ đệm xảy ra. Vì vậy, chúng ta cần chắc chắn rằng trong suốt quá trình thực thi mã, nó không bao giờ vượt quá không gian đó. để làm được điều đó, chúng ta cần hiểu một công thức chung cho thấy mối quan hệ giữa các biến. Rốt cuộc, chúng tôi chỉ cố gắng để hiểu hành vi của chương trình.


0

Nói một cách đơn giản, đó là một điều kiện LOOP đúng trong mỗi lần lặp:

for(int i=0; i<10; i++)
{ }

Trong đó chúng ta có thể nói trạng thái của tôi là i<10 and i>=0


0

Bất biến vòng lặp là một xác nhận đúng trước và sau khi thực hiện vòng lặp.


-1

Trong Tìm kiếm tuyến tính (theo bài tập được đưa ra trong sách), chúng ta cần tìm giá trị V trong mảng đã cho.

Nó đơn giản như quét mảng từ 0 <= k <length và so sánh từng phần tử. Nếu tìm thấy V hoặc nếu quét đạt đến độ dài của mảng, chỉ cần chấm dứt vòng lặp.

Theo sự hiểu biết của tôi trong vấn đề trên-

Vòng lặp bất biến (Khởi tạo): Không tìm thấy V trong lần lặp k - 1. Lần lặp đầu tiên, đây sẽ là -1 do đó chúng ta có thể nói V không tìm thấy ở vị trí -1

Bảo trì: Trong lần lặp lại tiếp theo, V không tìm thấy trong k-1 đúng

Chấm dứt: Nếu V tìm thấy ở vị trí k hoặc k đạt đến độ dài của mảng, chấm dứt vòng lặp.

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.