Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Việc đệ quy dựa trên một quan sát đơn giản, mà tôi sẽ đưa ra một đối số kết hợp, vì lý do tại sao nó là sự thật, chứ không phải là một bằng chứng toán học thông qua các công thức.

Bất cứ khi nào bạn chọn các yếu tố

    subset(n - 1, k)
9 trong số
if k == 0:
    return 1
if n == k:
    return 1
0, có hai trường hợp:

  1. Bạn chọn phần tử
    if k == 0:
        return 1
    if n == k:
        return 1
    
    1
  2. Bạn không chọn phần tử
    if k == 0:
        return 1
    if n == k:
        return 1
    
    1

Vì các sự kiện này là loại trừ lẫn nhau, tổng số lượng kết hợp được đưa ra bởi số lượng kết hợp khi chọn

if k == 0:
    return 1
if n == k:
    return 1
1 và các kết hợp khi bạn không chọn
if k == 0:
    return 1
if n == k:
    return 1
1.

Chọn phần tử if k == 0: return 1 if n == k: return 1 1

Vì chúng tôi đã chọn một yếu tố, chúng tôi chỉ cần chọn một yếu tố

if k == 0:
    return 1
if n == k:
    return 1
6 khác. Ngoài ra, vì chúng tôi đã quyết định một yếu tố - về việc nó có được bao gồm hay không - đã, chúng tôi chỉ cần xem xét các yếu tố
if k == 0:
    return 1
if n == k:
    return 1
7 còn lại.

Do đó, số lượng kết hợp để chọn phần tử

if k == 0:
    return 1
if n == k:
    return 1
1 được đưa ra bởi

    subset(n - 1, k - 1)

Không chọn phần tử if k == 0: return 1 if n == k: return 1 1

Vẫn còn các yếu tố

    subset(n - 1, k)
9 để lựa chọn, nhưng vì chúng ta đã quyết định về yếu tố
if k == 0:
    return 1
if n == k:
    return 1
1, vẫn chỉ còn
def C(n,k):
  if k == 1:
    return n
  if k == n:
    return 1
  return C(n-1,k-1)+C(n-1,k)
2 các yếu tố để lựa chọn. Do đó:

    subset(n - 1, k)

Trường hợp cơ sở

Việc đệ quy sử dụng thực tế, rằng chúng ta thường có thể phân biệt giữa hai tình huống, các giải pháp trong đó phần tử

if k == 0:
    return 1
if n == k:
    return 1
0 là một phần của giải pháp đó và những giải pháp không có.

Tuy nhiên, sự khác biệt như vậy không phải lúc nào cũng có thể được thực hiện:

  • Khi chọn tất cả các phần tử (tương ứng với trường hợp
    def C(n,k):
      if k == 1:
        return n
      if k == n:
        return 1
      return C(n-1,k-1)+C(n-1,k)
    
    4 trong mã bên dưới)
  • hoặc khi không chọn các phần tử nào cả (tương ứng với trường hợp
    def C(n,k):
      if k == 1:
        return n
      if k == n:
        return 1
      return C(n-1,k-1)+C(n-1,k)
    
    5 trong mã bên dưới)

Trong những trường hợp này, chỉ có chính xác một giải pháp, do đó

if k == 0:
    return 1
if n == k:
    return 1

Đảm bảo nó hoạt động

Để làm điều đó, chúng ta cần phải thuyết phục bản thân (hoặc chứng minh) rằng trường hợp cơ sở luôn bị ảnh hưởng tại một số điểm.

Chúng ta hãy giả sử rằng

def C(n,k):
  if k == 1:
    return n
  if k == n:
    return 1
  return C(n-1,k-1)+C(n-1,k)
6 tại một số điểm. Vì theo giả định của chúng tôi,
if k == 0:
    return 1
if n == k:
    return 1
0 ban đầu lớn hơn hoặc bằng
    subset(n - 1, k)
9, nên phải có một số điểm mà
def C(n,k):
  if k == 1:
    return n
  if k == n:
    return 1
  return C(n-1,k-1)+C(n-1,k)
9, vì
if k == 0:
    return 1
if n == k:
    return 1
