«تابع بازگشتی» به اینجا تغییرمسیر دارد. برای مفهومی در ریاضیات، رابطه بازگشتی را ببینید.

| پارادایم‌های برنامه‌نویسی |
| --- |
| * زبان عملی
* عامل گرا
* آرایه‌گرا
* مبتنی بر اتوماتا
* رایانش همزمان
	+ نسبیت گرایی
* داده‌محور
* اعلانی (تضاد: دستوری)
	+ تابعی
		- منطق تابعی
		- تابعی خالص
	+ منطقی
		- منطقی قیاسی
		- مجموعه جواب
		- منطق همزمان
		- منطق تابعی
		- منطق استقرایی
	+ محدودیتی
		- منطق محدودیتی
			* منطق محدودیت همزمان
	+ جریان داده
		- مبتنی بر جریان
		- واکنشی
	+ هستی‌شناسی
* تشخیص پذیر
* پویا/اجرانامه‌نویسی
* رویدادمحور
* سطح تابع (تضاد: سطح مقدار)
	+ سبک بدون آرگومان
		- الحاقی
* همگانی
* دستوری (تضاد: اعلانی)
	+ رویه‌ای
	+ شیءگرا (OOP)
		- کد چندریخت
* تصمیم گرا
* زبان گرا
	+ خاص دامنه
* ادیبانه
* برنامه‌نویسی زبان طبیعی
* فرا برنامه‌نویسی
	+ خودکار
		- استقرایی
	+ پژواکی
		- صفت گرا
	+ مبتنی بر کلان‌دستور (ماکرو)
	+ خودآرا
* غیر ساخت‌یافته (تضاد: ساخت‌یافته)
	+ آرایه‌ای (برداری)
* غیرقطعی
* رایانش موازی
	+ فرایند گرا
* احتمالی
* کوانتمی
* نظریه مجموعه‌ها
* مبتنی بر پشته
* ساخت‌یافته (تضاد: غیر ساخت‌یافته)
	+ بلوک ساختاری
		- ساخت‌یافته همزمان
	+ شیءگرا (OOP)
		- مبتنی بر بازیگر
		- مبتنی بر کلاس
		- همزمان
		- بر پایه پیش‌نمونه
		- با تفکیک دغدغه‌ها:
			* جنبه‌گرا
			* نقش گرا
			* موضوع گرا
	+ بازگشتی
* نمادین
* سطح مقدار (تضاد: سطح تابع)
 |
| * ن
* ب
* و
 |

**بازگشت** (به انگلیسی: Recursion) در علوم رایانه، روشی برای حل یک مسئله است که در آن راه‌حل مسئله به راه‌حل هایی در نمونه های کوچکتر از همان مساله وابسته می باشد.

به نظر می‌رسد ترجمه «بازگشت» بیشتر مناسب کلمه انگلیسی Return باشد تا کلمه Recursion ؛ به همین دلیل بعضی از اساتید عبارت «توابع خوداتکاء» را برای نامیدن این‌گونه توابع به کار می‌برند.
همچنین از آنجایی که ریشهٔ این کلمه در زبان انگلیسی فعل Recur به معنای "اتفاق افتادن مجدد" می‌باشد ترجمه‌های مناسب دیگر می توانند "توابع بازوقوع" و "توابع بازفراخوانی شونده" باشند، که همگی قطعا بهتر از ترجمهٔ مشهور و ضعیف آن(توابع بازگشتی) می‌باشند.
به هر حال، نگرش خوداتکاء یا بازگشتی در علم کامپیوتر یک روش فکر کردن برای حل مسائل است. در واقع خوداتکایی یا بازگشت یکی از ایده‌های اصلی علم کامپیوتر است. حل یک مسئله به روش خوداتکاء/بازگشتی بدین معناست که راه حل بستگی به مدل کوچکتری از صورت مسئله داشته باشد.

