Chính xác thì thuật toán là gì?


12

Tôi biết rằng điều này nghe có vẻ hơi khó hiểu, thực tế tôi đã luôn nghĩ bên trong chiếc hộp, nhưng gần đây tôi đã nghĩ, có thể vì khoa học máy tính cung cấp một mức độ tự do cao, về những cách để đưa ra các chương trình khác ngoài những người được dạy trong trường đại học.

Hãy xem xét chức năng giai thừa. Thông thường chúng ta định nghĩa hàm này như

 int fact(int n) 
 { 
 int r = 1; 
 for(int i=2;i<=n;i++) 
 r = r*i; 
 return r; 
 } 

Tôi gọi đây là một thuật toán và không nghi ngờ gì rằng đây là cách đúng đắn để làm điều đó. Sau đó, tôi tự hỏi "tôi có thể làm điều này trong thời gian liên tục không?", Điều này cho phép ý tưởng sau: nếu tôi có một mảng các số nguyên trong đó mảng [n] chứa giai thừa của n? Khi mảng này được điền, tôi có thể chỉ cần định nghĩa thực tế là:

 int fact(int n) 
 { 
 return array[n]; 
 } 

Tuy nhiên, tôi dường như không thể sử dụng thuật toán này, mặc dù nó cung cấp kết quả chính xác và hoạt động trong thời gian không đổi O (1). Điều này có thể được gọi là một thuật toán? Nếu không, tại sao không? Tôi có thể lập luận rằng việc điền vào mảng sẽ yêu cầu một thuật toán hoạt động vào một lúc nào đó, ngay cả khi nó nằm trong não của chúng ta để chúng ta điền vào mảng, nhưng đây có thể là tiêu chí không? Làm thế nào là những khía cạnh được xử lý chính thức?

Lưu ý rằng khái niệm này có thể được mở rộng cho bất kỳ hàm nào hoạt động trên các số nguyên độc lập với số lượng đối số của nó, tôi sẽ chỉ phải sử dụng ma trận nếu hàm có 2 đối số hoặc 3 nếu hàm có 3 đối số, v.v. Ngoài ra, không phải các giải pháp này được sử dụng đơn giản là do tiêu thụ bộ nhớ?

Ngoài ra, không phải các chức năng đó cũng có thể bao gồm bất kỳ chương trình nào có đầu ra, vì tôi có thể tìm cách lập chỉ mục cho mọi đầu ra có thể mà chương trình có thể cung cấp.

Như một ví dụ khác, hãy xem xét việc sử dụng phổ biến của một mảng: tôi phân bổ một mảng ban đầu có kích thước N, sau đó tôi thêm các phần tử vào mảng bằng cách lưu trữ giá trị tại chỉ số n và tăng n lên một đơn vị. Sau đó, nếu tôi muốn tìm kiếm một phần tử, tôi không thể giúp thực hiện tìm kiếm tuyến tính trên mảng. Thay vào đó, nếu tôi tạo ra một mảng có kích thước, ví dụ, Integer.MAXVALUE, để lưu trữ các số nguyên, được khởi tạo bằng số 0, tôi có thể lưu trữ một số nguyên bằng cách đặt 1 vào chỉ mục của nó. Sau đó tôi có thể tìm kiếm sự tồn tại của nó trong mảng trong thời gian O (1). Điều gì xảy ra nếu tôi muốn có thể đặt nhiều đơn vị của cùng một số? Không có vấn đề gì, tôi chỉ cần tăng giá trị được lưu trữ tại chỉ mục của số nguyên.

Sắp xếp sẽ phức tạp hơn một chút, nhưng dù sao việc tra cứu và bổ sung có thể được thực hiện trong thời gian O (1).


Hàm thứ hai của bạn nên có mảng làm tham số. Nếu không, bạn bị lạc trong cái bẫy bắt buộc của trạng thái ẩn, rất hữu ích trong lập trình nhưng có thể làm cho mã của bạn rất khó để lý do.
jmite

Có, mã thứ hai của bạn có thể được gọi là thuật toán mà đầu vào là số n và mảng có tất cả các giai thừa. Trong mã đầu tiên, thuật toán chỉ có một đầu vào tức là số n.
Ankur

Bắt buộc: Hôm nay tôi sẽ không cố gắng xác định thêm các loại tài liệu mà tôi hiểu được chấp nhận trong phần mô tả tốc ký đó ["thuật toán"], và có lẽ tôi không bao giờ có thể thành công trong việc làm như vậy một cách thông minh. Nhưng tôi biết điều đó khi tôi nhìn thấy nó, và những điều được mô tả trong các bài viết dưới đây không phải là điều đó.
Patrick87

Liên quan đến câu hỏi này (nhưng không trả lời trực tiếp), cũng rất thú vị khi đọc "Thuật toán là gì?" bởi Yuri Gurevich, nghiên cứu của Microsoft, kỹ thuật Báo cáo MSR-TR-2011-116 research.microsoft.com/pubs/155608/209-3.pdf
godfatherofpolka

Bạn nói: "... nếu tôi có một mảng các số nguyên trong đó mảng [n] chứa giai thừa của n? Một khi mảng này được điền ....". Làm thế nào bạn sẽ điền vào một mảng với các giai thừa của tất cả các số nguyên? Mảng này sẽ có kích thước vô hạn và sẽ mất vô thời gian để lấp đầy. Do đó, câu hỏi của bạn không được đặt ra.
AP

Câu trả lời:


9

Định nghĩa không chính thức của một thuật toán trong sách giáo khoa phổ biến có dạng như sau:

Một thuật toán là (1) một thủ tục tính toán được xác định rõ (2) lấy một số đầu vào và (3) tạo ra một số đầu ra (4) cho một vấn đề tính toán được xác định rõ.

Trong trường hợp đầu tiên của bạn, bạn đã mã hóa một thuật toán trong đó: Vấn đề là tìm giai thừa (phần 4 của định nghĩa), đưa int n làm đầu vào (phần 2 của định nghĩa), mã mô tả tính toán được thực hiện (phần 1 của định nghĩa ), đầu ra là giai thừa (phần 3 của định nghĩa).