0 và
    subset(n - 1, k)
9 giảm hoặc chỉ
if k == 0:
    return 1
if n == k:
    return 1
0 giảm

Điều này ngụ ý, rằng phải có một cuộc gọi đến

C(8,5) calls C(7,4) and C(7,5)
C(7,4) calls C(6,3) and C(6,4)
C(7,5) calls C(6,4) and C(6,5)
C(6,3) calls C(5,2) and C(5,3)
C(6,4) calls C(5,3) and C(5,4)
C(6,4) calls C(5,3) and C(5,4)
C(6,5) calls C(5,4) and C(5,5)
3 để nó xảy ra, rằng ____20 giảm xuống dưới
    subset(n - 1, k)
9. Tuy nhiên, điều này là không thể vì chúng tôi có một trường hợp cơ sở trên
def C(n,k):
  if k == 1:
    return n
  if k == n:
    return 1
  return C(n-1,k-1)+C(n-1,k)
9 khi chúng tôi trả lại hằng số
C(8,5) calls C(7,4) and C(7,5)
C(7,4) calls C(6,3) and C(6,4)
C(7,5) calls C(6,4) and C(6,5)
C(6,3) calls C(5,2) and C(5,3)
C(6,4) calls C(5,3) and C(5,4)
C(6,4) calls C(5,3) and C(5,4)
C(6,5) calls C(5,4) and C(5,5)
7.

Chúng tôi kết luận rằng

if k == 0:
    return 1
if n == k:
    return 1
0 giảm tại một số điểm sao cho
def C(n,k):
  if k == 1:
    return n
  if k == n:
    return 1
  return C(n-1,k-1)+C(n-1,k)
9 hoặc giảm chính xác
    subset(n - 1, k)
9 lần như vậy
counts = np.zeros((18,18),dtype=int)
1.

Vì vậy, trường hợp cơ sở hoạt động.

Kết hợp

Rất nhiều vấn đề trong toán học và khoa học máy tính có các giải pháp đệ quy. Trong phần này của bài giảng, chúng tôi sẽ nghiên cứu một vấn đề từ toán học có một giải pháp đệ quy thanh lịch.

Biểu tượng kết hợp hoặc "n chọn k" có nhiều ứng dụng trong toán học. Trong xác suất, lý thuyết về số lượng cách mà chúng ta có thể có được các đầu k trong một chuỗi n lật một đồng tiền công bằng.

Hướng dẫn n choose k python recursive - n chọn k python đệ quy
or "n choose k" has many applications in mathematics. In probability theory
Hướng dẫn n choose k python recursive - n chọn k python đệ quy
counts the number of ways that we can get k heads in a sequence of n flips of a fair coin.

Hướng dẫn n choose k python recursive - n chọn k python đệ quy
được tính toán thông qua công thức

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Hai trường hợp đặc biệt rất dễ tính toán.

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Một cách để tính toán một kết hợp là tính toán tất cả các giai thừa liên quan và sau đó chia mẫu số thành tử số. Điều này không thực tế cho giá trị lớn vừa phải của N vì các giai thừa phát triển rất nhanh như là một hàm của n. Thay vào đó, phương pháp phổ biến nhất để tính toán một kết hợp sử dụng mối quan hệ đệ quy này:

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Mối quan hệ đệ quy này kết hợp với hai trường hợp đặc biệt cho phép xây dựng định nghĩa hàm đệ quy trong Python để tính toán một sự kết hợp.

def C(n,k):
  if k == 1:
    return n
  if k == n:
    return 1
  return C(n-1,k-1)+C(n-1,k)

Điều này hoạt động, và không tính toán giá trị chính xác cho một kết hợp.

Cách tiếp cận này có một lỗ hổng. Hãy xem xét những gì xảy ra khi chúng ta cố gắng tính toán C (8,5).

C(8,5) calls C(7,4) and C(7,5)
C(7,4) calls C(6,3) and C(6,4)
C(7,5) calls C(6,4) and C(6,5)
C(6,3) calls C(5,2) and C(5,3)
C(6,4) calls C(5,3) and C(5,4)
C(6,4) calls C(5,3) and C(5,4)
C(6,5) calls C(5,4) and C(5,5)

