Chuyển đến nội dung chính

Đệ quy

 



Đệ quy

Hãy nhìn vào tấm hình sau


Phía bên trong bức ảnh chứa một phiên bản của chính nó, và bên trong phiên bản đó, tiếp tục chứa một phiên bản nữa của chính nó. Điều này được lặp đi lặp lại, cho chúng ta một khái niệm trực quan về đệ quy.

Ví dụ toán học về đệ quy

Cho hàm f(n) được định nghĩa như sau:
f(n)=1+2+3+...+n
Đồng nghĩa với: 
f(n1)=1+2+3+...+n1
f(n)=n+f(n1)
Tất nhiên ta có thể tính biểu thức trên bằng công thức toán học f(n)=n×(n+1)2, nhưng tạm thời ta không xét nó ở đây.

Qua chứng minh trên ta rút ra được 1 điều: để tính f(n), ta có thể tính từ f(n1). Vậy làm sao để tính f(n1)? Tương tự, ta có thể tính nó từ f(n2), và rồi ta sẽ tính f(n2) từ f(n3), ...

Bên trong bài toán  trên chứa một phiên bản nhỏ hơn của chính nó, trong tin học, khái niệm này gọi là đệ quy.

Tuy nhiên, nếu chỉ tìm đáp án từ biểu thức f(n)=f(n1)+n, các biểu thức trên có thể lặp lại vô hạn, vì thế chúng ta phải thêm điều kiện sau vào bài toán:

Giá trị khởi đầu của biểu thức là f(0)=0, với n<0, bài toán không có lời giải.


Tới lúc này, vòng lặp vô hạn đã có điểm dừng, nghĩa là với 1 số nguyên dương cho trước, dù bạn có lặp đi lặp lại bao nhiêu lần thì một lúc nào đó các bước tính cũng dừng lại mà thôi.

Đây chính là định nghĩa về đệ quy, hay nói tổng quát:

Đệ quy là một hành động được định nghĩa bằng chính nó.


...Hoặc đó là cách mọi người vẫn hay viết. Mình sẽ viết lại nó như sau:

Đệ quy là một chuỗi các hành động y hệt nhau được lặp đi lặp lại và có điểm dừng. Nếu không có điểm dừng, bài toán trở thành một vòng lặp vô tận.

Code đệ quy cho bài toán trên

Đoạn code sau minh họa cho một vòng lặp vô tận:

#include <bits/stdc++.h>
using namespace std;
int f(int n)
{
	return n + f(n - 1);
}
int main()
{
	int n;
	cin >> n;
	int answer = f(n);
        cout << answer << '\n';
}
Vòng lặp trên sẽ chạy tới vô tận. Ta cần thêm điểm dừng cho nó.

Code đệ quy đầy đủ:

#include <bits/stdc++.h>
using namespace std;
int f(int n)
{
	if (n == 0) return 0;
	return n + f(n - 1);
}
int main()
{
	int n;
	cin >> n;
	int answer = f(n);
        cout << answer << '\n';
}
Ưu điểm: 
  • Là thuật toán cơ bản nhất trong các loại thuật toán, ai cũng dùng được.
  • Gọn, dễ nhìn, dễ hiểu.
  • Là phần lõi cơ bản của nhiều thuật toán khác.

Nhược điểm: tốn bộ nhớ, khó debug, chạy lâu vl. Học thì học thế thôi chứ nếu dùng được thuật toán khác thì bạn nên dùng nó. Bài toán trên chạy đến 10,100,1000,10000 còn được chứ chạy tới 109 thì đời nào mới xong, cứ sử dụng công thức f(n)=n×(n+1)2 là tính được ngay lập tức, đỡ mất công chờ đợi.

Một vài ví dụ về đệ quy

Tính số Fibonacci thứ n bằng đệ quy:

#include <bits/stdc++.h>
using namespace std;
int fibonacci(int n)
{
	if (n == 1) return 1;
	if (n == 2) return 1;
	return fibonacci(n - 1) + fibonacci(n - 2);
}
int main()
{
	int n;
	cin >> n;
	int answer = fibonacci(n);
        cout << answer << '\n';
}

Tìm số ước của một số bằng đệ quy:

#include <bits/stdc++.h>
using namespace std;
int divisors(int n, int i)
{
	if (i == 1) return 1;
	if (n % i == 0) return 1 + divisors(n, i - 1);
	else return divisors(n, i - 1);
}
int main()
{
	int n;
	cin >> n;
	int answer = divisors(n, n);
	cout << answer << '\n';
}
Tổng kết: đệ quy là một trong những thuật toán cơ bản nhất của lập trình nói chung. Nó rất dễ đọc, tuy nhiên hạn chế của nó cũng rất nhiều, khi không cần thiết bạn nên tránh đệ quy và thay vào đó là sử dụng những thuật toán khác.