Trong trường hợp thứ hai của bạn: Vấn đề là tìm phần tử mảng ở vị trí n (phần 4 của định nghĩa), được n làm đầu vào (phần 3 của định nghĩa), mã mô tả tính toán được thực hiện (phần 2 của định nghĩa), đầu ra là phần tử ở vị trí n (phần 1 của định nghĩa).

Bạn đã lưu trữ giai thừa ở đó để nó cung cấp cho bạn giai thừa. Nếu bạn đã lưu trữ hình vuông hoặc hình khối ở đó, bạn sẽ có hình vuông hoặc hình khối, do đó, không thể nói rằng đoạn mã thứ hai tự nó là một thuật toán để tính các giai thừa.

Và nếu bạn nói rằng một mảng tìm kiếm cùng với một mảng có f (n) tại vị trí n là một thuật toán để tính f (n) thì bạn đã đi sâu đến mức không còn tính toán nào nữa bên dưới. Một thủ tục tính toán được xác định rõ sẽ là một phần thông tin hữu hạn. Nếu một mảng vô hạn của giai thừa là một phần của thủ tục tính toán thì điều này không giữ được. Vì vậy, đó sẽ không phải là một thuật toán để tính giai thừa.


Vấn đề thực sự với đề xuất của OP là mô tả về "quy trình tính toán được xác định rõ" là không hữu hạn. Tất nhiên, trừ khi chúng tôi giải thích ý nghĩa của chúng tôi về "quy trình tính toán được xác định rõ", người ta không thể biết trước liệu thuật toán của OP có hợp pháp hay không. Nó thực sự là một "thủ tục tính toán được xác định rõ" được đưa ra mảng vô hạn, vậy tại sao điều này là bất hợp pháp? OP thậm chí có thể mô tả bằng thuật ngữ hữu hạn làm thế nào để điền vào mảng. Điều gì sau đó đi sai? Định nghĩa không chính thức của bạn có thể phân biệt giữa siêu tính toán và tính toán (Turing).
Yuval Filmus

Một thủ tục tính toán được xác định rõ nên có thể biểu thị như một phần thông tin hữu hạn. Nếu một mảng vô hạn của giai thừa là một phần của nó thì điều này không giữ được.
Ranbir

2
Nó là rõ ràng như là một thông tin hữu hạn, như OP đã chứng minh. Các mảng được khởi tạo với tất cả các giai thừa. Đây là một mô tả hữu hạn. Nó chỉ không hoạt động hữu hạn. Theo cùng một cách, có một mô tả hữu hạn mà không hữu hạn. {(n,n!):nN}
Yuval Filmus

Mô tả của mảng có thể biểu thị như một phần thông tin hữu hạn nhưng bản thân mảng thì không.
Ranbir

Tôi cho rằng cả hai ví dụ của OP đều là thuật toánkhông tính được yếu tố cho tất cả các số nguyên. Nhưng đó chỉ là sự kén chọn, tôi cho là vậy.
Patrick87

5

Nhìn chung, thuật toán là một chuỗi các bước để giải quyết vấn đề .

Trong CS, những điều sau đây thường được hiểu / giả định khi sử dụng thuật toán thuật ngữ:

  • Thuật toán có mô tả hữu hạn và một quy trình được xác định rõ để thực hiện các bước của nó với bất kỳ trường hợp vấn đề nào. (Thêm bên dưới.)
  • Một trường hợp vấn đề được đưa ra dưới dạng một chuỗi hữu hạn (chuỗi các ký hiệu đầu vào) và đầu ra của thuật toán có thể được mã hóa thành một chuỗi hữu hạn.
  • Một vấn đề là một tập hợp các trường hợp vấn đề cùng với các đầu ra "chính xác" có thể cho mỗi trường hợp. "Giải quyết" có nghĩa là tạo ra một đầu ra chính xác.
  • (Thông thường) các trường hợp vấn đề có thể lớn tùy ý (có vô số trường hợp có thể xảy ra mà thuật toán hữu hạn của bạn phải giải quyết).

Trước khi CS được thành lập, các nhà toán học có cùng loại mối quan tâm mà bạn nêu ra và đưa ra các định nghĩa chính thức về tính toán để giải quyết các mối quan tâm này. Do đó, ngày nay, chúng ta có thể chính thức hóa tất cả các giả định trên bằng cách nói đơn giản "thuật toán là một thủ tục có thể được thực hiện trên máy Turing" . Đây có lẽ là câu trả lời chính thức tốt nhất cho câu hỏi của bạn.

Lưu ý rằng luận án Church-Turing nói rằng chúng tôi nghĩ rằng không có sự chính thức hóa các thuật toán "mạnh hơn" so với Turing Machine.

Ví dụ giai thừa được đưa vào một mô hình tính toán khác, được gọi là tính toán không đồng nhất. Máy Turing là một ví dụ về mô hình tính toán thống nhất : Nó có một mô tả duy nhất, hữu hạn và hoạt động cho các đầu vào có kích thước lớn tùy ý. Nói cách khác, tồn tại một TM giải quyết vấn đề cho tất cả các kích cỡ đầu vào.

Bây giờ, thay vào đó, chúng ta có thể xem xét tính toán như sau: Đối với mỗi kích thước đầu vào, tồn tại một TM (hoặc một số thiết bị tính toán khác) giải quyết vấn đề. Đây là một câu hỏi rất khác nhau. Lưu ý rằng một TM đơn lẻ không thể lưu trữ giai thừa của mỗi số nguyên, vì TM có mô tả hữu hạn. Tuy nhiên, chúng ta có thể tạo một TM (hoặc một chương trình trong C) lưu trữ các giai thừa của tất cả các số dưới 1000. Sau đó, chúng ta có thể tạo một chương trình lưu trữ các giai thừa của tất cả các số từ 1000 đến 10000. V.v.

Các loại tính toán không đồng nhất này thường được mô hình hóa trong CS lý thuyết bằng các mạch. Bạn xem xét một cấu trúc mạch khác nhau cho mỗi kích thước đầu vào có thể.