Những gì bạn bắt đầu nhận thấy sau một thời gian là các chức năng tương tự được gọi là nhiều lần. Hiệu ứng này trở nên nghiêm trọng đối với N và K lớn đến nỗi hàm đệ quy đơn giản được hiển thị ở trên trở nên không hiệu quả.

Chúng ta có thể xây dựng một chương trình minh họa vấn đề này tồi tệ như thế nào. Bí quyết là tuyên bố một mảng hai chiều toàn cầu

counts = np.zeros((18,18),dtype=int)

Điều đó lưu trữ thông tin về số lần chúng ta gọi C với mỗi cặp giá trị tham số n và k.

Sau đó, chúng tôi sửa đổi chức năng tính toán kết hợp để ghi lại số lần nó được gọi với mỗi cặp tham số.

def C(n,k):
  counts[n][k] += 1;

     if k == 1:
    return n
  if k == n:
    return 1
  return C(n-1,k-1)+C(n-1,k)

Vào cuối chương trình, chúng tôi đổ dữ liệu đếm này vào một tệp.

def saveCounts():
  with open('counts.txt','w') as f:
    for row in counts:
      for col in row:
        f.write('{:5d}'.format(col))
      f.write('\n')

Kết quả là gây sốc. Dưới đây là tập hợp các số lượng kết quả khi chúng tôi cố gắng tính toán C (16,10):

0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0 1287 1287    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0  495 1287  792    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0  165  495  792  462    0    0    0    0    0    0    0    0    0    0    0    0    0
    0   45  165  330  462  252    0    0    0    0    0    0    0    0    0    0    0    0
    0    9   45  120  210  252  126    0    0    0    0    0    0    0    0    0    0    0
    0    1    9   36   84  126  126   56    0    0    0    0    0    0    0    0    0    0
    0    0    1    8   28   56   70   56   21    0    0    0    0    0    0    0    0    0
    0    0    0    1    7   21   35   35   21    6    0    0    0    0    0    0    0    0
    0    0    0    0    1    6   15   20   15    6    1    0    0    0    0    0    0    0
    0    0    0    0    0    1    5   10   10    5    1    0    0    0    0    0    0    0
    0    0    0    0    0    0    1    4    6    4    1    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    1    3    3    1    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    1    2    1    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    1    1    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    1    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0

Những gì chúng ta có thể đọc từ bảng này là C (2,1), C (2,2) và C (3,2) mỗi người được gọi là tổng cộng 1287 lần trong quá trình tính toán C (16,10) . Vấn đề này về các cuộc gọi chức năng dự phòng sẽ tồi tệ hơn theo cấp số nhân khi N và K trở nên lớn hơn. Vào thời điểm bạn đến N = 30 Phương pháp đệ quy đơn giản này để tính toán C (N, K) trở nên hoàn toàn không thực tế.

Ghi nhớ kết quả

Bản sửa lỗi đơn giản cần thiết để loại bỏ các cuộc gọi dự phòng đến một hàm đệ quy được gọi là ghi nhớ. Ý tưởng là ghi nhớ bất kỳ giá trị nào chúng tôi tính toán, để lần sau chúng tôi được yêu cầu tính toán một giá trị mà chúng tôi có thể tìm kiếm nó thay vì tính toán lại nó. Điều này hoạt động tốt nhất cho các hàm đệ quy với số lượng thông số số nguyên vừa phải. Trong trường hợp đó, chúng ta có thể nhớ các giá trị mà chúng ta đã tính toán trước đó bằng cách lưu trữ các giá trị trong bảng. Bất cứ khi nào chúng tôi được yêu cầu tính toán một giá trị, chúng tôi bắt đầu bằng cách tham khảo ý kiến ​​bảng.

Trong trường hợp hàm để tính toán các kết hợp, chúng tôi tiến hành như sau. Chúng tôi bắt đầu bằng cách tạo một mảng hai chiều toàn cầu để giữ các giá trị hàm được ghi nhớ.

c = np.zeros((100,100),dtype=int)

