русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Рекурсия


Дата добавления: 2013-12-23; просмотров: 1220; Нарушение авторских прав


Функция с двумя родовыми типами

 

В предложении template можно определить более одного родового типа данных, если использовать список с разделяющими запятыми. Например, приведенная ниже программа создает шаблонную функцию, использующую два родовых типа:

 

// demoTemplate.cpp : Defines the entry point for the console application.

//

#include "stdafx.h"

#include <iostream>

using namespace std;



 

template <typename Typel, typename Type2>

void myfunc(Typel x, Type2 y);

 

int main(){

myfunc(10, "hi");

myfunc(0.23, 10L);

return 0;

}

template <typename Typel, typename Type2>

void myfunc(Typel x, Type2 y)

{

cout << x << ' ' << y << '\n';

}

 

В этом примере условные имена типов Typel и Туре2 заменяются компилятором на типы данных int и char*, а также double и longсоответственно, когда компилятор создает специфические экземпляры функции myfunc() в main().

Последняя тема, которую мы рассмотрим в этом модуле, посвящена рекурсии. Рекурсия, иногда называемая циклическим определением, представляет собой процесс определения чего-то с помощью самого себя. В приложении к программированию рекурсия — это процесс вызова функцией самой себя. Функцию, которая вызывает саму себя, называют рекурсивной.

Классическим примером рекурсии может служить функция factr(), которая вычисляет факториал целого числа. Факториалом числа N называют произведение всех целых чисел между 1 и N.. Например, факториал числа 3 (или, как говорят, "три факториал") вычисляется как 1x2x3, что равно 6. Ниже приведены как функция factr(), так и ее итеративный эквивалент.

// Демонстрация рекурсии.

 

#include <iostream>

using namespace std;



 

int factr(int n);

int fact(int n);

 

int main () {

// используем рекурсивный вариант

cout << "4 факториал равен " << factr(4) ;

cout << '\n';

 

// используем итеративный вариант

cout << "4 факториал равен " << fact(4);

cout << ' \n' ;

 

return 0;

}'

// Рекурсивный вариант.

int factr(int n)

{

int answer;

if(n==l) return(1);

answer = factr (n-1) *n;//Выполнить рекурсивный вызов factr()

return(answer) ;

}

// Итеративный вариант.

int fact(int n) {

int answer;

answer = 1 ;

for(int t=l; t<=n; t++) answer = answer*(t);

return(answer);

}

 

Действие нерекурсивного варианта fact() вполне очевидно. Он использует цикл, начинающийся с 1, в котором каждое следующее число умножается на последовательно увеличивающееся пpоизведение.

Действие рекурсивной функции factr( ) несколько сложнее. При вызове factr( ) с аргументом 1 функция возвращает 1; в противном случае она возвращает произведение factr(n-l)*n. Для вычисления этого выражения factr( ) вызывается с аргументом (n-1). Это происходит до тех пор, пока n не станет равным 1, и вызов функции приведет к возврату из нее. Например, когда вычисляется факториал 2, первый вызов factr( ) породит второй вызов с аргументом 1. Этот вызов вернет 1, которая умножится на 2 (первоначальное значение n). Переменная answer будет тогда равна 2. Вы можете ради любопытства включить в factr( ) предложения cout, которые покажут, на каком уровне находится вызов и каков промежуточный результат (переменная answer).

Когда функция вызывает саму себя, для новых локальных переменных и параметров выделяется память (обычно на системном стеке), и код функции выполняется с самого начала с использованием этих новых переменных. Рекурсивный вызов не создает новой копии функции; только ее аргументы будут новыми. При возврате из каждого рекурсивного вызова старые локальные переменные и параметры удаляются из стека, и выполнение продолжается с точки вызова функции изнутри функции. Можно сказать, что рекурсивные функции действуют подобно раздвижной подзорной трубе, сначала раскладываясь, а затем складываясь.

Имейте в виду, что большинство рекурсивных функций не уменьшают размер кода в заметной степени. Кроме того, рекурсивные варианты большинства алгоритмов выполняются несколько более медленно, чем их итеративные эквиваленты, из-за добавления издержек на дополнительные функциональные вызовы. Слишком много рекурсивных обращений к функции может вызвать переполнение стека. Из-за того, что параметры и локальные переменные функции размещаются на стеке, и каждый новый вызов создает новую копию этих переменных, стек может истощиться. Если это произойдет, то могут быть разрушены другие данные. Реально, однако, вряд ли вам придется столкнуться с такой ситуацией, если только рекурсивная функция не зациклится.

Основное преимущество рекурсивных функций заключается в том, что их можно использовать для создания вариантов некоторых алгоритмов, которые оказываются проще и нагляднее, чем их итеративные аналоги. Например, алгоритм быстрого упорядочения довольно затруднительно реализовать в виде итеративных вызовов. Некоторые задачи, особенно в области искусственного интеллекта, кажутся прямо приспособленными для рекурсивного решения.

Составляя рекурсивную функцию, вы должны где-то в ней включить условное предложение, например, if, чтобы заставить функцию осуществить возврат без выполнения рекурсивного вызова. Если вы пренебрежете таким условным предложением, то вызвав однажды эту функцию, вы никогда из нее не вернетесь. Это, довольно распространенная ошибка. Разрабатывая программы с рекурсивными функциями, не стесняйтесь включать в них предложения cout, которые позволят вам наблюдать, что происходит в программе, и аварийно завершить выполнение, если вы обнаруживаете ошибку.

Ниже приведен другой пример рекурсивной функции, названной reverse(). Она выводит на экран строку задом наперед.

 

// Вывод строки задом наперед посредством рекурсии.

#include <iostream>

using namespace std;



 

void reverse(char *s);

 

int main() {

char str[] = "это просто проверка";

reverse (str) ;

return 0;

}

// Вывод строки задом наперед,

void reverse(char *s)

{

if(*s)

reverse(s+1);

else

return;

 

cout << *s;

}

 

Функция reverse() прежде всего проверяет, не передан ли ей указатель на завершающий ноль строки. Если нет, то reverse( ) вызывает себя с передачей в качестве аргумента указателя на следующий символ строки. Когда наконец будет найден завершающий ноль, вызовы начинают "раскручиваться", и символы появляются на экране в обратном порядке.

Еще одно замечание. Понятие рекурсии часто оказывается сложным для начинающих. Не отчаивайтесь, если этот материал показался вам слишком запутанным. С течением времени вы освоите и его.

 



<== предыдущая лекция | следующая лекция ==>
Родовые функции | Кластеры


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.089 сек.