> "قدرت بازگشت قطعاً در این نهفته‌است که دسته‌ای نامتناهی از اشیا را بوسیلهٔ یک عبارت متناهی تعریف می‌کند. به معنای دیگر یک عدد نامتناهی در محاسبات می‌تواند بوسیلهٔ یک برنامهٔ متناهی بازگشتی تعریف شود حتی اگر این برنامه هیچ تکرار واضحی نداشته باشد ".
> 
> 
> 

اکثر زبان‌های برنامه نویسی سطح بالا عمل بازگشت را به این صورت تعریف می‌کنند که یک تابع خودش را فراخوانی کند. زبان‌های دستوری ساختارهای حلقه‌ای مثل `while` یا `for` را برای انجام کارهای تکراری به کار می‌گیرند. بعضی از زبان‌های تابعی هیچ ساختار حلقه‌ای تعریف نمی‌کنند اما بر خود بازگشت تکیه دارند که کد را به‌طور مکرر فراخوانی کند. نظریهٔ رایانش‌پذیری ثابت کرده‌است که این زبان‌های فقط بازگشتی از نظر ریاضی برابر زبان‌های دستوری هستند، یعنی اینکه مسائل را بدون نیاز به `while` و `for` حل می‌کنند.

الگوریتم‌های بازگشتی
--------------------

در ریاضیات کاربردی و به خصوص کامپیوتر، مسائل فراوانی وجود دارد که حل آن‌ها را به سادگی می‌توان به صورت یک الگوریتم بازگشتی نشان داد. یک الگوریتم بازگشتی مانند یک تابع یا یک دنباله بازگشتی تعریف می‌شود فرمان‌های الگوریتم به‌طور مکرر و با پارامترهای مختلف اجرا می‌شوند تا به فرمان بنیادی الگوریتم برسیم. آنگاه تمام مقادیری را که محاسبهٔ آن‌ها انجام نشده‌است را به صورت بازگشتی محاسبه می‌نماییم تا فرمان مورد نظر اجرا شود.
یک روش متداول برای آسان‌سازی مسائل این است که آن‌ها را به زیر مسائلی از همان نوع تقسیم بندی کنیم. این روش با نام گویشی کردن شناخته می‌شود. به عنوان یک تکنیک برنامه نویسی کامپیوتر، به این روش تقسیم و غلبه (به انگلیسی: Divide and Conquer) اطلاق می‌شود. و کلید راه حل تعداد زیادی از مسائل کامپیوتری مهم است و یک بخش اساسی می‌باشد.
تمام زبان‌های برنامه‌نویسی که امروز مورد استفاده‌اند تعریفی مستقیم از توابع بازگشتی در خود دارند. وقتی چنین تابعی فراخوانی می‌شود، کامپیوتر(برای اکثر زبان‌هایی که پشته دارند) یا خود کد زبان instanceهای مختلف تابع را (با فراخوانی پشته، هر چند روش‌های دیگر هم مورد استفاده قرار می‌گیرند). برعکس آن همهٔ توابع بازگشتی می‌توانند به کمک پشته به یک تابع غیر بازگشتی تبدیل شوند. اکثر توابع و روش‌هایی که می‌توانند بوسیلهٔ کامپیوتر ارزشیابی شوند بدون استفاده از غیر بازگشتی کردن قابل بازگشتی شدن هستند.

برنامه‌نویسی بازگشتی
--------------------

بعضاً الگوریتم‌های بازگشتی را می‌توان به کمک زبان‌های برنامه‌نویسی پیاده‌سازی کرد که به این برنامه‌ها برنامه‌های بازگشتی اطلاق می‌شود. مانند الگوریتم‌های مرتب سازی، فاکتوریل، یافتن ب.م.م، و ..... در زیر به چند نمونه از برنامه‌های بازگشتی معروف اشاره می‌کنیم:

### نمونه‌های برنامه‌های بازگشتی

#### فاکتوریل

یک مثال متداول برای برنامه‌های بازگشتی، محاسبهٔ فاکتوریل برای اعداد طبیعی است:

{\displaystyle \operatorname {fact} (n)={\begin{cases}1&{\mbox{if }}n=0\\n\cdot \operatorname {fact} (n-1)&{\mbox{if }}n>0\\\end{cases}}}

| شبه کد (بازگشتی): |
| --- |
| 
```
**function** factorial is:
**input**: integer *n* such that *n*>= 0
**output**: [*n* × (*n*-1) × (*n*-2) × … × 1]
```

```
    1. if *n* is 0, **return** 1
    2. otherwise, **return** [ *n* × factorial(*n*-1) ]
```

```
**end** factorial
```
 |

این تابع می‌تواند به شکل یک رابطه‌ی بازگشتی نیز نوشته شود:

{\displaystyle b\_{n}=nb\_{n-1}}

{\displaystyle b\_{0}=1}

| محاسبهٔ رابطهٔ بازگشتی برای n = 4: |
| --- |
| 
```
b4           = 4 * b3
             = 4 * 3 * b2
             = 4 * 3 * 2 * b1
             = 4 * 3 * 2 * 1 * b0
             = 4 * 3 * 2 * 1 * 1
             = 4 * 3 * 2 * 1
             = 4 * 3 * 2
             = 4 * 6
             = 24
```
 |

این الگوریتم هم مانند الگوریتم‌های دیگر به صورت غیر بازگشتی هم نوشته می‌شود.

| شبه کد (غیر بازگشتی): |
| --- |
| 
```
**function** factorial is:
**input**: integer *n* such that *n*>= 0
**output**: [*n* × (*n*-1) × (*n*-2) × … × 1]
```

```
    1. **create** new variable called *running\_total* with a value of 1
```

```
    2. **begin** loop
          1. if *n* is 0, **exit** loop
          2. **set** *running\_total* to (*running\_total* × *n*)
          3. **decrement** *n*
          4. **repeat** loop
```

```
    3. **return** *running\_total*
```

```
**end** factorial
```
 |

#### فیبوناچی

یکی دیگر از الگوریتم‌های بازگشتی متداول الگوریتم فیبوناچی است.
 *تابع بازگشتی فیبوناچی:* 

{\displaystyle fib(n)={\begin{cases}1&{\mbox{if }}n=1\\1&{\mbox{if }}n=2\\fib(n-1)+fib(n-2)&{\mbox{if }}n>2\\\end{cases}}}


|  شبه کد  |
| --- |
| 
```
**function** fib is:
**input**: integer n such that n > 0
```

```
    1. if n is 1, **return** 1
    2. if n is 2, **return** 1
    3. otherwise, **return** [ fib(n-1) + fib(n-2) ]
```

```
**end** fib
```
 |

و می‌توان این تابع را با رابطهٔ بازگشتی زیر نشان داد:

{\displaystyle b\_{n}=b\_{n-1}+b\_{n-2}}

{\displaystyle b\_{2}=b\_{1}=1}


| محاسبهٔ رابطهٔ بازگشتی برای n = 5: |
| --- |
| 
```
  b5            = b4 + b3
                = b3 + b2 + b2 + b1
                = b2 + b1 + 1 + 1 + 1
                = 1 + 1 + 3
                = 5
```
 |

#### ب.م.م

الگوریتم اقلیدس که بزرگترین مقسوم‌علیه مشترک (ب.م.م) دو عدد را محاسبه می‌کند، می‌تواند به صورت بازگشتی نوشته شود. تابع به شکل زیر تعریف می‌شود:

{\displaystyle \gcd(x,y)={\begin{cases}x&{\mbox{if }}y=0\\\gcd(y,\operatorname {remainder} (x,y))&{\mbox{if }}x\geq y{\mbox{ and }}y>0\\\end{cases}}}  

| شبه کد (بازگشتی): |
| --- |
| 
```
**function** gcd is:
**input**: integer *x*, integer *y* such that *x*>= *y* and *y*> 0
```