Sau đó, chúng tôi viết lại hàm đệ quy để sử dụng bảng. Bất cứ khi nào chúng tôi được yêu cầu tính toán C (N, K) cho một N và K cụ thể, chúng tôi bắt đầu bằng cách kiểm tra bảng để xem có tính toán không. Nếu nó chưa được tính toán, chúng tôi tính toán nó và lưu giá trị trong bảng trước khi quay lại với kết quả.

    subset(n - 1, k)
0

Thay thế đệ quy bằng một bảng

Một tác dụng phụ thú vị của giải pháp ghi nhớ là nó kết thúc việc lấp đầy bảng C [n] [k] với các giá trị cho C (n, k).

Một cách tiếp cận trực tiếp hơn để thực hiện vấn đề kết hợp một cách hiệu quả là chỉ viết mã điền vào bảng với các giá trị phù hợp.

Chúng ta có thể làm điều này với một chức năng

    subset(n - 1, k)
1

Khi mảng C được lấp đầy đúng với các giá trị, chúng ta có thể viết lại hàm để tính toán các kết hợp

    subset(n - 1, k)
2

Để viết chức năng khởi tạo, chúng ta chỉ cần sao chép logic trong giải pháp đệ quy ban đầu

def C(n,k):
  if k == 1:
    return n
  if k == n:
    return 1
  return C(n-1,k-1)+C(n-1,k)

trong một tập hợp các vòng lặp. Có hai điều chúng ta cần làm. Đầu tiên là viết một cặp vòng lặp điền vào các mục C [N] [K] cho tất cả N và K trong các trường hợp cơ sở. Các trường hợp cơ sở cho các kết hợp là k = 1 và k = n:

    subset(n - 1, k)
4

Cuối cùng, chúng tôi xây dựng một vòng lặp điền vào C [N] [K] cho tất cả các mục còn lại. Chúng ta phải cẩn thận khi xây dựng vòng lặp để đảm bảo rằng công thức cho c [n] [k] chỉ sử dụng các mục mà vòng lặp đã điền vào. Đây là cấu trúc vòng lặp chính xác để làm điều này.

    subset(n - 1, k)
5

Tích hợp Romberg

Trong một bài giảng trước đó, chúng tôi đã sử dụng quy tắc hình thang để ước tính khu vực dưới đường cong. Ý tưởng cơ bản là phân chia phạm vi tích hợp thành một số lượng lớn các phân nhóm. Trên mỗi ô con này, chúng tôi xây dựng một hình thang có diện tích xấp xỉ diện tích dưới đường cong trên con con đó.

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Diện tích của một hình thang như vậy là H (f (xi) + f (xi + 1))/2. Thêm tất cả các khu vực hình thang này cho chúng ta ước tính diện tích hình thang cho N Subintervals:

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Quy tắc hình thang tạo thành điểm khởi đầu cho một phương pháp tinh vi hơn. Bước đầu tiên trong phương pháp này là một kỹ thuật gọi là ngoại suy Richardson.

Phép ngoại suy Richardson bắt đầu bằng việc xem xét thuật ngữ lỗi trong quy tắc hình thang. Khi chúng ta triển khai quy tắc hình thang để ước tính tích phân với N Subintervals và kích thước bước của H, quy tắc hình thang thường tạo ra kết quả chính xác với một yếu tố tỷ lệ thuận với H2.

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Ký hiệu O (H2) tôi đã sử dụng ở đây có nghĩa là lỗi là thứ tự H2. Một cách khác để viết thực tế này là viết thuật ngữ lỗi như là sự kết hợp của các quyền hạn khác nhau của H:

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

.

Bước tiếp theo là triển khai phép ngoại suy Richardson, đây là một mẹo đại số kỳ lạ, nhưng hiệu quả. Trong mẹo này, chúng tôi viết ra mối quan hệ lỗi hai lần, một lần đối với n hình thang như chúng tôi đã thấy ở trên và lần thứ hai cho 2 N hình thang. Tăng số lượng hình thang bằng hệ số 2 làm giảm kích thước bước từ H đến H/2, vì vậy chúng tôi nhận được hai biểu thức này cho lỗi:

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Nhân phương trình thứ hai với 4 và trừ phương trình đầu tiên từ nó tạo ra

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Chúng ta có thể viết lại điều này là

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

