Lý do cho câu lệnh return trong lệnh gọi hàm đệ quy


14

Tôi chỉ có một nghi ngờ trong tâm trí của tôi. Chương trình con sau đây (để tìm kiếm một phần tử, ví dụ trong danh sách) có câu lệnh return ở cuối:

list *search_list(list *l, item_type x) {
  if (l == NULL) return(NULL);
  if (l->item == x)
    return(l);
  else
    return( search_list(l->next, x) );
}

Tôi không thể nhận được tầm quan trọng của câu lệnh return ở cuối (tức là return search_list (l-> next, x)). Nó sẽ thực sự hữu ích nếu bất cứ ai có thể giải thích khái niệm này, sử dụng mô hình ngăn xếp.


Nếu thuật ngữ đầu tiên của danh sách không phải là kết quả, hãy tìm kiếm trong phần còn lại của danh sách . Đây là những gì cuối cùng returnlàm.
Giorgio

@ Giorgio, Tại sao chỉ một cuộc gọi chức năng đã được thực hiện, tại sao cần phải trả lại trước đó?
dùng1369975

7
Bởi vì bạn cần trả về giá trị được trả về bởi hàm
Esailija

7
Downvoters: xin vui lòng nhận ra rằng, tùy thuộc vào nền tảng của OP, nó hoàn toàn không rõ ràng return. Trong thực tế, trong các ngôn ngữ chức năng (và một số ngôn ngữ hỗn hợp, như Scala) return là không cần thiết : giá trị của hàm đệ quy là giá trị của biểu thức cuối cùng của nó. Đơn giản chỉ cần viết search_list(l->next, x)mà không returnlàm việc trong Scala! Ý nghĩa của returntuyên bố chỉ rõ ràng đối với các lập trình viên với một nền tảng bắt buộc.
Andres F.

OP: đoạn mã của bạn được viết bằng C?
Andres F.

Câu trả lời:


19

Câu lệnh trả về chuyển một giá trị trở lại cho người gọi ngay lập tức của khung gọi của hàm hiện tại. Trong trường hợp đệ quy, người gọi ngay lập tức này có thể là một lời gọi khác của cùng chức năng đó.

Trong hầu hết các ngôn ngữ, nếu bạn không sử dụng giá trị trả về của hàm bạn đã gọi (đệ quy hoặc không), thì giá trị trả về đó sẽ bị loại bỏ hoặc đó là lỗi có thể chẩn đoán được. Có một số ngôn ngữ trong đó giá trị trả về của lệnh gọi hàm cuối được tự động sử dụng lại làm giá trị trả về của lệnh gọi hàm hiện tại, nhưng chúng không phân biệt giữa các lệnh gọi hàm thông thường và hàm đệ quy.

Giả sử các giá trị trả về không được sử dụng sẽ bị loại bỏ trong âm thầm, nếu bạn đã viết mã như thế này:

list *search_list(list *l, item_type x) {
  if (l == NULL) return(NULL);
  if (l->item == x)
    return(l);
  else
    search_list(l->next, x); // no return!
}

sau đó search_listsẽ chỉ trả về một giá trị được xác định cho danh sách trống (NULL) hoặc nếu mục đầu tiên khớp với giá trị bạn đang tìm kiếm. Ngay khi chức năng đi vào cuộc gọi đệ quy, bạn không biết kết quả sẽ như thế nào, vì kết quả của cuộc gọi đệ quy sẽ bị loại bỏ.

Ngoài ra, bạn hứa sẽ trả về một giá trị từ hàm của bạn, nhưng bạn có một đường dẫn (đệ quy) trong đó bạn không chỉ định giá trị nào sẽ trả về. Tùy thuộc vào ngôn ngữ bạn sử dụng, điều này thường dẫn đến chẩn đoán bắt buộc hoặc trong hành vi không xác định (đó là cách viết tắt của: mọi thứ có thể xảy ra và có thể thay đổi bất cứ lúc nào mà không cần thông báo trước. bài thuyết trình quan trọng nhất của bạn). Có một số tình huống trong đó giá trị trả về bị thiếu có thể hoạt động, nhưng điều đó có thể thay đổi vào lần tiếp theo bạn chạy chương trình (có hoặc không có biên dịch lại).


FWIW, Perl tự động trả về kết quả của biểu thức cuối cùng, mà tôi nghĩ có nghĩa là nó sẽ sử dụng lại giá trị trả về. Nhưng tôi đã không chạm vào nó trong nhiều năm, vì vậy tôi không chắc về điều đó.
Bobson

1

Hai điều; Trả lại toàn bộ danh sách trong trường hợp bạn tìm thấy "x" mà bạn đang tìm kiếm không nhất thiết phải đảm bảo sử dụng đệ quy, nhưng bỏ qua một bên, hãy xem xét các điều sau:

Giả sử bạn đang tìm kiếm một giá trị X = "Tháng 12" và danh sách của bạn là giá trị số của các tháng trong năm, một con trỏ đến tháng tiếp theo và các mục l-> trong danh sách là tên được đánh vần của tháng. (Tháng 1, tháng 2, ..., tháng 12). Bạn cần ba lợi nhuận cho các kết quả có thể. Đầu tiên, return (NULL) là cần thiết nếu danh sách không chứa X bạn đang tìm kiếm. Thứ hai, (return (l)) trả về danh sách, trong trường hợp này, cho bạn biết bạn đã tìm thấy "x" của mình. Cuối cùng là nơi mô hình ngăn xếp phát huy tác dụng. Các lệnh gọi liên tiếp đến hàm sẽ cập nhật các biến cục bộ (cụ thể là l-> item) như thế này:

1: l->item = January
   returns search_list(l->next, x)
2: l->item = February
   returns search_list(l->next, x)
3-11: March, April, May, June, July, August, September, October, November
   all return search_list(l->next, x)
12: l->item = December
  This matches the second if() and returns your list, letting you know you found your search item.

, cảm ơn vì minh họa của bạn, nhưng thực sự không sử dụng lợi nhuận cuối cùng
user1369975

Nếu không có sự trở lại cuối cùng, bạn sẽ không bao giờ vượt qua bước 1.
panhandel
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.