
- •«Рекурсивные алгоритмы» Содержание:
- •Теоретическое введение:
- •Тексты программ с комментариями;
- •Результаты выполнения программ. Теоретическое введение.
- •Задача поиска максимума.
- •Задача рисования меток на линейке.
- •Задача о Ханойских башнях.
- •Переместить верхние n-1 диск со столбика a на столбик b, используя столбик c как вспомогательный.
- •Переместить оставшийся нижний диск со столбика a на столбик c.
- •Переместить n-1 диск со столбика b на столбик c, используя столбик a как вспомогательный.
- •Тексты программ с комментариями.
- •Int Maximum(int a[10], int l, int r)//заголовок ф-ии
- •Результаты выполнения программ.
Int Maximum(int a[10], int l, int r)//заголовок ф-ии
{//a-исходный массив, l-индекс 1-го эл-та, r-индекс //последнего эл-та
if (l==r) return a[l]; //если массив состоит из 1-го //эл-та, то он и есть max
int m=(l+r)/2;//делим массив на 2 подмассива
int u=Maximum(a,l,m);//ищем в 1-ом максимальный эл-т
int v=Maximum(a,m+1,r);//во 2-ом также ищем //максимальный эл-т
if (u>v) return u; else return v;//сравнивая их, //возвращаем максимальный
}
-------------------------------------------------------------------------------------------------------
Программа 2 (Рисование меток) (Имя файла: line.cpp) :
-------------------------------------------------------------------------------------------------------
//*******************************************************
//Подключаемые заголовочные файлы
#include <stdio.h> //стандартный ввод-вывод
#include <conio.h>//для ф-ии getch() и т. д.
#include <ctype.h>//для ф-ии isdigit()
#include <string.h>//работа со строками
#include <stdlib.h>//стандартная библиотека (для ф-ии //atoi(),exit(1))
#include <graphics.h>//работа с графикой
#include <dos.h>//для ф-ии delay()
//*******************************************************
//объявление глобальных переменных
int stepen;//число 2^n
int lastx;//абсцисса текущей метки
//*******************************************************
//Основная функция main()
void main()
{
int Error();//прототип ф-ии запроса и проверки на //неверный ввод
void Rule(int, int, int);//прототип рекурсивной ф-//ии, вызывающей Mark(x,h)
int i,n;//i-счетчик цикла, n-показатель степени 2
while(1) // цикл проверки введенного n в диапазоне
{
n=Error(); // вызов ф-ии запроса и прис-е рез-та
if (n>=1 && n<=8) break;// диапазон
}
stepen=2;
for (i=1;i<n;i++) stepen=stepen*2;//цикл подсчета //степени 2^n
int gdriver = DETECT, gmode;//переменные для //инициализации граф. режима
initgraph(&gdriver,&gmode, "");//инициализация граф. //режима
if (graphresult()!=0) //проверка на ошибку
{
clrscr();
printf("\nОшибка инициализации графики!!!");
getch();
exit(1); //выйти из программы в случае ошибки
}
setcolor(10);//установка св.-зел. цвета рисования
//рисование левой границы линейки
line(0,getmaxy()-200,0,getmaxy()-210-10*n);
setcolor(11);//установка св.-сер. цвета рисования
Rule(0,stepen,n);//вызов рекурсивной ф-ии
setcolor(10);//установка св.-зел. цвета рисования
//рисование верхней границы линейки
line(0,getmaxy()-210-10*n,lastx+getmaxx()/stepen, getmaxy()-210-10*n);
//рисование нижней границы линейки
line(0,getmaxy()-200,lastx+getmaxx()/stepen, getmaxy()-200);
//рисование правой границы линейки
line(lastx+getmaxx()/stepen,getmaxy()-200, lastx+getmaxx()/stepen,getmaxy()-210-10*n);
setcolor(5);//установка роз. цвета рисования
//вывод сообщения
outtextxy(getmaxx()/2-80,getmaxy()-100,"Press any key for quit");
getch();//задержка
delay(1000);
closegraph(); //закрытие графического режима
return;
}
//*******************************************************
//ф-ия запроса и проверки (защита от неверных нажатий)
int Error()//заголовок ф-ии
{
int i;
char str[10]; //вводимая строка
int str_int[2]; //массив из 2 целых значений
clrscr();//очистка экрана
// печать строки на экран
printf("\n\t\tВведите показатель степени 2 разрешения 1/2^n (1-8): ");
gets(str);//ф-ия ввода строки с клавиатуры
i=1;
if (strlen(str)>2) return 0;
while (i<=strlen(str))//цикл преобразования кодов //символов из char в int,
{//а также анализ на код не цифры
str_int[i-1]=(int)str[i-1];//в эл-ты массива //str_int поместить преобразованные в тип int коды //введенных символов
if (isdigit(str_int[i-1])==0) return 0;//выйти из //ф-ии с передачей 0, если это код не цифры
i++;
}
return atoi(str);//ф-ия преобразования введенной //строки в целое число типа int, а также возвращение //этого рез-та в главную ф-ию main()
}
//*******************************************************
//рекурсивная ф-ия, вызывающая Mark(x,h)
void Rule (int l, int r, int h)//заголовок ф-ии
{//l-условная абсцисса левой границы линейки
// r-условная абсцисса правой границы линейки 2
// h-высота самой длинной метки
void Mark (int, int);//прототип ф-ии рисования меток
int m=(l+r)/2;//делим линейку пополам
if (h>0) //если высота метки не нулевая, то
{
Rule(l,m,h-1); //вызов ф-ии из самой себя (рекурсия), //сначала работаем в левой части линейки
Mark(m,h); //вызов ф-ии рисования метки
Rule(m,r,h-1);//вызов ф-ии из самой себя (рекурсия), //потом работаем в правой части линейки
}
}
//*******************************************************
//ф-ия рисования меток
void Mark (int x, int p)//заголовок ф-ии
{//x-коэффициент абсциссы метки, p-коэффициент высоты //метки
lastx=getmaxx()/stepen*x;//в глоб. перем. заносим //текущую абсциссу метки
//рисуем метку
line(lastx,getmaxy()-200,lastx,getmaxy()-200-p*10); return;//возврат из ф-ии
}
-------------------------------------------------------------------------------------------------------
Программа 3 (Ханойские башни) (Имя файла: han_gr_3.cpp) :
-------------------------------------------------------------------------------------------------------
//*******************************************************
//Подключаемые заголовочные файлы
#include <stdio.h> //стандартный ввод-вывод
#include <conio.h>//для ф-ии getch() и т. д.
#include <ctype.h>//для ф-ии isdigit()
#include <string.h>//работа со строками
#include <stdlib.h>//стандартная библиотека (для ф-ии //atoi(),exit(1))
#include <graphics.h>//работа с графикой
#include <dos.h>//для ф-ии delay()
//*******************************************************
//объявление глобальных переменных
struct zap //структура, состоящая из
{ int y1,y2;//ординат верхнего и нижнего угла объекта
};
zap arr_A[14],arr_B[14],arr_C[14];//3 массива(3 //столбика) из структур
int i; //счетчик цикла
char ch; //код символа
FILE *st1;//указатель на файл st1
int w=54;//доп. переменная для рисования дисков
//*******************************************************
//Основная функция main()
void main()
{
void Move_Disks(int, char, char, char);//прототип //функции получения решения
void Graph_disk (int, char, char, char);//прототип //ф-ии графического представления решения
int Error(); //прототип ф-ии запроса и проверки //на неверные символы
int r; //кол-во дисков
int e; //кол-во перемещений (шагов)
while(1)// цикл проверки введенного r в диапазоне
{
r=Error();// вызов ф-ии запроса и прис-е рез-та
if (r>=1 && r<=14) break; // диапазон
}
for (i=1,e=2;i<r;i++) e=e*2;//цикл подсчета кол-ва //перемещений e по формуле 2^n-1
e--;
st1=fopen("res.txt","w+");//создание или открытие //файла res.txt
// печать строки в файл, на который указывает st1
fprintf(st1,"\t\tРешение задачи о Ханойских башнях для %d дисков:\n\n",r);
Move_Disks(r,'A','C','B');//вызов рекурсивной ф-ии //решения
// печать строки в файл, на который указывает st1
fprintf(st1,"\nТребуется %d перемещений!",e);
fclose(st1); //закрытие файла
Graph_disk(r,'A','C','B');//вызов ф-ии //графического представления решения
return;//выход из главной ф-ии
}
//*******************************************************
//Описание функции получения решения (рекурсивная)
//заголовок ф-ии с параметрами
void Move_Disks (int n, char Source, char Dest, char Temp)
{
if (n==1) //если имеется только 1 диск, то это //элементарно
{
fprintf(st1,"Переставить диск номер 1 со столбика %c на столбик %c\n",Source,Dest);
}
else //иначе:
{//сначала перемещаем n-1 диск со столбика A на //столбик B, используя столбик C как вспомогательный
Move_Disks(n-1,Source,Temp,Dest);//вызов процедуры из //самой себя, или рекурсия
fprintf(st1,"Переставить диск номер %d со столбика %c на столбик %c\n",n,Source,Dest);
//затем перемещаем n-1 диск со столбика B на столбик C, //используя столбик A как вспомогательный
Move_Disks(n-1,Temp,Dest,Source);//вызов процедуры из //самой себя, или рекурсия
return;//возврат из ф-ии
}
}
//*******************************************************
//ф-ия запроса и проверки (защита от неверных нажатий)
int Error()//заголовок ф-ии
{
char str[10]; //вводимая строка
int str_int[2]; //массив из 2 целых значений
clrscr();//очистка экрана
// печать строки на экран
printf("\n\t\tВведите количество дисков (без пробелов!) (1-14): ");
gets(str);//ф-ия ввода строки с клавиатуры
i=1;
if (strlen(str)>2) return 0;
while (i<=strlen(str))//цикл преобразования кодов //символов из char в int, а также анализ на код не цифры
{ str_int[i-1]=(int)str[i-1];//в эл-ты массива //str_int поместить преобразованные в тип int коды //введенных символов
if (isdigit(str_int[i-1])==0) return 0;//выйти из //ф-ии с передачей 0, если это код не цифры
i++;
}
return atoi(str);//ф-ия преобразования введенной //строки в целое число типа int, а также возвращение //этого рез-та в главную ф-ию main()
}
//*******************************************************
//ф-ия прорисовки шагов
void Graph_disk(int n, char S, char D, char T)//заголовок
{
void Graph_steps(int, char, char, char);//прототип //рекурсивной граф. ф-ии
int Klav_getch();//прототип ф-ии нажатий 'n' и 'q'
int gdriver = DETECT, gmode;//переменные для //инициализации граф. режима
initgraph(&gdriver,&gmode, "");//инициализация граф. //режима
if (graphresult()!=0) //проверка на ошибку
{
clrscr();
printf("\nОшибка инициализации графики!!!");
getch();
exit(1); //выйти из программы в случае ошибки
}
//сообщения на экран
printf("\t\tРешение задачи о Ханойских башнях для %d дисков:",n);
printf("\n\n\n\tЖмите:\n\t n - для просмотра очередного шага");
printf("\n\t q - для выхода (результат см. в файле res.txt)\n");
setcolor(10);//установка светло-зеленого цвета
rectangle(0,20,getmaxx(),getmaxy());//обрамление экрана
setfillstyle(1,5);//установка сплошного розового стиля //заливки
//рисование 3-х столбиков с обозначением A,B,C
bar(getmaxx()/4-40,200,getmaxx()/4-39,getmaxy()-40);
outtextxy(getmaxx()/4-42,getmaxy()-20,"A");
bar(getmaxx()/4*2,200,getmaxx()/4*2+1,getmaxy()-40);
outtextxy(getmaxx()/4*2-2,getmaxy()-20,"B");
bar(getmaxx()/4*3+40,200,getmaxx()/4*3+41,getmaxy()-40);
outtextxy(getmaxx()/4*3+38,getmaxy()-20,"C");
setfillstyle(1,11);//установка сплошного светло-серого //стиля заливки
int o=68; //доп. переменная для рисования дисков
char stroka[3]; //строка, которая будет содержать номер //рисуемого диска
i=1;
while (i<=n) //цикл заполнения массивов ординат
{
arr_A[n-i].y1=getmaxy()-o+4;//ордината верхнего угла //диска
arr_A[n-i].y2=getmaxy()-o+12;//ордината нижнего угла //диска
arr_B[n-i].y1=getmaxy()-o+4;
arr_B[n-i].y2=getmaxy()-o+12;
arr_C[n-i].y1=getmaxy()-o+4;
arr_C[n-i].y2=getmaxy()-o+12;
//нач. прорисовка дисков с уменьшением диаметра на //столбике A
bar(getmaxx()/4-36-w,arr_A[n-i].y1,getmaxx()/4-39+w-4, arr_A[n-i].y2);
itoa(n+1-i,stroka,10);//преобразование номера диска в //строку stroka
//вывод номера диска слева от диска
outtextxy(getmaxx()/4-36-w-17,getmaxy()-o+5,stroka);
w=w-4;//радиус вышележащего(след.)диска уменьшаем на 4
o=o+12;//изменяем ординаты углов вышележащего(след.) //диска
i++;
}
o=0;
setfillstyle(1,0);//установить сплошную черную заливку
o=Klav_getch(); // при нажатии 'n'
if (o==1) Graph_steps(n,S,D,T);// вызвать ф-ию
cleardevice();//залить экран
//выдать сообщение
outtextxy(getmaxx()/2-80,getmaxy()/2,"Press any key for quit");
getch();//задержка
delay(1000);
closegraph(); //закрытие графического режима
return;//возврат из ф-ии
}
//*******************************************************
//рекурсивная граф. ф-ия
void Graph_steps(int n, char S, char D, char T) //заголовок ф-ии
{
void Analizing(int, char, char);//прототип ф-ии //перемещения дисков
int Klav_getch();//прототип ф-ии нажатий 'n' и 'q'
if (n==1) //если имеется только 1 диск, то это //элементарно(с A на C)
{
Analizing(n,S,D);//вызвать ф-ию перемещения дисков
Klav_getch(); //вызвать ф-ию на нажатия 'n' и 'q'
}
else//иначе
{//сначала перемещаем n-1 диск со столбика A на //столбик B, используя столбик C как вспомогательный
Graph_steps(n-1,S,T,D);//вызов процедуры из самой //себя, или рекурсия
Analizing(n,S,D);//вызвать ф-ию перемещения дисков
Klav_getch();//вызвать ф-ию на нажатия 'n' и 'q'
//затем перемещаем n-1 диск со столбика B на //столбик C, используя столбик A как вспомогательный
Graph_steps(n-1,T,D,S);//вызов процедуры из самой //себя, или рекурсия
return;//возврат из ф-ии
}
}
//*******************************************************
//ф-ия перемещения дисков
void Analizing(int n, char S, char D) //заголовок ф-ии
//n-номер переносимого диска, S-откуда переносить, D-//куда переносить
{ void *ukaz; //указатель на объект для ф-ии //getimage/putimage
switch(S)
{//диск переносится со столбика A
case 'A' : switch(D)
{//на столбик B
case 'B' : {//сохраняем в памяти //объект(диск и его номер) на столбике A, ординаты берем //из соотв. массива
getimage(getmaxx()/4-120,arr_A[n-1].y1,getmaxx()/4+11,arr_A[n-1].y2,ukaz);
setfillstyle(1,0);
//стираем его со столбика A
bar(getmaxx()/4-120,arr_A[n-1].y1,getmaxx()/4+11,arr_A[n-1].y2);
setfillstyle(1,5);
//снова прорисовываем часть //столбика A, где был диск
bar(getmaxx()/4-40,arr_A[n-1].y1,getmaxx()/4-39,arr_A[n-1].y2);
//начиная с низа столбика B до его //верхушки ищем свободное место для переносимого диска, //анализируя цвет
for (i=1;i<=164;i=i+4) if (getpixel(getmaxx()/4*2,getmaxy()-55-i)==5)
{//если оно найдено,то
//в соотв. эл-т //массива запоминаем новые ординаты переносимого диска
arr_B[n-1].y1=getmaxy()-55-i-8;
arr_B[n-1].y2=getmaxy()-55-i;
setfillstyle(1,0);
//стираем часть //столбика B, куда будет перенесен диск
bar(getmaxx()/4*2,arr_B[n-1].y1,getmaxx()/4*2+1,arr_B[n-1].y2);
//и, наконец, //вставляем из памяти объект в найденное место
putimage(getmaxx()/4*2-80,arr_B[n-1].y1,ukaz,1);
break;
}
} break;
//далее все аналогично
//на столбик C
case 'C' : {getimage(getmaxx()/4-120,arr_A[n-1].y1,getmaxx()/4+11,arr_A[n-1].y2,ukaz);
setfillstyle(1,0);
bar(getmaxx()/4-120,arr_A[n-1].y1,getmaxx()/4+11,arr_A[n-1].y2);
setfillstyle(1,5);
bar(getmaxx()/4-40,arr_A[n-1].y1,getmaxx()/4-39,arr_A[n-1].y2);
for (i=1;i<=164;i=i+4) if (getpixel(getmaxx()/4*3+40,getmaxy()-55-i)==5)
{
arr_C[n-1].y1=getmaxy()-55-i-8;
arr_C[n-1].y2=getmaxy()-55-i;
setfillstyle(1,0);
bar(getmaxx()/4*3+40,arr_C[n-1].y1,getmaxx()/4*3+41,arr_C[n-1].y2);
putimage(getmaxx()/4*3+40-80,arr_C[n-1].y1,ukaz,1);
break;
}
} break;
} break;
//диск переносится со столбика B
case 'B' : switch(D)
{//на столбик A
case 'A' : {getimage(getmaxx()/4*2-80,arr_B[n-1].y1,getmaxx()/4*2+51,arr_B[n-1].y2,ukaz);
setfillstyle(1,0);
bar(getmaxx()/4*2-80,arr_B[n-1].y1,getmaxx()/4*2+51,arr_B[n-1].y2);
setfillstyle(1,5);
bar(getmaxx()/4*2,arr_B[n-1].y1,getmaxx()/4*2+1,arr_B[n-1].y2);
for (i=1;i<=164;i=i+4) if (getpixel(getmaxx()/4-40,getmaxy()-55-i)==5)
{
arr_A[n-1].y1=getmaxy()-55-i-8;
arr_A[n-1].y2=getmaxy()-55-i;
setfillstyle(1,0);
bar(getmaxx()/4-40,arr_A[n-1].y1,getmaxx()/4-39,arr_A[n-1].y2);
putimage(getmaxx()/4-120,arr_A[n-1].y1,ukaz,1);
break;
}
} break;
//на столбик C
case 'C' : {getimage(getmaxx()/4*2-80,arr_B[n-1].y1,getmaxx()/4*2+51,arr_B[n-1].y2,ukaz);
setfillstyle(1,0);
bar(getmaxx()/4*2-80,arr_B[n-1].y1,getmaxx()/4*2+51,arr_B[n-1].y2);
setfillstyle(1,5);
bar(getmaxx()/4*2,arr_B[n-1].y1,getmaxx()/4*2+1,arr_B[n-1].y2);
for (i=1;i<=164;i=i+4) if (getpixel(getmaxx()/4*3+40,getmaxy()-55-i)==5)
{
arr_C[n-1].y1=getmaxy()-55-i-8;
arr_C[n-1].y2=getmaxy()-55-i;
setfillstyle(1,0);
bar(getmaxx()/4*3+40,arr_C[n-1].y1,getmaxx()/4*3+41,arr_C[n-1].y2);
putimage(getmaxx()/4*3+40-80,arr_C[n-1].y1,ukaz,1);
break;
}
} break;
} break;
//диск переносится со столбика C
case 'C' : switch(D)
{//на столбик A
case 'A' : {getimage(getmaxx()/4*3+40-80,arr_C[n-1].y1,getmaxx()/4*3+40+51,arr_C[n-1].y2,ukaz);
setfillstyle(1,0);
bar(getmaxx()/4*3+40-80,arr_C[n-1].y1,getmaxx()/4*3+40+51,arr_C[n-1].y2);
setfillstyle(1,5);
bar(getmaxx()/4*3+40,arr_C[n-1].y1,getmaxx()/4*3+41,arr_C[n-1].y2);
for (i=1;i<=164;i=i+4) if (getpixel(getmaxx()/4-40,getmaxy()-55-i)==5)
{
arr_A[n-1].y1=getmaxy()-55-i-8;
arr_A[n-1].y2=getmaxy()-55-i;
setfillstyle(1,0);
bar(getmaxx()/4-40,arr_A[n-1].y1,getmaxx()/4-39,arr_A[n-1].y2);
putimage(getmaxx()/4-120,arr_A[n-1].y1,ukaz,1);
break;
}
} break;
//на столбик B
case 'B' : {getimage(getmaxx()/4*3+40-80,arr_C[n-1].y1,getmaxx()/4*3+40+51,arr_C[n-1].y2,ukaz);
setfillstyle(1,0);
bar(getmaxx()/4*3+40-80,arr_C[n-1].y1,getmaxx()/4*3+40+51,arr_C[n-1].y2);
setfillstyle(1,5);
bar(getmaxx()/4*3+40,arr_C[n-1].y1,getmaxx()/4*3+41,arr_C[n-1].y2);
for (i=1;i<=164;i=i+4) if (getpixel(getmaxx()/4*2,getmaxy()-55-i)==5)
{
arr_B[n-1].y1=getmaxy()-55-i-8;
arr_B[n-1].y2=getmaxy()-55-i;
setfillstyle(1,0);
bar(getmaxx()/4*2,arr_B[n-1].y1,getmaxx()/4*2+1,arr_B[n-1].y2);
putimage(getmaxx()/4*2-80,arr_B[n-1].y1,ukaz,1);
break;
}
} break;
} break;
}
return;//возврат из ф-ии
}
//*******************************************************
//ф-ия на нажатия 'n' и 'q'
int Klav_getch()//заголовок ф-ии
{
w=0;
while(1) //цикл анализа нажатой клавиши
{
ch=getch();//принять от клавиатуры символ
switch(ch)
{
case 'q': i=1 ; break; //выход из цикла //производится,только если была
case 'n':{i=1;w=1;} break;//нажата 'n' или 'q'
default : i=0 ;
}
if (i==1) break;
}
if (w==0) //если нажата 'q', то
{
setfillstyle(1,0);
cleardevice(); //залить экран
//выдать сообщение
outtextxy(getmaxx()/2-80,getmaxy()/2,"Press any key for quit");
getch(); //задержка до нажатия
delay(1000);
closegraph(); //закрыть граф. режим
exit(1);//прервать выполнение программы
}
return 1;//если нажата 'n', то возвратить значение 1
}
-------------------------------------------------------------------------------------------------------