hoặc

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Bằng cách sử dụng thủ thuật đại số đơn giản này, chúng tôi đã chuyển từ một phương pháp có thuật ngữ lỗi với cường độ O (H2) sang phương pháp có thuật ngữ lỗi với cường độ O (H4).

Tốt hơn nữa, thủ thuật này có thể được lặp lại. Tôi sẽ dành cho bạn các chi tiết, nhưng lặp đi lặp lại thủ thuật này là cơ sở cho một kỹ thuật tích hợp có tên là tích hợp Romberg. Dưới đây là một bản tóm tắt về kỹ thuật Romberg. Hàm R (K, J) đại diện cho phép lặp thứ J của kỹ thuật này bắt đầu từ một quy tắc hình thang với các bước N = 2K-1.

R (A, B, K, 1) = hình thang (A, B, 2K-1)

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Dưới đây là một chương trình Python sử dụng công thức đệ quy này để tính toán các ước tính tích phân.

    subset(n - 1, k)
6

Phải mất một chút nỗ lực để giải nén những gì chương trình này đang làm. Vòng lặp ở phía dưới là tính toán R (A, B, 4 J, J) cho J trong phạm vi từ 2 đến 5. Đối với giá trị J đã cho của J, phương pháp này bắt đầu bằng ước tính quy tắc hình thang bằng cách sử dụng 2K-1 = 24 j - 1 bước. Khi j = 5 Điều này có nghĩa là sử dụng 220 - 1 = 524288 bước.

Chương trình này có một lỗ hổng cuối cùng trong đó và lỗ hổng này nghiêm trọng làm giảm tính toán bắt đầu từ khoảng j = 4. Vấn đề ở đây là một trong những đệ quy quá mức. Như bạn có thể thấy từ mã ở trên, một cuộc gọi điển hình đến hàm Romberg kích hoạt ba cuộc gọi đệ quy bổ sung. Nếu mỗi người lần lượt kích hoạt nhiều cuộc gọi đến chức năng Romberg, cuối cùng bạn có thể thực hiện một số lượng lớn các cuộc gọi này.

Để chống lại vấn đề này, chúng ta có thể sử dụng một chiến lược bộ nhớ đệm đơn giản. Mỗi lần chúng tôi tính toán một giá trị cho

counts = np.zeros((18,18),dtype=int)
2 cho một sự kết hợp cụ thể của K và J, chúng tôi nên ghi chú kết quả đó. Lần tới khi chúng ta kết thúc cần có giá trị đó, chúng ta chỉ có thể tìm kiếm kết quả mà không cần phải tính toán lại bất cứ điều gì.

Phiên bản cuối cùng của chương trình sử dụng chiến lược lưu trữ này. Chúng tôi thiết lập một danh sách hai chiều

counts = np.zeros((18,18),dtype=int)
3 có thể lưu trữ các giá trị cho nhiều kết hợp của K và J. Hàm
counts = np.zeros((18,18),dtype=int)
4 sau đó trao hầu hết các công việc cho chức năng bên trong đệ quy,
counts = np.zeros((18,18),dtype=int)
5.
counts = np.zeros((18,18),dtype=int)
5 thực hiện tính toán được tối ưu hóa bằng cách trước tiên kiểm tra bộ đệm để xem kết quả đã được ghi lại cho sự kết hợp của K và J này. Nếu vậy, nó ngay lập tức dừng lại và trả về giá trị được lưu trong bộ nhớ cache. Nếu không, nó rơi trở lại công thức đệ quy để tính kết quả, và sau đó lưu trữ kết quả trước khi trả lời trả lời.

    subset(n - 1, k)
7

Lưu ý rằng vì chúng ta có một phương pháp hiệu quả hơn bây giờ, chúng ta có thể mở rộng phạm vi của J mà chúng ta tính toán một cách an toàn. Dưới đây là kết quả mà chương trình này trả về.

    subset(n - 1, k)
8

Bài tập lập trình