```
    1. if *y* is 0, **return** *x*
    2. otherwise, **return** [ gcd( *y*, (remainder of *x*/*y*) ) ]
```

```
**end** gcd
```
 |

رابطهٔ بازگشتی ب.م.م به شکل زیر تعریف می‌شود، در این رابطه منظور از {\displaystyle x\%y}، مقدار باقیمانده‌ی حاصل از {\displaystyle x/y} است:

{\displaystyle \gcd(x,y)=\gcd(y,x\%y)}
{\displaystyle \gcd(x,0)=x}

| محاسبهٔ رابطهٔ بازگشتی برای x = 27 و y = 9: |
| --- |
| 
```
gcd(27, 9)   = gcd(9, 27 % 9)
             = gcd(9, 0)
             = 9
```
 |
| محاسبهٔ رابطهٔ بازگشتی برای x = 259 و y = 111: |
| 
```
gcd(259, 111)   = gcd(111, 259 % 111)
                = gcd(111, 37)
                = gcd(37, 0)
                = 37
```
 |

| شبه کد (غیر بازگشتی): |
| --- |
| 
```
**function** gcd is:
**input**: integer *x*, integer *y* such that *x*>= *y* and *y*> 0
```

```
    1. **create** new variable called *remainder*
```

```
    2. **begin** loop
          1. if *y* is zero, **exit** loop
          2. **set** *remainder* to the remainder of x/y
          3. **set** x to y
          4. **set** y to *remainder*
          5. **repeat** loop
```

```
    3. **return** *x*
```

```
**end** gcd
```
 |

#### برج‌های هانوی(برج برهما)

در محوطه معبدی در آسیای دور سه میله الماسی قرار داشت که یکی از آن‌ها حاوی تعدادی قرص طلایی بود. کاهنان معبد در تلاش بودند تا قرص‌های طلائی را از آن میله به یکی دیگر از میله‌ها تحت شرایطی انتقال دهند، و باور داشتند که با تمام شدن انتقال قرص‌ها عمر جهان نیز به پایان خواهد رسید! میله اولیه ۶۴ قرص داشت، که بر روی هم به‌طور نزولی بر اساس اندازه‌شان چیده شده‌بودند.
همانند شکل سه میله داریم. یکی از میله‌ها میله مبدأ (A)، دیگری میله کمکی (B) و دیگری میله مقصد (C) است. هدف انتقال تمام دیسک‌ها از میله مبدأ به میله مقصد با رعایت شرایط زیر است:

در هر زمان فقط یک دیسک را می‌توان جابجا نمود. نباید در هیچ زمانی دیسکی بر روی دیسک با اندازه کوچکتر قرار بگیرد.
هدف ما ارائه الگوریتمی است که کمترین توالی حرکت‌ها را برای انتقال دیسک‌ها به ما بدهد. مثلاً اگر n=۲ باشد، توالی حرکت به صورت زیر است:

حل مسئله برج هانوی
* دیسک ۱ را به میله B منتقل می‌کنیم.
* دیسک ۲ را به میله C منتقل می‌کنیم.
* دیسک ۱ را به میله C منتقل می‌کنیم.

توجه داشته باشید که بر اساس قانون اول نمی‌توان به غیر از بالاترین دیسک هر میله، به دیسک دیگری از آن دسترسی پیدا کرد.

حال سؤال این است که آیا این مسئله به کمک تکنیک بازگشت قابل حل است؟ اصولاً چه مسائلی را می‌توان بازگشتی حل نمود؟

برای اینکه مسئله‌ای بتواند با روش بازگشتی حل شود باید یک ویژگی اساسی داشته باشد. مسئله اصلی (مسئله‌ای که به ما داده می‌شود) قابل خرد شدن به زیر مسئله‌هایی از همان نوع مسئله اصلی باشد، به شرطی که اندازه زیر مسئله‌های ایجاد شده کمتر باشد. آنگاه می‌توان امیدوار بود که آن را به‌طور بازگشتی حل کرد! این ویژگی در مورد مسئله برج هانوی صدق می‌کند. ایده اصلی این است که توجهمان را به جای حرکت بالاترین دیسک، روی پایین‌ترین دیسک میله متمرکز کرده، و مراحل زیر را طی می‌کنیم:

n - ۱ دیسک بالایی را با شرایط ذکر شده و به کمک میله C به میله B منتقل می‌کنیم. بزرگترین دیسک را از میله مبدأ به میله مقصد حرکت می‌دهیم. n - ۱ دیسک را که هم‌اکنون در میله B هستند با شرایط داده شده به میله مقصد انتقال می‌دهیم. می‌بینیم که توانستیم عملیات جابجا کردن n دیسک را به دو عملیات مشابه ولی با اندازه کمتر و یک عملیات ساده تقسیم کنیم. واضح است که جابجا کردن n - ۱ قرص راحتتر از جابجا نمودن n قرص است.
*تابع بازگشتی برج‌های هانوی*:

{\displaystyle \operatorname {hanoi} (n)={\begin{cases}1&{\mbox{if }}n=1\\2\cdot \operatorname {hanoi} (n-1)+1&{\mbox{if }}n>1\\\end{cases}}}

*رابطهٔ بازگشتی برای هانوی*:

{\displaystyle h\_{n}=2h\_{n-1}+1}
{\displaystyle h\_{1}=1}

| محاسبهٔ رابطهٔ بازگشتی برای n = 4: |
| --- |
| 
```
hanoi(4)     = 2*hanoi(3) + 1
             = 2*(2*hanoi(2) + 1) + 1
             = 2*(2*(2*hanoi(1) + 1) + 1) + 1
             = 2*(2*(2*1 + 1) + 1) + 1
             = 2*(2*(3) + 1) + 1
             = 2*(7) + 1
             = 15
```
 |

| شبه کد (بازگشتی): |
| --- |
| 
```
**function** hanoi is:
**input**: integer *n*, such that *n*>= *1*
```

```
    1. **if** n is 1 **then return** 1
```

```
    2. **return** [2 * [**call** hanoi(n-1)] + 1]
```

```
**end** hanoi
```
 |

هر چند برای تمام توابع بازگشتی راه حل روشنی نمی‌توان یافت اما برج‌های هانوی از این قاعده مستثنی است:

راه حل مستقیم برای مسئلهٔ برج‌های هانوی:

|
|  |
| 
```
h1 = 1   = 21 - 1
h2 = 3   = 22 - 1
h3 = 7   = 23 - 1
h4 = 15  = 24 - 1
h5 = 31  = 25 - 1
h6 = 63  = 26 - 1
h7 = 127 = 27 - 1
```

```
In general:
hn = 2n - 1, for all n>= 1
```
 |

### ساختمان داده‌های بازگشتی(ساخت یافته)

در اصطلاح کامپیوتری، ساختمان داده به روشهایی از ذخیره اطلاعات گفته می‌شود که برای استفاده بهینه از اطلاعات ذخیره شده اتخاذ می‌شود. غالباً انتخاب یک ساختمان داده موجب ایجاد الگوریتم‌های متناسب با آن خواهد شد که این دو در کنار هم موجب افزایش سرعت انجام یک وظیفه یا کاهش مصرف حافظه برای پردازش داده می‌شود؛ سنگ بنای ساختمان‌های داده انواع داده و اشاره گرهای گوناگون است. که با توجه به چگونگی تعریف کاربرد آن‌ها در هر زبان برنامه نویسی پیاده‌سازی آن‌ها متفاوت خواهد بود.

#### لیست پیوندی

در زیر می‌توانید تعریف ساده‌ای از گرهٔ فهرستهای پیوندی را مشاهده کنید. عنصر بعدی در ساختار گره اشاره گری است به یک ساختار گره.

```
struct node
{
 int n; // some data
 struct node \*next; // pointer to another struct node
};

// LIST is simply a synonym for struct node \* (aka syntactic sugar).
typedef struct node \*LIST;

```