Nhận xét

Bài đăng phổ biến từ blog này

Thuật toán lùa bò vào chuồng(Đếm phân phối)

Làm cách nào từ một coder chân chính  trở thành một người chăn bò 😃😃 Chắc hẳn trong lập trình chúng ta không khó để gặp gỡ các bài toán đếm.Tuy nhiên việc thực hiện các bài toán đếm thường được diễn ra trên dữ liệu lớn, nếu các bạn không biết cách tổ chức dữ liệu và thực hiện  thuật toán hiệu quả thường sẽ dẫn đến kết quả sai lầm. Vì vậy trong bài viết hôm nay chúng ta sẽ cùng tìm hiểu qua một trong những cách tiếp cận bài toán đếm đó là thuật toán lùa bò vào chuồng hay còn gọi là đếm phân phối. 1. Đặt vấn đề: Ban đầu bạn có một mảng số gồm N phần tử ( N <10^5) mỗi giá trị trong mảng đều bé hơn hoặc bằng 100. Bạn được giao nhiệm vụ đếm xem trong mảng số đó có bao nhiêu phần tử riêng biệt.      VD: N=10      arr []  =   1 6 9 1  7 9 9 9 2 3 => 6 phần tử riêng biệt. 2.Thuật toán lùa bò vào chuồng:   Tư tưởng của thuật toán: giả sử bạn là một người nông dân sở hữu một nông trại bò và bạn cần phải đếm chính xác số lượng những chú bò trong trang trại để dễ quản lý. Vi những chú bò

Vét cạn hay duyệt trâu (Brute Force)

Thuật toán vét cạn:  Thuật toán vét cạn hay duyệt trâu (Brute Force) được  hiểu đúng như tên gọi của nó, chúng ta sẽ dùng những phương pháp đơn giản để duyệt qua toàn bộ các trường hợp của bài toán và bằng sức mạnh của máy  tính để tìm ra được đáp án chính xác thay vì dùng các thuật toán hiệu quả hơn .  VD: bài toán sống sót qua cuối tháng khi hết tiền tiêu:  Giải pháp của bài này là chúng ta sẽ dùng  vòng for vét can toàn bộ lương thực quanh nhà như mì tôm, hủ gạo... Để có thể tìm ra bữa ăn sống sót qua ngày và vì phải chạy đi tìm kiếm khắp nơi nên cách làm này sẽ có hơi tốn sức (dẫn đến chết đói). Có nhiều cách duyệt khác nhau như: Dùng nhiều vòng for If, else Đệ Quy, quay lui (Backtracking) Bitmask .... Giải thuật này thường rất hiệu quả với những bài toán có dữ liệu đầu vào nhỏ nhưng đối với các dữ liệu lớn hơn hay các bài toán phức tạp hơn sẽ tốn rất nhiều thời gian và đòi hỏi một lực code trâu bò để có thể vét cạn hết toàn bộ.

(MESEC) MỘT SỐ TRANG WEB LUYỆN TẬP OSINT CHO NGƯỜI MỚI BẮT ĐẦU

OSINT là một trong các mảng của hình thức Jeopardy CTF và đang dần tiếp cận được với nhiều người hơn bởi những lợi ích mà nó đem lại. Vậy OSINT là gì? OSINT (Open Source Intelligency) là thuật ngữ dùng để chỉ bất kỳ thông tin nào có thể được thu thập hợp pháp từ các nguồn công khai, miễn phí về một cá nhân hoặc tổ chức. Trên thực tế, bất cứ hoạt động nào thông qua Internet đều phải để lại các thông tin có thể thu thập được, từ thông tin về tên miền, máy chủ web, máy chủ e-mail đến các file tài liệu, bài thuyết trình, video, hình ảnh… và cả những bài post, comment, hashtag trên các mạng xã hội có liên quan đến từ khóa nào đó. OSINT cũng là công cụ mà giới tội phạm mạng dùng để nghiên cứu thông tin đối tượng mà họ nhắm tới trước khi tấn công. Tuy nhiên, ở chiều ngược lại thì doanh nghiệp cũng có thể dùng để điều tra xác minh đối tác giao dịch qua mạng để phát hiện những dấu hiện khả nghi. Trong bài viết ngày hôm nay, MeSec sẽ đề xuất một vài trang web sẽ giúp cho bạn học tập và rèn luyện