Các mô hình tính toán không đồng nhất thường không được coi là thuật toán , mặc dù chúng có thể phù hợp với câu đầu tiên của tôi. Lý do là chúng không phù hợp với các giả định chính của chúng tôi: chúng không có mô tả hữu hạn có thể được thực hiện để giải quyết vấn đề "toàn bộ" cho bất kỳ kích thước đầu vào nào. Thay vào đó, họ cần một mô tả lớn hơn và lớn hơn khi vấn đề trở nên lớn hơn (như cần một bảng tra cứu lớn hơn). Tuy nhiên, chúng vẫn là những mô hình tính toán thú vị.


Tôi nghĩ rằng mô hình tính toán dựa trên mạch của bạn là không phù hợp. Như bạn nói, một TM có một mô tả hữu hạn. Nhưng điều đó không loại trừ việc có một băng phụ trợ chứa đầy phiên bản được lập bảng của giai thừa. Một người thậm chí có thể làm "tệ hơn" và vẫn có một mô tả hữu hạn. Nhưng thực sự tất cả những gì bạn cần là một mô tả tính toán, cuối cùng là hữu hạn. Có nhiều cách thống nhất về mặt tính toán để xác định máy Turing với giai thừa được lập bảng, không có cách nào có thể thực sự tăng sức mạnh tính toán của TM. Do đó kết luận của bạn không giữ được.
babou

@babou, tôi không hiểu ý bạn. Ý của bạn là "không phù hợp" và kết luận nào tôi đưa ra là sai? Ghi chú: Tôi không phát minh ra mô hình mạch. Có lẽ tôi đã không làm tốt công việc mô tả nó. Điểm mấu chốt là, đối với mỗi đầu vào, chúng tôi cho phép một thiết bị tính toán khác nhau (TM hoặc mạch), có nghĩa là có thể không có thuật toán thống nhất tạo ra tất cả các thiết bị này (cho tất cả các kích thước đầu vào), hay nói cách khác, có thể không có mô tả hữu hạn mô tả tất cả chúng.
usul

Xem bảng biểu của hàm giai thừa như một tính toán không đồng nhất đối với tôi dường như không phải là cách thích hợp để đi. Nó thực sự rất đồng đều, đến mức các phân đoạn hữu hạn của nó có thể được xem là liên tục với một giới hạn ở vô cực là toàn bộ bảng. Đó là những gì được thực hiện với ngữ nghĩa của Scott. Hơn nữa, toàn bộ bảng thực sự có thể được mô tả chính xác theo cách tính toán, do đó sẽ có ý nghĩa tính toán khi xem xét một TM với một băng thêm có chứa bảng được tính toán trước. Câu trả lời của bạn dường như kết luận rằng một bảng được tính toán trước có thể được coi là một thuật toán.
babou

Bất kỳ bảng được tính toán trước cụ thể nào cũng có thể là một phần của thuật toán và đối với một chuỗi vô hạn các bảng được tính toán trước có kích thước ngày càng lớn, bạn có thể tạo ra bất kỳ một trong những điều này bằng thuật toán. Nhưng tôi sẽ không xem xét một tập hợp vô hạn các bảng tra cứu có kích thước ngày càng lớn, tự nó là một thuật toán hoặc một tính toán thống nhất vì nó có kích thước vô hạn.
usul

Bạn sẽ không coi đó là một thuật toán. Đây là chủ quan. Điều quan trọng là biết tại sao bạn không nên. Và không có lý do mà tôi có thể nhìn thấy. Bất kỳ khái niệm nào có ý nghĩa cho các thuật toán đều có ý nghĩa trong trường hợp đó. Tất cả những gì nó làm là trừu tượng ra việc tạo bảng, mặc dù điều đó có thể được tính riêng. Trên thực tế đây là một vấn đề hoàn toàn về ngữ nghĩa, vì xem xét trình tự tăng dần như vậy, hoặc thay thế nó bằng giới hạn vô hạn của nó, tính toán một cách toán học như nhau. Và các lý thuyết ngữ nghĩa của tính toán thực sự xem xét các giới hạn vô hạn như vậy, tuy nhiên được sản xuất hoặc đại diện.
babou

4

Thuật toán là một chương trình được viết bằng C, sẽ hoạt động với mọi độ dài đầu vào (giả sử bộ nhớ vô hạn và số nguyên không giới hạn). Trong các ví dụ của bạn, nếu chúng tôi muốn chương trình hoạt động với tất cả độ dài của đầu vào, thì bảng trong đó kết quả được lưu trữ sẽ vô cùng lớn; các chương trình trong C luôn hữu hạn, vì vậy phương pháp này không thể được sử dụng.

Định nghĩa của thuật toán là rất linh hoạt: trong những ngày đầu của lý thuyết đệ quy, nhiều định nghĩa đã được đề xuất, và tất cả chúng đều được hiển thị là tương đương. Ví dụ: thay vì C, bạn có thể sử dụng máy Turing. Tuy nhiên, các mô hình này không nhất thiết phải tương đương về hiệu quả : một vấn đề có thể được giải quyết hiệu quả hơn trong C so với sử dụng máy Turing. Khi quan tâm đến hiệu quả, chúng ta nên giới hạn bản thân trong tất cả các mô hình "đủ gần" với C liên quan đến thời gian chạy. Ví dụ: nếu chúng ta được phép sử dụng một lệnh tính toán trong một đơn vị thời gian, sau đó mô hình kết quả vẫn xác định cùng một tập hợp các hàm tính toán, nhưng một số hàm (như n !n!n!) có thể được tính toán trong đó hiệu quả hơn nhiều so với C.

Khi lo lắng về thời gian chạy thực tế trên một máy tính thực tế, chúng ta thậm chí nên cẩn thận hơn, nhưng điều này thường vượt quá giới hạn của khoa học máy tính lý thuyết, thật không may.


