姓名:杨xx
学号:17272xxx/
运行环境:VS2017/DevC++
- 模块化程序与递归函数设计
prob1:整数的划分
思路
分析示例可得如下划分规律
1.第一个划分数为n-1~1
2.每一次划分后的余下部分不得大于前一个划分数。
故设置一个全局数组用于动态存储每一次划分的结果
然后在一个for循环中先降序划分出来第一个数x,再将余下部分n-x进行再划分。
因为要满足2规律方可使划分结果不重复,所以对划分数的划分需从划分数~1,当划分后余下的部分<=0时终止划分,输出本次划分结果。
代码实现:
#include<iostream>
#include<conio.h>
using namespace std;
int num[100]; //存储划分的数
void print(int k) //输出一次拆分的结果,k为拆分的个数
{
cout << num[0] << "=" << num[1];
for (int i = 2; i <= k; i++)
cout << "+" << num[i];
cout << endl;
}
void split(int k, int n) //n为待拆分数,即上一步拆分后最原始数剩余的部分
{
if (n <= 0) //n<0说明已拆分完全
print(k);
else
for (int i = n; i >= 1; --i) //
{
if (i <= num[k]) //确保拆分出来的数小于前一位拆分出来的数
{
num[k+1] = i; //将拆分出来的数存储进num[k+1]里
split(k + 1, n - i); //余下部分继续拆分,直到满足终止条件为止
}
}
}
int main()
{
cin >> num[0];
for (int i = num[0] - 1; i >= 1; i--) //先拆分出来第一位数
{
num[1] = i;
split(1, num[0] - i);
}
_getch();
return 0;
}
运行截图
prob2:递归实现走迷宫
代码实现:
#include<iostream>
using namespace std;
//迷宫的布局放入到一个二维的数组中
// 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9
int mizu[10][10] = {1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, //0
1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 1, //1
1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 1, //2
1 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1, //3
1 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1, //4
1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1, //5
1 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 1, //6
1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 1, //7
1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1, //8
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 //9
} ;
int flag[10][10];//定义操作数组
void putout(int a[10][10])//输出数组,可输出不同数组
{
int i,j;
for(i=0;i<=9;i++)
for(j=0;j<=9;j++)
{
if(a[i][j]==2)
cout << "*";//2则输出路径*
if(a[i][j]==1)
cout << "x";//1则输出x
if(a[i][j]==0)
cout << " ";//0则输出 空格
if(j==9)
cout << "\n";
}
cout << endl << endl;
}
void nextstep(int x,int y)
{
if(x==8&&y==8)
putout(flag);
flag[x][y]=2;
if(flag[x+1][y]==0)//right is passable
nextstep(x+1,y);
if(flag[x-1][y]==0)//left is passable
nextstep(x-1,y);
if(flag[x][y-1]==0)//down is passable
nextstep(x,y-1);
if(flag[x][y+1]==0)//up is passable
nextstep(x,y+1);
flag[x][y]=0;
}//调用自身完成递归
int main()
{ int i,j;
for(i=0;i<=9;i++)
for(j=0;j<=9;j++)
flag[i][j]=mizu[i][j];
int x=1,y=1;
cout << "迷宫构造" << endl;
putout(mizu);
cout << "5秒后将打印所有能走的方法:" << endl;
nextstep(x,y);
return 0;
}
运行截图
二 结构/链表与堆栈
prob1:猴子选大王
思路:
分析可知,每个猴子节点应该带有三个域,一个为猴子编号;一个为猴子的定数,用于确定下一个删除猴子节点的位置;一个为指向下一个猴子的指针,用于确定猴子之间的关系。
步骤:
1.动态创建一个猴子单向循环链
2.函数DeleteNext(p):删除猴子节点p;当选中猴子p时,只需将p->next指向p->next->next,可设置一个新的节点指针指向待删除的节点。若只是p->next=p-next->next,虽然成功指向,但被删除的猴子所占并内存没得到释放,会造成内存空间浪费。
3. 挑选函数
代码实现:
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct node{//这个结构类型包括三个域
int number;//猴子的编号
int mydata;//猴子的定数
struct node*next;//指向下一个猴子的指针
}linklist;
linklist *Creatcircle(int n) //创建一个猴子的单向循环链
{
linklist *head,*p,*s;
p=head = (linklist*)malloc(sizeof(linklist));//首节点创建
p -> number = 1; //为第一个猴子编号
cin >> p->mydata;//定数,确定下一只出局的猴子
p->next = NULL;
for(int i = 2;i <= n;i++)// 创建链表
{
s=(linklist*)malloc(sizeof(linklist));//创建一个新的节点
s->number = i;//为新节点的编号赋值
cin >> s->mydata;//定数(报数),确定下一只出局的猴子
p->next = s;//将前节点尾指向新节点(添加猴子进猴子圈)
p=s;//前节点指针标志指向新节点,成为新的尾节点
}
p->next = head;//尾节点的指针指向头节点,将表链接成圈
return p;
}
linklist *DeleteNext(linklist *p)//删除单循环链表的p所指的下一个节点
{
linklist *b = p->next; //b节点指向p节点的节点指针指向的节点
p->next = b->next;//
free(b);//释放b节点,即p->next节点
return p;
}
int KingOfMonkey(int n,linklist *head) //挑选大王
{
linklist *p = head;//初始p指针指向头节点
int i,j,steps = p->mydata;//从头节点的定数开始进行遍历删除
for(j = 1;j < n;j++)//删除操作共需n-1步
{
for(i = 1;i < steps;i++) //按照定数搜索待删除的节点
p = p->next; //累加步数,直到达到定数
steps = p->next->mydata; //存储当前待删猴子的定数(既下一待删猴子的位置)
cout << p->next->number << endl; //输出当前待删猴子的编号
DeleteNext(p);//将当前节点从表中删除
}
return p->number;//返货最终胜利的猴子,既猴王
}
int main()
{
linklist *head;
int n;
cout << "请输入猴子的总数和每只猴子的定数(必须是正整数):";
cin >> n;
head = Creatcircle(n);
cout << endl << "the king if monkey[" << KingOfMonkey(n,head) << "]." << endl;
return 0;
}
运行截图
prob2:链表表示一元n次多项式,实现多项式的加/减以及乘法运算
思路:
1.分析一元n次多项式的结构,每个项节点应包含三个域,一个次数域,一个系数域,一个指针域;
2.分析一元n次多项式的加/减/乘运算可知,加法与减法较易实现,次数相同的相加/减即可,但应注意格式输出时对正负号以及对系数为0时的控制;而乘法较复杂,结果链表需伸长至多2n个节点。
3.由于运算是从低次向高次遍历计算,而规范输出是从高次向低次遍历输出,所以需构建双向链表,既指针域有两个next和pre。
步骤
- 输入n
- 动态创建两个长度为n的链表
- 加法运算,需要一个长度为n的链表存储结果
- 减法运算,需要一个长度为n的链表存储结果
- 乘法运算,需要一个长度为2n的链表存储结果
- 将加/减/乘的结果输出
代码实现
#include<iostream>
using namespace std;
typedef struct linklist{
int tim; //指数
int coe; //系数
struct linklist *next;
struct linklist *pre;
}linklist;
/*构建多项式,并返回多项式的头指针*/
linklist *CreatePOOI(int n)
{
linklist *head,*end,*New;
end = head = (linklist*)malloc(sizeof(linklist));
end->tim = n;
cin >> end->coe; //输入系数
end->next =NULL;
end->pre = NULL;
for(int i = n-1;i >= 0;i--)
{
New=(linklist*)malloc(sizeof(linklist));
New->tim = i; //由高次向低次依次为多项式的次数赋值
cin >> New->coe; //由高次向低次依次为多项式的系数赋值
end->next = New; //将前一节点尾指向新节点
New->next = NULL;
New->pre = end; //将新节点的前序指针指向前一节点
end = New; //新尾节点标志设置为新节点
}
return head;
}
/*构建系数均为零的多项式,并返回多项式的头指针*/
linklist *CreateEmptyPOOI(int n)
{
linklist *head,*end,*New;
end = head = (linklist*)malloc(sizeof(linklist));
end->tim = n;
end->coe = 0; //输入系数
end->next =NULL;
end->pre = NULL;
for(int i = n-1;i >= 0;i--)
{
New=(linklist*)malloc(sizeof(linklist));
New->tim = i; //由高次向低次依次为多项式的次数赋值
New->coe = 0; //由高次向低次依次为多项式的系数赋值
end->next = New; //将前一节点尾指向新节点
New->next = NULL;
New->pre = end; //将新节点的前序指针指向前一节点
end = New; //新尾节点标志设置为新节点
}
return head;
}
/*规范输出多项式*/
void ShowPOOI(linklist *p)
{
if(p->coe == 0)
;
else
cout << p->coe << "*n^" << p->tim;
p = p->next;
while(p->next != NULL)
{
if(p->coe < 0)
cout << p->coe << "*n^" << p->tim;
else if(p->coe > 0)
cout << "+" << p->coe << "*n^" << p->tim;
else
;
p = p->next;
}
if(p->coe < 0)
cout << p->coe <<endl;
else if(p->coe > 0)
cout << "+" << p->coe <<endl;
else
;
cout << endl;
}
/*多项式求和,返回结果多项式的头指针*/
linklist *SumPOOI(linklist *ls_1,linklist *ls_2,int n)//n为最高次数
{
linklist *SUM,*Tail;
Tail = SUM = CreateEmptyPOOI(n);
while(SUM->next != NULL)
SUM = SUM->next;
while(ls_1->next != NULL)
ls_1 = ls_1->next;
while(ls_2->next != NULL)
ls_2 = ls_2->next;
while(ls_1->pre != NULL)
{
SUM->coe=ls_1->coe + ls_2->coe;
SUM = SUM->pre;
ls_1 = ls_1->pre;
ls_2 = ls_2->pre;
}
//对正数第1位的运算
SUM->coe=ls_1->coe + ls_2->coe;
return Tail;
}
/*多项式求差,返回结果多项式的头指针*/
linklist *DiffPOOI(linklist *ls_1,linklist *ls_2,int n)//n为最高次数
{
linklist *DIFF,*Tail;
Tail = DIFF = CreateEmptyPOOI(n);
while(DIFF->next != NULL)
DIFF = DIFF->next;
while(ls_1->next != NULL)
ls_1 = ls_1->next;
while(ls_2->next != NULL)
ls_2 = ls_2->next;
while(ls_1->pre != NULL)
{
DIFF->coe=ls_1->coe - ls_2->coe;
DIFF = DIFF->pre;
ls_1 = ls_1->pre;
ls_2 = ls_2->pre;
}
//对正数第1位的运算
DIFF->coe=ls_1->coe - ls_2->coe;
return Tail;
}
/*多项式求积,返回结果多项式的头指针*/
linklist *ProdPOOI(linklist *ls_1,linklist *ls_2,int n)//n为最高次数
{
linklist *PROD,*Tail;
Tail = PROD = CreateEmptyPOOI(2*n);
while(PROD->next != NULL)//3个while作用:找到常数项,从常数项开始按指数升序计算
PROD = PROD->next;
while(ls_1->next != NULL)
ls_1 = ls_1->next;
while(ls_2->next != NULL)
ls_2 = ls_2->next;
//计算PROD的指数n对应的系数时,当ls_1的指数项为i=0~n,则j=n-i~n,Sum=i*j累加;
linklist *i,*j,*iHead,*jHead;//iHead和jHead始终指向ls_1和ls_2的表尾:常数项; 为i,j提供每次循环的初始条件
i = iHead =ls_1;
j = jHead = ls_2;
for(PROD;PROD->pre != NULL;PROD=PROD->pre)
{
for(i = iHead;i->pre != NULL;i = i->pre)
{
for(j = jHead;j->pre != NULL;j = j->pre)
{
if(i->tim + j->tim == PROD->tim)//当ls_1的指数+ls_2的指数等于PROD的指数时
{
PROD->coe += (i->coe*j->coe);
}
}
PROD->coe += (i->coe * j->coe);//为什么有这步以及line:164,line:166,因为每次循环后最高次数项都会漏算
}
PROD->coe += (i->coe * j->coe);
}
PROD->coe += (ls_1->coe * ls_2->coe);
//nice nice nice
return Tail;
}
int main()
{
int n;
linklist *ls_1,*ls_2,*ls_sum,*ls_diff,*ls_prod;
cout << "please input n:";
cin >> n;
cout << "构建链表1" << endl;
ls_1 = CreatePOOI(n);
cout << "构建链表2" << endl;
ls_2 = CreatePOOI(n);
cout << "一元多项式1:";
ShowPOOI(ls_1);
cout << "一元多项式2:";
ShowPOOI(ls_2);
ls_sum = SumPOOI(ls_1,ls_2,n);
cout << "多项式1和2的和:";
ShowPOOI(ls_sum);
ls_diff = DiffPOOI(ls_1,ls_2,n);
cout << "多项式1和2的差:";
ShowPOOI(ls_diff);
ls_prod = ProdPOOI(ls_1,ls_2,n);
cout << "多项式1和2的积:";
ShowPOOI(ls_prod);
}
运行截图
- 图形程序设计基础
prob1:画房子
关键在于计算坐标,最简洁的方法是一个line函数搞定.
代码实现:
#include "graphics.h"
int main(void)
{
initgraph(638,512); // 初始化绘图环境
line(175, 211, 175, 391);
line(175, 211, 463, 211);
line(463, 211, 463, 391);
line(175, 391, 463, 391);
line(175, 301, 463, 301);
line(247, 199, 247, 391);
line(319, 199, 319, 391);
line(391, 211, 391, 391);
line(211, 121, 175, 211);
line(211, 121, 247, 211);
line(427, 121, 391, 211);
line(427, 121, 463, 211);
line(259, 199, 247, 199);
line(259, 199, 259, 211);
line(271, 211, 271, 199);
line(271, 199, 283, 199);
line(283, 199, 283, 211);
line(295, 211, 295, 199);
line(295, 199, 307, 199);
line(307, 199, 307, 211);
line(331, 199, 319, 199);
line(331, 199, 331, 211);
line(343, 211, 343, 199);
line(343, 199, 355, 199);
line(355, 199, 355, 211);
line(367, 211, 367, 199);
line(367, 199, 379, 199);
line(379, 199, 379, 211);
ege::getch();
closegraph();
return 0;
}
运行截图
prob2:画多边形
思路
分析多边形,可看出是由以下图形绕一点旋转20°连续旋转18次得到,且线段长度不变.
- 可设置一个循环,在循环里设置一个初始为0°,每一次增加20°的角度变量(因为要用到sin和cos函数所以需转换为弧度制),再对每一次旋转后进行画线操作。
- 分析每一次的画线操作,可得到如下相同的画线规律
沿当前角度(第1步骤中的角度)画线->逆时针旋转60°->画线->逆时针旋转-120°->画线->逆时针旋转-60°->画线->逆时针旋转120°->画线
此步骤在draw函数中实现
- 旋转角度函数turn
- 移动画线的起始坐标函数move
- 沿特定角度画线函数forward
实现代码<