رویه‌هایی که لیست ساختمان داده را به وجود می‌آورند می‌توانند به صورت بازگشتی هم تعریف شوند.

```
void printList(LIST lst)
{
 if (!isEmpty(lst)) // base case
 {
 printf("%d ", lst->n); // print integer followed by a space
 printList(lst->next); // recursive call
 }
}

```

#### درخت‌های دودویی

در زیر می‌توانید تعریف ساده‌ای از درخت‌های دودویی را مشاهده کنید. همانند گره‌ها برای لیست‌های الحاقی در اینجا نیز تعریف به صورت بازگشتی است. در اینجا دو اشاره‌گر داریم، یکی به زیر درخت سمت چپ و دیگری به زیر درخت سمت راست.

```
struct node
{
 int n; // some data
 struct node \*left; // pointer to the left subtree
 struct node \*right; // point to the right subtree
};

// TREE is simply a synonym for struct node \* (aka syntactic sugar).
typedef struct node \*TREE;

```

```
void printTree(TREE t) {
 if (!isEmpty(t)) { // base case 
 printTree(t->left); // go left
 printf("%d ", t->n); // print the integer followed by a space
 printTree(t->right); // go right
 }
}

```

### بازگشتی در مقابل غیر بازگشتی

دربارهٔ اینکه کدامیک سریعتر و بهینه تر است نمی‌توان نظر قطعی داد و بستگی به خود الگوریتم و دفعات اجرای آن دارد. اما در هر حال هر کدام برتری‌ها و کاستی‌های نسبت به دیگری دارد و در موارد خاصی الگوریتم‌ها فقط با یکی از این روش قابل پیاده سازی‌اند.

ترتیب فراخوانی توابع
--------------------

### تابع ۱

ترتیب فراخوانی توابع تأثیر به سزایی در اجرای برنامه دارد. به مثال زیر که با زبان C نوشته است، توجه کنید.

```
void recursiveFunction(int num) {
 if (num <5) {
 printf("%d\n", num);
 recursiveFunction(num + 1);
 }
}

```

### تابع ۲ با خطوط جابجا شده

```
void recursiveFunction(int num) {
 if (num <5) {
 recursiveFunction(num + 1);
 printf("%d\n", num);
 }
}

```

بازگشت مستقیم و غیرمستقیم
-------------------------

بازگشت مستقیم زمانی است که تابع خود را فراخوانی کند. بازگشت غیرمستقیم زمانی است که به‌طور مثال تابع «الف» تابع «ب» و تابع «ب« تابع «ث« و تابع «ث» نیز دوباره تابع «الف» را فراخوانی کند.

پیوند به بیرون
--------------

منابع
-----

* 
* ریاضیات گسسته و الگوریتم‌ها نوشته دکتر علی بهفروز و مهندس محمد ایزدی

1. ↑  Graham, Ronald; Knuth, Donald; Patashnik, Oren (1990). "1: Recurrent Problems". *Concrete Mathematics*. ISBN 0-201-55802-5. Archived from the original on 6 November 2020. Retrieved 15 May 2009.
2. ↑  Epp, ‎Susanna (1995), *Discrete Mathematics with Applications* (به انگلیسی) (2nd ed.), p. 427`{{citation}}`: نگهداری یادکرد:نام‌های متعدد:فهرست نویسندگان (link)
3. ↑  Graham, ‎Ronald (1990), *Concrete Mathematics* (به انگلیسی), Donald Knuth, Oren Patashnik, p. Chapter 1: Recurrent Problems, archived from the original on 6 November 2020, retrieved 15 May 2009`{{citation}}`: نگهداری یادکرد:نام‌های متعدد:فهرست نویسندگان (link)
4. ↑  Wirth, ‎Niklaus (1976), *Algorithms + Data Structures = Programs* (به انگلیسی), Prentice-Hall, p. 126`{{citation}}`: نگهداری یادکرد:نام‌های متعدد:فهرست نویسندگان (link)