Nếu chúng ta rất cầu kỳ, chúng ta cần phải rõ ràng về sự khác biệt giữa các thuật toán và các hàm được tính toán bằng các thuật toán . Ví dụ, hàm giai thừa được lấy làm số tự nhiên và đầu ra n ! . Hàm giai thừa có thể được tính bằng thuật toán. Chúng ta nói rằng một hàm có thể tính toán được nếu nó có thể được tính bằng thuật toán nào đó.nn!

Chúng ta nên sử dụng khái niệm nào về thuật toán? Một đề nghị, được nêu ở trên, là sử dụng các chương trình C. Chúng ta có thể gọi khái niệm này là tính toán C. Turing-tính toán là những gì bạn nhận được khi bạn sử dụng máy Turing. Nó chỉ ra rằng một hàm là C-computable nếu và chỉ khi nó là Turing-computable. Theo nghĩa này, cả hai mô hình tính toán này đều tương đương nhau. Thật vậy, nhiều mô hình khác là tương đương, ví dụ như tất cả các ngôn ngữ lập trình được sử dụng chung (giả sử bộ nhớ vô hạn và các biến không giới hạn).

Chúng tôi nói rằng ngôn ngữ lập trình P là Turing-Complete là một chức năng có thể tính toán được P khi và chỉ khi nó là Turing-computable. Giả thuyết Turing Church Church là một tuyên bố không chính thức cho thấy tất cả các mô hình tính toán hợp lý có mô tả hữu hạn và mất thời gian hữu hạn là Turing hoàn chỉnh. Mô hình của bạn có một mô tả hữu hạn nhưng không mất thời gian hữu hạn.


3
lol "Một thuật toán là một chương trình được viết bằng C ..."?!?
vzn

2
"Thuật toán là một chương trình được viết bằng C" ... Tại sao bạn chỉ định ngôn ngữ? Nó làm cho vô nghĩa.
nouney

1
@nouney Tôi chỉ đang cố gắng cụ thể. Ngôn ngữ lập trình yêu thích của bạn cũng là Turing-Complete.
Yuval Filmus

@YuvalFilmus Vâng, bạn không cụ thể, bạn đang bối rối.
nouney

@nouney Bạn có thể thêm câu trả lời của riêng bạn.
Yuval Filmus

4

Phần quan trọng của định nghĩa chung về thuật toán mà bạn thiếu là đặc tả phải hữu hạn và kích thước của đặc tả không được thay đổi theo kích thước của đầu vào.

Bộ nhớ có thể lớn tùy ý và có thể nhập vào, nhưng để là một định nghĩa hữu ích của thuật toán, không gian mã phải là hữu hạn. Nếu không, bạn nhận được vấn đề mà bạn vừa xác định.

O(logA)AO(logn)O(logn!)O(n(logn)2)sn=O(2s)O(2s s2)O(1)


"không gian mã phải là hữu hạn ": Bạn có nghĩa là chương trình Lisp gọi evalhàm trên một số cấu trúc dữ liệu lớn mà nó vừa tạo và biểu thị một biểu thức lLisp, không thể được coi là một thuật toán. Tôi nghi ngờ rằng phần lớn mã được sản xuất tại MIT trong thế kỷ 20 không đủ điều kiện làm thuật toán. Đây chỉ là một đối số không chính thức, nhưng vấn đề chính thức nằm ở quan điểm về một đặc tả hữu hạn là gì, mà bạn đọc theo một cách quá hạn chế.
babou

Nếu biểu thức được tạo ra thì nó là hữu hạn. Không có vấn đề lớn như thế nào. Tuy nhiên, loại bỏ các hạn chế về độ chính xác của không gian mã có thể hữu ích, nó có thể được sử dụng để chứng minh các giới hạn thấp trong thời gian chạy (chẳng hạn như chứng minh mức thấp hơn trong thời gian chạy sắp xếp danh sách). Nhưng hầu như bất kỳ kết quả thú vị nào trên các thuật toán sẽ yêu cầu một không gian mã hữu hạn. Nó tương tự như cách đa thức phải có số lượng hệ số hữu hạn, nhưng chuỗi lũy thừa cũng hữu ích.
DanielV

Tôi không phải là chuyên gia về cách tính độ phức tạp (không phải lĩnh vực của tôi), nhưng thực tế là bạn có hoặc không có toán học để làm điều đó nên không ảnh hưởng đến thuật toán là gì. Vấn đề là chương trình Lisp có thể tiếp tục tăng kích thước mã của nó mà không bị ràng buộc. Sau đó, có thể có ý nghĩa hơn để phân tích điều này như một đoạn mã vô hạn với các thuộc tính tính toán cụ thể. Trường hợp của chức năng được lập bảng có thể được nhìn thấy trong ánh sáng đó. Tôi ngạc nhiên rằng câu trả lời có một ví dụ giới hạn (tôi sắp sửa nói giáo xứ ) quan điểm của những gì một thuật toán là.
babou

3

Một vài quan sát có thể hữu ích:

Vấn đề là tuyên bố về đầu vào cho phép và đầu ra tương ứng. Chúng là những gì chúng tôi muốn giải quyết. Thuật toán là các thủ tục tính toán. Chúng ta có thể nói rằng một thuật toán là chính xác đối với một vấn đề nếu nó chấp nhận các đầu vào được phép đối với vấn đề và tạo ra các đầu ra theo mô tả vấn đề.

Cả hai ví dụ của bạn đều là thuật toán, vì cả hai đều là các thủ tục tính toán rõ ràng. Các thuật toán có chính xác hay không phụ thuộc vào cách bạn xác định vấn đề và cách bạn diễn giải sự biểu diễn của thuật toán. Một số báo cáo vấn đề:

  1. nn!
  2. n>0n!< INT_MAXn!

Một số giải thích về đoạn mã đầu tiên của bạn:

  1. Đây là mã giả giống với C / C ++ ngoại trừ trong các chi tiết. intthực sự có nghĩa là "bất kỳ số nguyên", ví dụ.
  2. Điều này được hiểu là nó là một chương trình C / C ++ thực sự.