Trong một trong những bài giảng đầu tiên trong khóa học này, chúng tôi đã thấy một ví dụ về vấn đề nội suy đa thức. Đưa ra một danh sách (x0, y0), (x1, y1), xông, (xn, yn) của các điểm để nội suy, chúng tôi muốn xây dựng một đa thức cấp độ thứ n đi qua các điểm.

Newton đã giải quyết vấn đề này bằng cách tìm kiếm một đa thức có dạng đặc biệt, được gọi là đa thức Newton:

Pn (x) = a0 + a1 (x - x0) + a2 (x - x0) (x - x1) + + an (x - x0) (x - x1) ⋯ (x - xn -1)

Newton đã có thể đưa ra một mối quan hệ đệ quy mà các hệ số của đa thức này hài lòng. Anh ấy đã giới thiệu một ký hiệu đặc biệt

Hướng dẫn n choose k python recursive - n chọn k python đệ quy

Sử dụng ký hiệu này, các hệ số của đa thức Newton là

ak = f [0, k]

Viết một chương trình có thể đọc một danh sách các điểm dữ liệu từ một tệp văn bản và xây dựng một đa thức Newton nội suy các điểm. Mỗi dòng trong tệp văn bản chứa một giá trị x và một giá trị y. Chương trình của bạn nên đọc các điểm dữ liệu đó và lưu trữ chúng trong hai danh sách,

counts = np.zeros((18,18),dtype=int)
7 và
counts = np.zeros((18,18),dtype=int)
8. Chương trình của bạn sau đó sẽ nhắc người dùng nhập giá trị cho X và sau đó tính toán và in giá trị của đa thức Newton tại x.

Chương trình của bạn phải chứa ít nhất một hàm,

counts = np.zeros((18,18),dtype=int)
9, để tính toán các yếu tố f [i, j]. Bạn cũng có thể muốn viết một hàm thứ hai,
def C(n,k):
  counts[n][k] += 1;

     if k == 1:
    return n
  if k == n:
    return 1
  return C(n-1,k-1)+C(n-1,k)
0 để tính toán thuật ngữ thứ k của đa thức nội suy:

f [0, k] (x- x0) (x - x1) ⋯ (x - xk -1)

Để kiểm tra chương trình của bạn, đây là một số dữ liệu kiểm tra.

xy
1.0 0.7651977
1.3 0.6200860
1.6 0.4554022
1.9 0.2818186
2.2 0.1103623

Đa thức của độ bốn đi qua các điểm này có giá trị khoảng 0,5118200 tại x = 1,5.

Làm thế nào để chấm dứt chức năng đệ quy?

Một hàm đệ quy chấm dứt, nếu với mỗi cuộc gọi đệ quy, giải pháp của vấn đề bị thu hẹp và di chuyển về phía một trường hợp cơ sở.Một trường hợp cơ sở là một trường hợp, trong đó vấn đề có thể được giải quyết mà không cần đệ quy thêm.Một đệ quy có thể kết thúc trong một vòng lặp vô hạn, nếu trường hợp cơ sở không được đáp ứng trong các cuộc gọi.if with every recursive call the solution of the problem is downsized and moves towards a base case. A base case is a case, where the problem can be solved without further recursion. A recursion can end up in an infinite loop, if the base case is not met in the calls.

Làm thế nào để kết thúc một chức năng đệ quy Python?

Một cách để thoát ra khỏi một chức năng đệ quy trong Python là ném một ngoại lệ và bắt được điều đó ở cấp cao nhất.Một số người sẽ nói rằng đây không phải là cách đúng đắn để suy nghĩ về đệ quy, nhưng nó hoàn thành công việc.throw an exception and catch that at the top level. Some people will say that this is not the right way to think about recursion, but it gets the job done.

Có thể làm chức năng đệ quy giá trị trả về?

Với đệ quy, chúng tôi đang chờ các giá trị trả về đến từ các bối cảnh thực thi khác.Những bối cảnh khác cao hơn lên ngăn xếp.Khi mục cuối cùng trên ngăn xếp hoàn thành thực thi, bối cảnh đó sẽ tạo ra giá trị trả về.Giá trị trả về này được truyền xuống dưới dạng giá trị trả về từ trường hợp đệ quy sang mục tiếp theo.