Đối tượng hàm đệ quy JavaScript
Đệ quy là một mẫu lập trình hữu ích trong các tình huống khi một tác vụ có thể được chia thành nhiều tác vụ cùng loại nhưng đơn giản hơn. Hoặc khi một nhiệm vụ có thể được đơn giản hóa thành một hành động dễ dàng cộng với một biến thể đơn giản hơn của cùng một nhiệm vụ. Hoặc, như chúng ta sẽ sớm thấy, để xử lý các cấu trúc dữ liệu nhất định Show Khi một hàm giải quyết một tác vụ, trong quá trình đó, nó có thể gọi nhiều hàm khác. Một phần trường hợp này là khi một hàm gọi chính nó. Đó gọi là đệ quy Hai cách suy nghĩĐối với một cái gì đó đơn giản để bắt đầu – hãy viết một hàm 8 nâng 9 lên lũy thừa tự nhiên của 0. Nói cách khác, nhân 9 với chính nó 0 lần
Có hai cách để thực hiện nó
Xin lưu ý cách biến thể đệ quy khác nhau về cơ bản Khi 8 được gọi, quá trình thực thi sẽ chia thành hai nhánh 0
Chúng ta cũng có thể nói rằng 02 tự gọi đệ quy cho đến khi 5Ví dụ: để tính toán 08, biến thể đệ quy thực hiện các bước sau
Vì vậy, đệ quy rút gọn lời gọi hàm thành một lời gọi đơn giản hơn, và sau đó – thành đơn giản hơn nữa, v.v., cho đến khi kết quả trở nên rõ ràng Đệ quy thường ngắn hơn Một giải pháp đệ quy thường ngắn hơn một giải pháp lặp lại Ở đây chúng ta có thể viết lại tương tự bằng cách sử dụng toán tử điều kiện 63 thay vì 64 để làm cho 8 ngắn gọn hơn và vẫn rất dễ đọc 6Số lần gọi lồng nhau tối đa (bao gồm cả cuộc gọi đầu tiên) được gọi là độ sâu đệ quy. Trong trường hợp của chúng tôi, nó sẽ chính xác là 0Độ sâu đệ quy tối đa bị giới hạn bởi công cụ JavaScript. Chúng ta có thể dựa vào đó là 10000, một số công cụ cho phép nhiều hơn, nhưng 100000 có thể vượt quá giới hạn đối với phần lớn trong số chúng. Có các tối ưu hóa tự động giúp giảm bớt điều này (“tối ưu hóa cuộc gọi đuôi”), nhưng chúng chưa được hỗ trợ ở mọi nơi và chỉ hoạt động trong các trường hợp đơn giản Điều đó hạn chế việc áp dụng đệ quy, nhưng nó vẫn còn rất rộng. Có nhiều tác vụ mà cách suy nghĩ đệ quy cho mã đơn giản hơn, dễ bảo trì hơn Bối cảnh thực thi và ngăn xếpBây giờ hãy kiểm tra xem các cuộc gọi đệ quy hoạt động như thế nào. Đối với điều đó, chúng ta sẽ xem xét các chức năng Thông tin về quá trình thực hiện chức năng đang chạy được lưu trữ trong ngữ cảnh thực thi của nó Bối cảnh thực thi là một cấu trúc dữ liệu nội bộ chứa các chi tiết về việc thực thi một chức năng. vị trí hiện tại của luồng điều khiển, các biến hiện tại, giá trị của 67 (chúng tôi không sử dụng nó ở đây) và một số chi tiết nội bộ khácMột lệnh gọi hàm có chính xác một ngữ cảnh thực thi được liên kết với nó Khi một chức năng thực hiện cuộc gọi lồng nhau, điều sau đây sẽ xảy ra
Hãy xem điều gì xảy ra trong cuộc gọi 68bột (2, 3)Khi bắt đầu cuộc gọi 68, bối cảnh thực thi sẽ lưu trữ các biến. 70, luồng thực thi nằm ở dòng 05 của hàmChúng ta có thể phác họa nó như
Đó là khi chức năng bắt đầu thực thi. Điều kiện 5 là sai, vì vậy luồng tiếp tục vào nhánh thứ hai của 64 7Các biến giống nhau, nhưng dòng thay đổi, vì vậy bối cảnh bây giờ là
Để tính toán 9, chúng ta cần tạo một lớp con của ________ 102 với các đối số mới _______ 376bột (2, 2)Để thực hiện lệnh gọi lồng nhau, JavaScript ghi nhớ ngữ cảnh thực thi hiện tại trong ngăn xếp ngữ cảnh thực thi Ở đây chúng ta gọi hàm tương tự là 02, nhưng nó hoàn toàn không thành vấn đề. Quá trình này là giống nhau cho tất cả các chức năng
Đây là ngăn xếp ngữ cảnh khi chúng tôi tham gia cuộc gọi phụ 76
Bối cảnh thực thi hiện tại mới ở trên cùng (và được in đậm) và các bối cảnh được ghi nhớ trước đó ở bên dưới Khi chúng tôi kết thúc cuộc gọi phụ - thật dễ dàng để tiếp tục bối cảnh trước đó, bởi vì nó giữ cả hai biến và vị trí chính xác của mã nơi nó dừng lại Xin lưu ý Ở đây trong hình, chúng tôi sử dụng từ “dòng”, vì trong ví dụ của chúng tôi, chỉ có một lệnh gọi phụ trong dòng, nhưng nhìn chung một dòng mã có thể chứa nhiều lệnh gọi phụ, chẳng hạn như 79Vì vậy, sẽ chính xác hơn khi nói rằng quá trình thực thi sẽ tiếp tục “ngay sau cuộc gọi phụ” bột (2, 1)Quá trình lặp lại. một cuộc gọi phụ mới được thực hiện tại dòng 80, bây giờ với các đối số 81, 82Một bối cảnh thực thi mới được tạo, bối cảnh trước đó được đẩy lên trên cùng của ngăn xếp
Hiện có 2 ngữ cảnh cũ và 1 ngữ cảnh hiện đang chạy cho 83Lối thoátTrong quá trình thực hiện của 83, không giống như trước đây, điều kiện của 5 là đúng nên nhánh đầu tiên của 64 hoạt động 8Không còn lệnh gọi lồng nhau nào nữa, vì vậy hàm kết thúc, trả về 87Khi chức năng kết thúc, bối cảnh thực thi của nó không còn cần thiết nữa, do đó, nó sẽ bị xóa khỏi bộ nhớ. Cái trước đó được khôi phục khỏi đỉnh ngăn xếp
Việc thực thi của 76 được nối lại. Nó có kết quả của cuộc gọi phụ 83, vì vậy nó cũng có thể kết thúc việc đánh giá của 9, trả về 01Sau đó, bối cảnh trước đó được khôi phục
Khi nó kết thúc, chúng ta có kết quả là 02Độ sâu đệ quy trong trường hợp này là. 3 Như chúng ta có thể thấy từ các hình minh họa ở trên, độ sâu đệ quy bằng với số lượng ngữ cảnh tối đa trong ngăn xếp Lưu ý các yêu cầu bộ nhớ. Bối cảnh chiếm bộ nhớ. Trong trường hợp của chúng tôi, việc tăng lên lũy thừa của 0 thực sự yêu cầu bộ nhớ cho ngữ cảnh 0, cho tất cả các giá trị thấp hơn của 0Thuật toán dựa trên vòng lặp tiết kiệm bộ nhớ hơn 0Lặp đi lặp lại 02 sử dụng một ngữ cảnh duy nhất thay đổi 07 và 08 trong quy trình. Yêu cầu bộ nhớ của nó nhỏ, cố định và không phụ thuộc vào 0Bất kỳ đệ quy nào cũng có thể được viết lại dưới dạng vòng lặp. Biến thể vòng lặp thường có thể được thực hiện hiệu quả hơn …Nhưng đôi khi việc viết lại không hề nhỏ, đặc biệt là khi một hàm sử dụng các cuộc gọi con đệ quy khác nhau tùy thuộc vào điều kiện và hợp nhất các kết quả của chúng hoặc khi việc phân nhánh phức tạp hơn. Và việc tối ưu hóa có thể không cần thiết và hoàn toàn không xứng đáng với những nỗ lực Đệ quy có thể cho đoạn mã ngắn hơn, dễ hiểu và dễ hỗ trợ hơn. Tối ưu hóa không bắt buộc ở mọi nơi, chủ yếu là chúng tôi cần một mã tốt, đó là lý do tại sao nó được sử dụng duyệt đệ quyMột ứng dụng tuyệt vời khác của đệ quy là truyền tải đệ quy Hãy tưởng tượng, chúng ta có một công ty. Cấu trúc nhân viên có thể được trình bày như một đối tượng 0Nói cách khác, một công ty có các bộ phận
Bây giờ, giả sử chúng ta muốn một hàm lấy tổng của tất cả các mức lương. Làm thế nào chúng ta có thể làm điều đó? Một cách tiếp cận lặp đi lặp lại là không dễ dàng, bởi vì cấu trúc không đơn giản. Ý tưởng đầu tiên có thể là tạo một vòng lặp 3 trên 08 với vòng lặp con lồng nhau trên các bộ phận cấp 1. Nhưng sau đó, chúng ta cần nhiều vòng lặp con lồng nhau hơn để lặp lại nhân viên ở các bộ phận cấp 2 như 02… Và sau đó, một vòng lặp con khác bên trong các vòng lặp dành cho các bộ phận cấp 3 có thể xuất hiện trong tương lai? Hãy thử đệ quy Như chúng ta có thể thấy, khi hàm của chúng ta tính tổng một bộ phận, có hai trường hợp có thể xảy ra
Trường hợp đầu tiên là cơ sở của đệ quy, trường hợp tầm thường, khi chúng ta nhận được một mảng Trường hợp thứ 2 khi chúng ta lấy một đối tượng là bước đệ quy. Một nhiệm vụ phức tạp được chia thành các nhiệm vụ con cho các bộ phận nhỏ hơn. Họ có thể lần lượt chia tách một lần nữa, nhưng sớm hay muộn sự chia tách sẽ kết thúc ở (1) Thuật toán có lẽ còn dễ đọc hơn từ mã 1Mã ngắn và dễ hiểu (hy vọng?). Đó là sức mạnh của đệ quy. Nó cũng hoạt động đối với bất kỳ cấp độ nào của việc lồng nhau Đây là sơ đồ của các cuộc gọi Chúng ta có thể dễ dàng nhận thấy nguyên tắc. đối với một đối tượng 12 các cuộc gọi con được thực hiện, trong khi mảng 13 là “các lá” của cây đệ quy, chúng cho kết quả ngay lập tứcLưu ý rằng mã sử dụng các tính năng thông minh mà chúng tôi đã đề cập trước đây
cấu trúc đệ quyCấu trúc dữ liệu đệ quy (được xác định đệ quy) là cấu trúc sao chép chính nó thành từng phần Chúng ta vừa thấy nó trong ví dụ về cấu trúc công ty ở trên Một bộ phận của công ty là
Đối với các nhà phát triển web, có nhiều ví dụ nổi tiếng hơn. Tài liệu HTML và XML Trong tài liệu HTML, một thẻ HTML có thể chứa danh sách các
Đó là một lần nữa một định nghĩa đệ quy Để hiểu rõ hơn, chúng ta sẽ đề cập đến một cấu trúc đệ quy khác có tên là “Danh sách được liên kết” có thể là một giải pháp thay thế tốt hơn cho mảng trong một số trường hợp danh sách liên kếtHãy tưởng tượng, chúng tôi muốn lưu trữ một danh sách các đối tượng được sắp xếp theo thứ tự Sự lựa chọn tự nhiên sẽ là một mảng 0…Nhưng có một vấn đề với mảng. Thao tác “xóa phần tử” và “chèn phần tử” rất tốn kém. Chẳng hạn, hoạt động của 17 phải đánh số lại tất cả các phần tử để nhường chỗ cho một 18 mới và nếu mảng lớn thì sẽ mất thời gian. Tương tự với 19Các sửa đổi cấu trúc duy nhất không yêu cầu đánh số lại hàng loạt là những sửa đổi hoạt động với phần cuối của mảng. 00. Vì vậy, một mảng có thể khá chậm đối với các hàng đợi lớn, khi chúng ta phải làm việc từ đầuNgoài ra, nếu thực sự cần chèn/xóa nhanh, chúng ta có thể chọn một cấu trúc dữ liệu khác gọi là danh sách liên kết Phần tử danh sách liên kết được định nghĩa đệ quy là một đối tượng có
Ví dụ 1Biểu diễn đồ họa của danh sách Một mã thay thế để tạo 2Ở đây chúng ta có thể thấy rõ hơn rằng có nhiều đối tượng, mỗi đối tượng có 01 và 02 trỏ đến hàng xóm. Biến 06 là đối tượng đầu tiên trong chuỗi, vì vậy theo các con trỏ 02 từ nó, chúng ta có thể tiếp cận bất kỳ phần tử nàoDanh sách có thể dễ dàng chia thành nhiều phần và sau đó nối lại 3Tham gia 4Và chắc chắn chúng ta có thể chèn hoặc xóa các mục ở bất kỳ đâu Chẳng hạn, để thêm vào trước một giá trị mới, chúng ta cần cập nhật phần đầu của danh sách 5Để xóa một giá trị ở giữa, hãy thay đổi 02 của giá trị trước đó 6Chúng tôi đã làm cho 09 nhảy qua 05 thành giá trị 87. Giá trị 05 hiện đã bị loại khỏi chuỗi. Nếu nó không được lưu trữ ở bất kỳ nơi nào khác, nó sẽ tự động bị xóa khỏi bộ nhớKhông giống như mảng, không cần đánh số lại hàng loạt, chúng ta có thể dễ dàng sắp xếp lại các phần tử Đương nhiên, danh sách không phải lúc nào cũng tốt hơn mảng. Nếu không, mọi người sẽ chỉ sử dụng danh sách Hạn chế chính là chúng ta không thể dễ dàng truy cập một phần tử theo số của nó. Trong một mảng dễ dàng. 13 là một tài liệu tham khảo trực tiếp. Nhưng trong danh sách, chúng ta cần bắt đầu từ mục đầu tiên và đi 02 10 lần để lấy phần tử thứ N…Nhưng không phải lúc nào chúng ta cũng cần những hoạt động như vậy. Chẳng hạn, khi chúng ta cần một hàng đợi hoặc thậm chí là một deque – cấu trúc được sắp xếp phải cho phép thêm/xóa các phần tử ở cả hai đầu rất nhanh, nhưng không cần truy cập vào phần giữa của nó Danh sách có thể được nâng cao
Bản tóm tắtĐiều kiện
Bất kỳ hàm đệ quy nào cũng có thể được viết lại thành một hàm lặp. Và điều đó đôi khi được yêu cầu để tối ưu hóa nội dung. Nhưng đối với nhiều tác vụ, một giải pháp đệ quy đủ nhanh và dễ dàng hơn để viết và hỗ trợ Bốn loại đệ quy là gì?🔹 Có 4 loại đệ quy. . đệ quy trực tiếp đệ quy gián tiếp đệ quy đuôi Đệ quy đầu / không đuôi 3 phần của hàm đệ quy là gì?Trường hợp đệ quy có ba thành phần. chia vấn đề thành một hoặc nhiều phần đơn giản hơn hoặc nhỏ hơn của vấn đề, gọi hàm (đệ quy) trên từng phần và. kết hợp lời giải của các phần thành lời giải cho bài toán .
Chức năng đệ quy trong JavaScript với ví dụ là gì?Một hàm là đệ quy nếu nó gọi chính nó và đạt đến điều kiện dừng . Trong ví dụ sau, testcount() là một hàm gọi chính nó. Chúng tôi sử dụng biến x làm dữ liệu, tăng dần theo 1 ( x + 1 ) mỗi lần chúng tôi lặp lại. Đệ quy kết thúc khi biến x bằng 11 ( x == 11 ).
JavaScript có hỗ trợ chức năng đệ quy không?Tuy nhiên, trong khi kiểu mã hóa chức năng của JavaScript hỗ trợ các hàm đệ quy , chúng ta cần lưu ý rằng hầu hết các trình biên dịch JavaScript hiện không được tối ưu hóa để hỗ trợ . Đệ quy được áp dụng tốt nhất khi bạn cần gọi lặp lại cùng một chức năng với các tham số khác nhau từ trong một vòng lặp. |