Giải thích 1 là chính xác cho câu lệnh vấn đề 1, miễn là giai thừa thừa nhận giá trị 1 cho các số âm (nếu không, chúng ta có thể sửa đổi câu lệnh vấn đề để hạn chế miền hoặc thuật toán để giải thích cho hành vi mong muốn). Giải thích 2 là chính xác cho câu lệnh vấn đề 2, với cùng một cảnh báo.

arrayarraynn>0n!< INT_MAXn!n<0 và như vậy, sẽ không thực tế khi hy vọng rằng thuật toán sẽ chính xác cho một vấn đề cho phép các giá trị đó.

Tổng quát hơn - các hàm tính toán trước vào các bảng là một kỹ thuật phổ biến vì chính xác lý do bạn nhận thấy: bạn có thể thực hiện tính toán một lần, và sau đó sử dụng lại kết quả của tính toán đó nhiều lần. Đối với nhiều chức năng, nó có rất nhiều ý nghĩa. Yếu tố là một ví dụ tuyệt vời: nó phát triển rất nhanh, một mảng tương đối nhỏ có thể lưu trữ hầu như tất cả các giá trị số nguyên bạn cần trong thực tế (bài tập: số nguyên nhỏ nhất là gìnn!232n!264

kknknk+n


Tôi sẽ nghĩ rằng khái niệm về một thuật toán vượt xa giới hạn kích thước từ của máy tính. Tôi cảm thấy rằng bạn chỉ đang né tránh vấn đề.
babou

1

Một thuật toán là một chương trình viết bằng một ngôn ngữ Turing hoàn tất mà tạm dừng provably trên tất cả các đầu vào hợp lệ. Tất cả các ngôn ngữ lập trình tiêu chuẩn là Turing-Complete. Từ này bắt nguồn từ một bản dịch tiếng Âu của tên al-Khwārizmī, một nhà toán học, nhà thiên văn học và nhà địa lý học người Ba Tư, người đã xây dựng nên từ nhà toán học Ấn Độ thế kỷ thứ 7 Brahmagupta, người đã giới thiệu hệ thống chữ số Ấn Độ cho thế giới phương Tây.

Câu hỏi dường như về cơ bản là liệu các bảng tra cứu có phải là một phần của thuật toán hay không. Chắc chắn rồi! Trong bảng Turing máy (TM) có thể được mã hóa trong bảng trạng thái của TM. TM có thể khởi tạo băng dựa trên lượng dữ liệu hữu hạn được lưu trữ trong bảng chuyển đổi. Tuy nhiên, "thuật toán" không chạy trên đầu vào vô hạn, chỉ đầu vào hữu hạn, là các máy trạng thái hữu hạn "tầm thường" (FSM) .


3
Tại sao nó phải ở trong một ngôn ngữ hoàn chỉnh TUring?
babou

1

Tóm lại : Thuật toán là phần mang tính xây dựng của một bằng chứng mang tính xây dựng rằng một vấn đề nhất định có một giải pháp. Động lực cho định nghĩa này là sự đồng hình hóa Curry-Howard giữa các chương trình và bằng chứng, xem xét rằng một chương trình chỉ có lợi ích nếu nó giải quyết được một vấn đề, nhưng có thể chứng minh như vậy. Định nghĩa này cho phép trừu tượng hơn và để lại một số cánh cửa mở về loại lĩnh vực có thể liên quan, ví dụ về các thuộc tính hữu hạn.

Cảnh báo . Tôi đang cố gắng tìm một cách tiếp cận chính thức để trả lời câu hỏi. Tôi nghĩ rằng nó là cần thiết, nhưng dường như không có người dùng nào trả lời cho đến nay (bao gồm cả tôi và một số ít rõ ràng về nó trong các bài đăng khác) có nền tảng phù hợp để phát triển đúng các vấn đề liên quan đến toán học xây dựng, lý thuyết bằng chứng, lý thuyết loại và các kết quả như Curry-Howard giữa các bằng chứng và chương trình. Tôi đang làm hết sức mình ở đây, với bất kỳ đoạn kiến ​​thức nào tôi có (tin vào) có, và tôi chỉ nhận thức được những hạn chế của câu trả lời này. Tôi chỉ hy vọng đưa ra một số gợi ý về những gì tôi nghĩ câu trả lời sẽ như thế nào. Nếu bạn thấy bất kỳ điểm nào rõ ràng sai chính thức (có thể chứng minh được), vui lòng cho tôi ngay bây giờ trong một nhận xét - hoặc qua email.

Xác định một số vấn đề

Một cách tiêu chuẩn để xem xét thuật toán là tuyên bố rằng thuật toán là một chương trình được chỉ định chính xác tùy ý cho một số thiết bị máy tính , bao gồm cả những thuật toán không có giới hạn trong bộ nhớ. Các langage cũng có thể là ngôn ngữ máy tính. Trên thực tế, nó là đủ để xem xét tất cả các chương trình cho một thiết bị máy tính hoàn chỉnh Turing (ngụ ý không có giới hạn bộ nhớ). Nó có thể không cung cấp cho bạn tất cả các bài thuyết trình về thuật toán, theo nghĩa là các thuật toán phải được thể hiện dưới dạng phụ thuộc vào chi tiết của nó trên bối cảnh diễn giải, thậm chí là lý thuyết, vì mọi thứ đều được định nghĩa theo một số mã hóa. Nhưng, vì nó sẽ tính toán tất cả những gì cần tính toán, nên nó sẽ bao gồm bằng cách nào đó tất cả các algoritms, cho đến mã hóa.

π

π, có thể theo nghĩa toán học của hầu hết tất cả. Nhưng điều đó sẽ đòi hỏi độ chính xác cao hơn trong định nghĩa.

Vì vậy, câu hỏi thực sự là để biết các thuật toán có ý nghĩa là gì. Câu trả lời là các thuật toán có ý nghĩa là những thuật toán giải quyết vấn đề, tính toán từng bước "giải pháp", "câu trả lời" cho vấn đề đó. Một thuật toán rất thú vị nếu nó liên quan đến một vấn đề mà nó giải quyết.

Vì vậy, đưa ra một vấn đề chính thức làm thế nào để chúng ta có được một thuật toán giải quyết vấn đề. Cho dù rõ ràng hay ngầm định, các thuật toán được liên kết với ý tưởng rằng có tồn tại một giải pháp cho vấn đề, điều này có thể được chứng minh là đúng. Cho dù kỹ thuật chứng minh của chúng tôi là chính xác là một vấn đề khác, nhưng chúng tôi ít nhất cố gắng để thuyết phục bản thân. Nếu bạn giới hạn mình trong toán học xây dựng, đó thực sự là những gì chúng ta phải làm (và là một hạn chế tiên đề rất dễ chấp nhận đối với hầu hết toán học), cách để chứng minh sự tồn tại của một giải pháp là trải qua các bước chứng minh thực sự thể hiện một cấu trúc đại diện cho giải pháp, bao gồm cả các bước khác có thể thiết lập tính chính xác.

Tất cả các lập trình viên đều nghĩ một cái gì đó như: nếu tôi sử dụng dữ liệu theo cách tương tự và như vậy, thì tôi nhận được tiện ích này có các thuộc tính phù hợp vì định lý Sesame và chạy phép chuyển đổi bảo toàn foo này, tôi nhận được câu trả lời mong muốn . Nhưng bằng chứng thường không chính thức và chúng tôi không tìm ra tất cả các chi tiết, điều này giải thích tại sao một vệ tinh cố quay quanh Sao Hỏa dưới lòng đất (trong số những thứ khác). Chúng tôi thực hiện nhiều lý do, nhưng chúng tôi thực sự chỉ giữ phần xây dựng để xây dựng giải pháp và chúng tôi mô tả nó bằng ngôn ngữ máy tính để trở thành thuật toán giải quyết vấn đề.

Các thuật toán thú vị (hoặc chương trình)

Tất cả điều này là để giới thiệu những ý tưởng sau đây, là đối tượng của nhiều nghiên cứu hiện tại (trong đó tôi không phải là chuyên gia). Khái niệm " thuật toán thú vị " được sử dụng ở đây là của tôi, được giới thiệu như một người giữ chỗ không chính thức cho các định nghĩa chính xác hơn.

Một thuật toán thú vị là phần xây dựng của một bằng chứng xây dựng rằng một vấn đề nhất định có một giải pháp . Điều đó có nghĩa là bằng chứng thực sự phải thể hiện giải pháp chứ không chỉ đơn giản là chứng minh sự tồn tại của nó, ví dụ bằng mâu thuẫn. Để biết thêm chi tiết, xem Logic Trực giácCấu tạo trong Toán học.

Tất nhiên đây là một định nghĩa rất hạn chế, chỉ xem xét những gì tôi gọi là thuật toán thú vị. Vì vậy, nó bỏ qua gần như tất cả chúng. Nhưng tất cả các sách giáo khoa của chúng tôi về thuật toán cũng vậy. Họ cố gắng chỉ dạy một số trong những người thú vị.

Đưa ra tất cả các tham số của vấn đề (dữ liệu đầu vào), nó sẽ cho bạn biết làm thế nào để có được kết quả được chỉ định từng bước. Một ví dụ điển hình là độ phân giải của phương trình ( thuật toán tên thực sự bắt nguồn từ tên của nhà toán học Ba Tư, Muḥammad ibn Mūsā al-Khwārizmī , người đã nghiên cứu độ phân giải của một số phương trình). Các phần của bằng chứng được sử dụng để xác định rằng một số giá trị được tính toán trong thuật toán có một số thuộc tính, nhưng các phần này không cần phải được giữ trong chính thuật toán.

Tất nhiên, điều này phải diễn ra trong khuôn khổ logic chính thức để thiết lập dữ liệu được tính toán với những bước nào, các bước tính toán cơ bản được phép và các tiên đề được sử dụng là gì.

Quay trở lại ví dụ giai thừa của bạn, nó có thể được hiểu là một thuật toán, mặc dù là một thuật toán tầm thường. Hàm giai thừa bình thường tương ứng với một bằng chứng rằng, với một số khung số học và được cho một số nguyên n, có một số là tích của n số nguyên đầu tiên. Điều này là khá đơn giản, như là tính toán giai thừa. Nó có thể phức tạp hơn cho các chức năng khác.

Bây giờ, nếu bạn quyết định lập bảng giai thừa, giả sử bạn có thể, điều này không đúng với tất cả các số nguyên (nhưng có thể đúng với một số miền hữu hạn của các giá trị), tất cả những gì bạn đang làm là bao gồm trong các tiên đề của bạn bằng cách xác định bằng một tiên đề mới giá trị của nó cho mỗi số nguyên, do đó bạn không còn cần phải chứng minh (do đó để tính toán) bất cứ điều gì.

Nhưng một hệ thống các tiên đề được coi là hữu hạn (hoặc ít nhất là được xác định một cách hữu hạn). Và có vô số giá trị cho giai thừa, mỗi giá trị một số nguyên. Vì vậy, bạn đang gặp rắc rối cho hệ tiên đề hữu hạn của mình nếu bạn tiên đề hóa một hàm vô hạn, tức là được xác định trên một miền vô hạn. Điều đó dịch tính toán trong thực tế là việc tìm kiếm bảng của bạn sẽ không thể được thực hiện cho tất cả các số nguyên. Điều đó sẽ giết chết yêu cầu về độ chính xác thông thường đối với các thuật toán (nhưng nó có nghiêm ngặt như thường được trình bày không?).

Bạn có thể quyết định có một trình tạo tiên đề được xác định chính xác để xử lý tất cả các trường hợp. Điều này sẽ số tiền, ít nhiều, bao gồm chương trình giai thừa chuẩn trong thuật toán của bạn để khởi tạo mảng khi cần. Điều đó được gọi là ghi nhớ bởi các lập trình viên. Đây thực sự là lần gần nhất bạn có được tương đương với một bảng được tính toán trước. Có thể hiểu rằng có một bảng được tính toán trước, ngoại trừ thực tế bảng được tạo ra trong chế độ đánh giá lười biếng , bất cứ khi nào cần thiết. Cuộc thảo luận này có lẽ sẽ cần một chút quan tâm chính thức hơn.

Bạn có thể xác định các hoạt động nguyên thủy của mình theo ý muốn (trong sự nhất quán với hệ thống chính thức của bạn) và gán cho chúng bất kỳ chi phí nào bạn chọn khi sử dụng thuật toán, để phân tích hiệu suất hoặc độ phức tạp. Nhưng, nếu các hệ thống cụ thể thực sự thực hiện thuật toán của bạn (ví dụ máy tính hoặc não) không thể tôn trọng các thông số kỹ thuật chi phí này, phân tích của bạn có thể thú vị về mặt trí tuệ, nhưng không có giá trị sử dụng thực tế trong thế giới thực.

21000

Chương trình nào thú vị

Thảo luận này nên được liên kết chính xác hơn với các kết quả như sự đồng hình hóa Curry-Howard giữa các chương trình và bằng chứng. Nếu bất kỳ chương trình nào thực sự là bằng chứng của một cái gì đó, thì bất kỳ chương trình nào cũng có thể được hiểu là một chương trình thú vị theo nghĩa của định nghĩa trên.

Tuy nhiên, theo sự hiểu biết (có giới hạn) của tôi, sự đồng hình này chỉ giới hạn ở các chương trình có thể được gõ tốt trong một số hệ thống gõ thích hợp, trong đó các kiểu tương ứng với các mệnh đề của lý thuyết tiên đề. Do đó không phải tất cả các chương trình có thể đủ điều kiện là chương trình thú vị. Tôi đoán là theo nghĩa đó, một thuật toán được cho là để giải quyết vấn đề.

Điều này có lẽ loại trừ hầu hết các chương trình "được tạo ngẫu nhiên".

Nó cũng là một định nghĩa hơi mở về "thuật toán thú vị" là gì. Bất cứ chương trình nào có thể được xem là thú vị chắc chắn là như vậy, vì có một hệ thống loại được xác định làm cho nó thú vị. Nhưng một chương trình không thể đánh máy cho đến nay, có thể trở nên có thể đánh máy được với một loại sytem tiên tiến hơn, và do đó trở nên thú vị. Chính xác hơn, nó luôn luôn thú vị, nhưng vì thiếu kiến ​​thức về hệ thống loại thích hợp, chúng tôi không thể biết điều đó.

Tuy nhiên, người ta biết rằng không phải tất cả các chương trình đều có thể đánh máy được, vì người ta biết rằng một số biểu thức lambda, như thực hiện bộ kết hợp Y , không thể được nhập vào hệ thống loại âm thanh .

Quan điểm này chỉ áp dụng cho các hình thức lập trình có thể được liên kết trực tiếp với một số hệ thống chứng minh tiên đề. Tôi không biết làm thế nào nó có thể được mở rộng cho các hình thức tính toán cấp thấp như Máy Turing. Tuy nhiên, vì thuật toán và khả năng tính toán thường là một trò chơi mã hóa các vấn đề và giải pháp (nghĩ về arithologists được mã hóa trong phép tính lambda ), người ta có thể xem xét rằng bất kỳ tính toán được xác định chính thức nào có thể được hiển thị là mã hóa thuật toán cũng là một thuật toán. Các bảng mã như vậy có lẽ chỉ sử dụng một phần rất nhỏ của những gì có thể được thể hiện trong một hình thức chính thức cấp thấp, chẳng hạn như Turing Machines.

Một lợi ích của phương pháp này là nó đưa ra một khái niệm về thuật toán trừu tượng và độc lập hơn với các vấn đề về mã hóa thực tế, về "tính đại diện vật lý" của miền tính toán. Vì vậy, người ta có thể, ví dụ, xem xét các miền với các đối tượng vô hạn miễn là có một cách sử dụng âm thanh tính toán.


2
Đây không phải là một cái nhìn dễ dàng về vấn đề này, mặc dù nó là một vấn đề cơ bản. Tôi đã phải đơn giản hóa thái quá và tôi có thể đã phạm sai lầm. Nhưng, nếu bạn muốn downvote, xin vui lòng cho tôi biết tại sao.
babou

Vâng, tôi không chắc những gì với downvote.
Bút danh

@Pseudonymous Trong trường hợp của tôi. Tôi nghĩ rằng tôi biết. Nó nghi ngờ đó là cuộc chiến cũ giữa các nhà ngữ nghĩa học và thuật toán, đặc biệt là những người làm việc về khả năng tính toán. Đó là cuộc chiến giữa triết lý và kinh doanh, nó là gì và chi phí là bao nhiêu. Tôi quan tâm đến các thuật toán "có ý nghĩa". Tôi đã sửa đổi cho phù hợp (nhưng tôi ở rìa kiến ​​thức của tôi dường như vẫn còn tốt hơn hầu hết). Bạn có thể bị ghettoisation tương tự. - - - Tuy nhiên. một điều khá rõ ràng là về chủ đề tinh tế này, bất cứ ai có ý kiến ​​đáng giá nửa xu sẽ không mơ ước hạ thấp mà không có lời giải thích phù hợp.
babou

Sau khi đọc cả câu hỏi và câu trả lời của bạn, tôi đã cố gắng hạ thấp nó, bởi vì nó không tập trung đủ vào câu hỏi thực tế và chứa quá nhiều suy nghĩ còn dang dở. Ngoài ra, tôi không nghĩ rằng "giải quyết vấn đề" là phần còn thiếu trong định nghĩa của thuật toán. Nhưng tôi đồng ý rằng "ngữ nghĩa" không nên bị bỏ qua trong định nghĩa về những gì cấu thành một thuật toán.
Thomas Klimpel

@ThomasKlimpel Như tôi đã nói, tôi không đủ chuyên môn về các vấn đề thực sự. Và tôi nói thêm rằng không có câu trả lời nào khác. Làm các thuật toán không giống như hiểu chúng là gì. Nhận thức của tôi về kiến ​​thức hạn chế của tôi, điều sẽ là không khoa học để che giấu là nguồn gốc của cảm giác suy nghĩ dang dở này. Có vẻ tốt hơn để nhấn mạnh sự tồn tại của vấn đề, thay vì bỏ qua chúng. Tôi đã giải quyết từng ví dụ, nhiều hơn từ một ngữ nghĩa POV hơn là từ một thuật toán, vì câu hỏi là một câu hỏi ngữ nghĩa ("Cái gì là ...?"). Bạn có nghĩ rằng câu trả lời khác mang lại bất kỳ sự hiểu biết chính thức. Cf ý kiến ​​của tôi
babou

0

Không có định nghĩa chính thức tốt về "thuật toán" tại thời điểm viết. Tuy nhiên, có những người thông minh làm việc trên nó.

Những gì chúng ta biết là bất kể "thuật toán" là gì, nó nằm ở đâu đó giữa "hàm toán học" và "chương trình máy tính".

Một hàm toán học là khái niệm chính thức của ánh xạ từ đầu vào đến đầu ra. Vì vậy, ví dụ, "sort" là ánh xạ giữa một chuỗi các mục có thể sắp xếp và một chuỗi các mục có thể sắp xếp cùng loại, ánh xạ từng chuỗi theo trình tự được sắp xếp. Hàm này có thể được thực hiện bằng các thuật toán khác nhau (ví dụ: sắp xếp hợp nhất, sắp xếp heap). Lần lượt, mỗi thuật toán có thể được thực hiện bằng các chương trình khác nhau (thậm chí được cung cấp cùng ngôn ngữ lập trình).

Vì vậy, cách xử lý tốt nhất mà chúng ta có về "thuật toán" là gì, đó là một loại lớp tương đương trên các chương trình, trong đó hai chương trình tương đương nhau nếu chúng thực hiện "về cơ bản giống nhau". Bất kỳ hai chương trình thực hiện cùng một thuật toán đều phải tính toán cùng một hàm, nhưng điều ngược lại là không đúng.

Tương tự, có một lớp tương đương giữa các thuật toán, trong đó hai thuật toán tương đương nếu chúng tính toán cùng một hàm toán học.

Phần khó trong tất cả những điều này là cố gắng nắm bắt những gì chúng ta muốn nói là "về cơ bản là cùng một thứ".

Có một số điều rõ ràng mà chúng ta nên bao gồm. Ví dụ, hai chương trình về cơ bản là giống nhau nếu chúng chỉ khác nhau bởi các lần đổi tên. Hầu hết các mô hình ngôn ngữ lập trình đều có các khái niệm nguyên gốc về "tính tương đương" (ví dụ: giảm beta và chuyển đổi eta trong phép tính lambda), vì vậy chúng ta cũng nên đưa chúng vào.

Bất cứ mối quan hệ tương đương nào chúng ta chọn, điều này cho chúng ta một số cấu trúc. Các thuật toán tạo thành một thể loại bởi thực tế rằng chúng là thể loại thương số của các chương trình. Một số quan hệ tương đương thú vị được biết là làm phát sinh các cấu trúc phân loại thú vị; ví dụ, phạm trù thuật toán đệ quy nguyên thủy là một đối tượng phổ quát trong phạm trù các phạm trù. Bất cứ khi nào bạn thấy cấu trúc thú vị như thế, bạn biết rằng dòng điều tra này có thể sẽ hữu ích.


1
Tôi không nghĩ thật công bằng khi nói rằng không có định nghĩa chính thức tốt về thuật toán. Đây là trường hợp khoảng 100 năm trước.
Juho

1
@Juho Có thể là Bút danh làm cho âm thanh quá mạnh, mặc dù anh ta cố gắng giảm nhẹ tuyên bố, đặc biệt thêm rằng tình hình đang tiến triển. Tuy nhiên, tôi nghĩ rằng anh ấy khá đúng trong đánh giá của mình. Tôi phản ứng muộn, vì tôi đã dành nhiều thời gian cho việc này, và cảm thấy khá giống nhau. Mọi người đã cải thiện đáng kể sự hiểu biết của họ, nhưng toàn bộ cuộc thảo luận cho thấy rằng không có sự đồng thuận thực sự ... và tôi thấy hầu hết các đóng góp vô cùng non nớt, dựa trên mức độ của những người liên quan. Nếu anh ta không công bằng, bạn nghĩ ai đã đưa ra một định nghĩa chính thức tốt?
babou

Bạn đúng 100%. Và tôi nghĩ rằng nếu Turing còn sống, hoặc bất kỳ nhà lý thuyết nào khác trong lý thuyết phức tạp, anh ta sẽ đồng ý 100% với bạn. Các học giả cần phải từ bỏ chủ nghĩa tam sinh của họ. Nó thực sự đang cản trở lĩnh vực này. Điều này cuối cùng sẽ xảy ra bằng mọi cách, một khi họ chết. Cảm ơn lòng tốt cho điều đó.
BananaCats Tác giả

-4

Câu hỏi và mô tả của bạn không liên quan nhiều. Thuật toán là lý thuyết và không liên quan đến bất kỳ ngôn ngữ lập trình. Thuật toán là một tập hợp các quy tắc hoặc các bước (thủ tục) để giải quyết vấn đề. Vấn đề của bạn có thể được giải quyết bằng nhiều cách hoặc nhiều thuật toán.

Giải pháp thứ hai của bạn có nghĩa là tính toán trước một mảng lớn các yếu tố mà ban đầu sẽ mất rất nhiều thời gian sau đó lưu trữ nó. Nó sẽ tiêu thụ nhiều dung lượng hơn nhưng cuối cùng nó sẽ nhanh hơn trong khi cái đầu tiên không tiêu thụ dung lượng nhưng tiêu thụ năng lượng tính toán nên bạn sẽ phải chọn tùy thuộc vào môi trường của bạn.


Vâng, hoàn toàn không có mối quan hệ. Công cụ đột phá.
BananaCats Tác giả
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.