Fork me on GitHub

python机器学习--手写算法KNN

一. KNN 算法简介

K-近邻((k-Nearest Neighbors))算法可以说是最简单的机器算法。构建模型只需要保存训练数据集即可。想要对新数据点做出预测,算法会在训练数据集中找到最近的数据点,也就是它的“最近邻”。该算法的思想是一个样本与数据集中的k个样本最相似,如果这k个样本中的大多数属于某一个类别,则该样本也属于这个类别。

二. 算法构造

(1) 计算测试数据与各训练数据之间的距离;
  (2) 对距离进行升序排列;
  (3) 选取距离最小的K个点;
  (4) 计算前K个点各自类别的出现频率;
  (5) 返回前K个点中出现频率最高的类别作为测试数据的预测分类。

三. 算法细节实现

1.生成数据集(加载鸢尾花数据集)

在这里插入图片描述
以下是生成的数据及类别数据
在这里插入图片描述
在这里插入图片描述

2.获取训练集测试集

在这里插入图片描述

3 .构建模型(绘制训练集散点图)

在这里插入图片描述

4.KNN 算法处理过程
(1).新增一个点

绘制新增点后的散点图
在这里插入图片描述
图中黑色的点是所需预测的数,利用距离得出离他最近的点的类别以此来进行分类
以下是算法及注释
在这里插入图片描述

5.使用测试集数据进行算法精度评估

在这里插入图片描述
即将测试集的各个点代用算法距离公式,实现分类决策

四.算法优劣

 优点:
    (1) 精度高;
    (2) 对异常值不敏感。
 缺点:
    (1) 计算复杂度高;
    (2) 空间复杂度高。
 适用数据范围:
    数值型和标称型

五.经验总结

由于不熟悉numpy 和matplotlib的函数,在相关的功能实现上费了很大功夫,但也学会了相关的知识。在手写KNN 算法的基础上进一步理解了KNN算法的思想。

附源碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# coding:utf-8
import numpy as np
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
from math import sqrt
from collections import Counter
test_num = 75 # 测试数据个数
# 源数据的产生(加载sklearn鸢尾花数据集)
datas = load_iris()
# 使用切片获取150组鸢尾花数据(datas['data']为data key 值对应数据,即鸢尾花花瓣花萼数据)
raw_data_x = datas['data'][0:150]
# 表示鸢尾花的类别(K-NN算法处理基于监督学习的分类问题)
# 0表示setosa类 ,1 表示versicolor类 ,2表示virginica 类
raw_data_y = datas['target'][0:150]
# 产生训练集(源数据的百分之50)
x_Train = raw_data_x[0:150:2]
y_Train = raw_data_y[0:150:2]
# 产生测试集(源数据的百分之50)
x_Test = raw_data_x[1:150:2]
y_Test = raw_data_y[1:150:2]

print(raw_data_x)
print(raw_data_y)

plt.scatter(x_Train[y_Train == 0, 0], x_Train[y_Train == 0, 1], color='b', label="feature 0")
plt.scatter(x_Train[y_Train == 1, 0], x_Train[y_Train == 1, 1], color='r', label="feature 1")
plt.scatter(x_Train[y_Train == 2, 0], x_Train[y_Train == 2, 1], color='yellow', label="feature 2")
plt.title("train-data-view")
plt.xlabel("x axis")
plt.ylabel("y axis")
plt.show()

# 增加一个新的点
x = np.array([4.0915321615, 3.4651321653, 1.48654954531, 0.46365316316])
# 绘制新增点的数据散点图并判断其是0 or 1 or 2
plt.scatter(x_Train[y_Train == 0, 0], x_Train[y_Train == 0, 1], color='b', label="feature 0")
plt.scatter(x_Train[y_Train == 1, 0], x_Train[y_Train == 1, 1], color='r', label="feature 1")
plt.scatter(x_Train[y_Train == 2, 0], x_Train[y_Train == 2, 1], color='yellow', label="feature 2")
plt.scatter(x[0], x[1], color='black', label="symbol ?") # 将新增点绘制成黑色
plt.title("k-NN (one point view)")
plt.xlabel("x axis")
plt.ylabel("y axis")
plt.legend()
plt.show()
#新点knn
distances = []
for X_train in x_Train:

d = sqrt(np.sum((X_train - x) ** 2))
distances.append(d)

nearest = np.argsort(distances)
k = int(input("请输入k值 "))
topK_y = [y_Train[i] for i in nearest[:k]]
print("KNN 计算距离列表"+str(topK_y))


votes = Counter(topK_y)
predict_y = votes.most_common(1)[0][0]
print("新增点预测数值为:"+str(predict_y))
if predict_y==0:
print("新增点预测结果为:setosa")
elif predict_y==1:
print("新增点预测结果为:versicolor")
elif predict_y==2:
print("新增点预测结果为:virginica")
counter = 0
pre = 0

for select in x_Test:
Distance = []
for x_pre in x_Train:
d_t = sqrt(np.sum((x_pre-select) ** 2))
Distance.append(d_t)

near = np.argsort(Distance)
topK_y = [y_Train[i] for i in near[:k]]
votes = Counter(topK_y)
result = votes.most_common(1)[0][0]
if y_Test[pre] == result:
counter = counter + 1
pre = pre + 1
else:
pre = pre + 1
score = counter / test_num
print("测试精度为"+str(score)) #输出测试精度

最大公约数算法比较

最大公约数算法比较

edit time:2019 03 07

一.代码编写目的

1明确算法的概念和特点。
2通过对问题的分析,设计合理的算法解决问题

二.代码内容

运行最大公约数的常用算法,并进行程序的调式与测试,要求程序设计风格良好,并添加异常处理模块(如输入非法等)

三.分析

通过对最大公约数四种算法的编程实现,以多组随机数作为测试数据,测试相同功能代码在大数据输入情况下不同算法的时间效率,从而比较这四种算法的优劣性。同时在代码实现过程中了解自己写代码时算法优劣的重要性,思考如何提升代码效率及实现效果。

四.算法构造

1. 辗转相除

设两数为a,b设其中a 做被除数,b做除数,temp为余数1、大数放a中、小数放b中;
求a/b的余数;
若temp=0则b为最大公约数;
如果temp!=0则把b的值给a、temp的值给a;
返回第二步
在这里插入图片描述)在这里插入图片描述

2. 穷举法

对两个正整数a,b如果能在区间[a,0]或[b,0]内能找到一个整数temp能同时被a和b所整除,则temp即为最大公约数。
在这里插入图片描述)在这里插入图片描述

3. 更相减损术

第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
在这里插入图片描述)在这里插入图片描述

4. stein

如果An=Bn,那么An(或Bn)Cn是最大公约数,算法结束
如果An=0,Bn是最大公约数,算法结束
如果Bn=0,An是最大公约数,算法结束
设置A1=A、B1=B和C1=1
如果An和Bn都是偶数,则An+1=An/2,Bn+1=Bn/2,Cn+1=Cn
2(注意,乘2只要把整数左移一位即可,除2只要把整数右移一位即可)
如果An是偶数,Bn不是偶数,则An+1=An/2,Bn+1=Bn,Cn+1=Cn(很显然啦,2不是奇数的约数)
如果Bn是偶数,An不是偶数,则Bn+1=Bn/2,An+1=An,Cn+1=Cn(很显然啦,2不是奇数的约数)
如果An和Bn都不是偶数,则An+1=|An-Bn|/2,Bn+1=min(An,Bn),Cn+1=Cn
n加1,转1
在这里插入图片描述
在这里插入图片描述

五. 算法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/**
*auther:@却水
*edit time:2019-03-07
*@xi'an University of science & technology
*@Software engineering 1703 17408070828

*/



#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <Windows.h>
#define N 5000

using namespace std;
//辗转相除法嵌套调用
int divisor(int a,int b)//最大公约数

{

int temp;
if(a>b)
{
temp=a;a=b;b=temp;
}
while(b!=0)
{
temp=a%b;
a=b;
b=temp;
}

return (a);
}
int multiple(int a,int b)//最小公倍数
{
int divisor(int a,int b);
int temp;
temp=divisor(a,b);
return(a*b/temp);
}

int gcd (int a,int b)//递归调用

{
if(a%b==0)
return b;
else
return gcd(b,a%b);
}


//穷举法
int divisor1(int a,int b)
{
int temp;
temp=(a>b)?b:a;
while(temp>0)
{if(b%temp==0&&a%temp==0)
break;
temp--;
}

return(temp);
}
int multiple1(int a,int b)
{
int p,q,temp;
p=(a>b)?a:b;//较大值
q=(a>b)?b:a;//较小值
temp=p;
while(1)
{
if(p%q==0)
break;
p+=temp;
}

return p;
}
//更相减损术
int gcd1(int a,int b)
{
int i=0,temp,x;
while(a%2==0&&b%2==0)//两数都是偶数
{a/=2;
b/=2;
i++;//计算共有几个2
}
if(a<b)
{
temp=a;
a=b;
b=temp;
}
while(x)
{
x=a-b;
a=(b>x)?b:x;
b=(b<x)?b:x;
if(b==(a-b))
break;
}
if(i=0)
return b;
else
return (int)pow(2,i)*b;//计算更相减损后的乘积

}
//stein
int Stein(unsigned int x,unsigned int y)//返回a,b中的最大公约数

/* return the greatest common divisor of x and y */
{
int factor = 0;
int temp;

if ( x < y )
{
temp = x;
x = y;
y = temp;
}
if ( 0 == y )
{
return 0;
}
while ( x != y )
{
if ( x & 0x1 )
{//x为偶数
if ( y & 0x1 )
{/* when x and y are both odd */
y = ( x - y ) >> 1;
x -= y;
}
else
{/* X为偶数y为奇数 */
y >>= 1;
}
}
else
{/* x为奇数 */
if ( y & 0x1 )
{/* x为奇数y为偶数 */
x >>= 1;
if ( x < y )
{
temp = x;
x = y;
y = temp;
}
}
else
{/* when x and y are both even */
x >>= 1;
y >>= 1;
++factor;
}
}
}
return ( x << factor );

}


int gcd_run(int u,int v)//stein递归
{
if (u == 0) return v;
if (v == 0) return u;
// look for factors of 2
if (~u & 1) // u is even
{
if (v & 1) // v is odd
return gcd(u >> 1, v);
else // both u and v are even
return gcd(u >> 1, v >> 1) << 1;
}
if (~v & 1) // u is odd, v is even
return gcd(u, v >> 1);
// reduce larger argument
if (u > v)
return gcd((u - v) >> 1, v);
return gcd((v - u) >> 1, u);
}
void main()
{
int i,a;
cout<<"请输入测试数据组数"<<endl;
/*
数据异常处理

*/
int ret;
ret = scanf("%d",&a);
while (ret != 1)
{
while (getchar() != '\n');
printf("error input,please again.\n");
ret = scanf("%d",&a);
}//直到输入的值为整数

int arr[N] ;
srand((unsigned)time(NULL));//调用time函数来获取随机数
for (i = 0; i< N; i++)
{
arr[i] = rand(); //随机数组


}cout<<" 检验数据是否随机"<<endl;
for(i=0;i<10;i++)
{
cout<<" ********"<<arr[i]<<"********"<<endl;
}
//计时函数
double time=0;
double counts=0;
LARGE_INTEGER nFreq;
LARGE_INTEGER nBeginTime;
LARGE_INTEGER nEndTime;
QueryPerformanceFrequency(&nFreq);

QueryPerformanceCounter(&nBeginTime);
for(i=0;i<2*a;i++){
divisor(arr[i],arr[i+2]);//调用辗转相除法函数
}
QueryPerformanceCounter(&nEndTime);//停止计时
time=(double)(nEndTime.QuadPart-nBeginTime.QuadPart)/(double)nFreq.QuadPart;//计算程序执行时间单位为s
cout<<"辗转相除法(非递归)时间为:"<<time*1000<<"ms"<<endl;

QueryPerformanceCounter(&nBeginTime);
for(i=0;i<2*a;i++)
{
gcd(arr[i],arr[i+2]);//辗转相除递归调用

}
QueryPerformanceCounter(&nEndTime);//停止计时
time=(double)(nEndTime.QuadPart-nBeginTime.QuadPart)/(double)nFreq.QuadPart;//计算程序执行时间单位为s
cout<<"辗转相除法(递归)时间为:"<<time*1000<<"ms"<<endl;

QueryPerformanceCounter(&nBeginTime);
for(i=0;i<2*a;i++)
{
divisor1(arr[i],arr[i+2]);//穷举法函数调用QueryPerformanceCounter(&nEndTime);//停止计时

}time=(double)(nEndTime.QuadPart-nBeginTime.QuadPart)/(double)nFreq.QuadPart;//计算程序执行时间单位为s
cout<<"穷举法时间为:"<<(-time*1000)<<"ms"<<endl;

QueryPerformanceCounter(&nBeginTime);
for(i=0;i<2*a;i++)
{
gcd1(arr[i],arr[i+2]);//更相减损术算法

}
QueryPerformanceCounter(&nEndTime);//停止计时
time=(double)(nEndTime.QuadPart-nBeginTime.QuadPart)/(double)nFreq.QuadPart;//计算程序执行时间单位为s
cout<<"更相减损术算法时间为:"<<time*1000<<"ms"<<endl;

QueryPerformanceCounter(&nBeginTime);
for(i=0;i<2*a;i++)
{
Stein(arr[i],arr[i+2]);//Stein
}
QueryPerformanceCounter(&nEndTime);//停止计时
time=(double)(nEndTime.QuadPart-nBeginTime.QuadPart)/(double)nFreq.QuadPart;//计算程序执行时间单位为s
cout<<"Stein算法时间为:"<<time*1000<<"ms"<<endl;

QueryPerformanceCounter(&nBeginTime);
for(i=0;i<2*a;i++)
{i+=1;gcd_run(arr[i],arr[i+2]);//Stein递归调用
}
QueryPerformanceCounter(&nEndTime);//停止计时
time=(double)(nEndTime.QuadPart-nBeginTime.QuadPart)/(double)nFreq.QuadPart;//计算程序执行时间单位为s
cout<<"Stein(递归)时间为:"<<time*1000<<"ms"<<endl;
}

七. 个人经验总结

本次实验立足算法的代码实现,侧重于编程及算法构造能力,通过对算法时间的统计,清晰明了看到解决相同问题时不同算法的时间效率,为自己写程序使用最优代码时刻提醒。
收获:熟悉了C语言随机数生成机制及函数调用方法掌握了时间计算的三种函数,如头文件#include<time.h>下的clock函数#include<windows.h>下的gettimeofday(&start, NULL)和QueryPerformanceCounter(&nEndTime)
函数。在随机数生成方面因为以前做课设时不够认真掌握不足,所以在本次程序设计中花费了不少功夫,时间。虽然花费了时间但是收获很大,补上了前面应该学却没学到的东西。在异常处理方面了解到了scanf()返回值的特性,并利用了其函数特性实现了非整数输入的排错功能。
不足之处及改进:冰冻三尺非一日之寒,以前下的功夫不够,以至于编程实践能力欠缺,以后要抓住这样的机会锻炼自己的代码能力及算法设计能力。另外,程序设计方面封装性差,要多学习优秀代码,养成好的编程风格。

三天打鱼两天晒网

题目背景

中国有句俗语叫“三天打鱼两天晒网”。某人从2010年1月1日起开始“三天打鱼两天晒网”,问这个人在以后的某一天中是“打鱼”还是“晒网”。用C或C++语言/java/python实现程序解决问题。

基本要求及提高要求

基本要求:
1.程序风格良好(使用自定义注释模板),提供友好的输入输出。
提高要求:
1.输入数据的正确性验证。
2.使用文件进行数据测试。如将日期 20100101 20111214 等数据保存在 in.txt文件中,程序读入in.dat文件进行判定,并将结果输出至 out.txt文件。

代码编写语言

C++

代码设计思想

1.建立主类,初始化数据元素
2.通过Deal_key函数实现日期的输入与正确性判断
3.函数sumdays()实现输入日期到2010-1-1的天数计算
4.display()函数判断变量days_5的取值来确定工作状态
5.file()函数通过文件流操作实现文件内数值的读入及处理

具体功能实现(代码片段)

1.数据输入及判断正误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
int Date_fish::Deal_key()
{
cout<<"请输入年"<<endl;
cin>>year;
//判断输入的年,月,日是否在规定的范围
if (year<2010||year>2019) //判断年
{
cout<<"年份输入错误,请输入2010-2019范围的年份(包含2010和2019)"<<endl;

cin>>year;
}
cout<<"请输入月"<<endl;
cin >>month;
if(month<=0||month>12) //判断月
{
cout<<"月份输入错误,请输入1-12范围的月份(包含1和12)"<<endl;
cin>>month;
}


cout<<"请输入日"<<endl;
cin>>day;

if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)//判断日
{
if(day>31||day<=0)//判断大月
{cout<<"天数输入错误,请输入改后的正常天数"<<endl;
cin>>day;
}
}
else if(month!=2)//判断小月
if(day>30||day<=0)
{{cout<<"您输入的日期有误,请重新输入"<<endl;
cin>>day;}
}
else if(((year%4==0&&year%100!=0)||year%400==0))//判断闰年2月
{
if(day>29||day<=0)
{cout<<"您输入的日期有误,请重新输入"<<endl;
cin>>day;
}

}
else
{
if(day>28||day<=0)
{cout<<"您输入的日期有误,请重新输入"<<endl;
cin>>day;}
return 0;
}
}
2.距离指定日期的天数计算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void Date_fish::sumdays() //判断平闰年函数并计算天数
{
int YEAR_0=2010; //定义初始变量YEAR_0为2010
for (YEAR_0;YEAR_0<year;YEAR_0++) //距当前年份几年,循环几次
{
if((year%400==0)||(year%4==0&&year%100!=0)) //当前年份为闰年,||前为世纪年判断,||后为普通年
{
sum+=366;//闰年,总天数加366天
}
else//为平年
{
sum+=365; //平年,总天数加365天
}
}
for(int i=0;i<month-1;i++)
{
if((year%400==0)||(year%4==0&&year%100!=0))
sum+=special_month_day[i]; //加当前月份的天数
else
sum+=normal_month_day[i];
}
sum+=day; //总天数
cout<<"到2010-01-01的总天数为:";
cout<<sum<<endl;

days_5=sum%5;//除5取余
sum=0;//初始化
//return days_5;
}
3.输入日期工作状态判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Date_fish::display()
{

if (days_5>=1&&days_5<4)//余数1,2,3
{
//余数1,2,3打鱼
cout<<"这天在打鱼"<<endl;
}
else
{
//晒网
cout<<"这天在晒网"<<endl;
}
//return days_5;
}
4.文件操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int Date_fish::file()

{int a[3];//数组实现txt文档中三个值的传回
ifstream infile("in.txt",ios::in);
if(!infile)
{cerr<<"open in.txt error!"<<endl;
exit(1);
}
infile>>a[0]>>a[1]>>a[2];
year=a[0]; month=a[1]; day=a[2];

sumdays();//接收计算后的days_5
//
ofstream outfile("out.txt",ios::out);

{if (days_5>0&&days_5<4)
{
outfile<<year<<"."<<month<<"."<<day<<"该天打鱼"<<endl; //余数为1或2或3,将打鱼的信息写入out文件中
}
else
{
outfile<<year<<"."<<month<<"."<<day<<"该天晒网"<<endl;//余数为0或4,将晒网的信息写入out文件中

}
}
//关闭文件
infile.close();
outfile.close();
return 0;
}

**文件操作解释说明

为方便使用.txt文档中保存的输入数据,分别将“year”,“month”,“day”放在一个数组中,以空格隔开,达到为程序写入数值的功能。

详细代码(可编译执行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*~
#@**xi'an university of science & technology**
#@Software engineering 1703
#@17408070828
~*/

#include<iostream>
#include<fstream>
#include<stdlib.h>
using namespace std;
class Date_fish{
public :
int year; //年
int month; //月
int day; //日
Date_fish();//构造函数
int file(); //对文件中的信息进行处理
int Deal_key();//对从键盘输入的信息进行处理
int Choose;////键盘读入或文件读入的选择标志
void sumdays();//判断闰年平年
void display();//工作类型
int days_5; //除5的余数
int sum; //距2010年1月1日的总天数
int normal_month_day[12]; //平年每月的天数
int special_month_day[12];
};
Date_fish::Date_fish () //构造函数初始化
{
Choose=0; //键盘读入或文件读入的选择标志
sum=0;
days_5=0;
year=0;
month=0;
day=0;
int normal_month_day[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int special_month_day[12]={31,29,31,30,31,30,31,31,30,31,30,31};//初始平闰年各月份天数

}
int Date_fish::Deal_key()
{
cout<<"请输入年"<<endl;
cin>>year;
//判断输入的年,月,日是否在规定的范围
if (year<2010||year>2019) //判断年
{
cout<<"年份输入错误,请输入2010-2019范围的年份(包含2010和2019)"<<endl;

cin>>year;
}
cout<<"请输入月"<<endl;
cin >>month;
if(month<=0||month>12) //判断月
{
cout<<"月份输入错误,请输入1-12范围的月份(包含1和12)"<<endl;
cin>>month;
}


cout<<"请输入日"<<endl;
cin>>day;

if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)//判断日

{
if(day>31||day<=0)//判断大月
{cout<<"天数输入错误,请输入改后的正常天数"<<endl;
cin>>day;
}

}
else if(month!=2)//判断小月
if(day>30||day<=0)
{{cout<<"您输入的日期有误,请重新输入"<<endl;
cin>>day;}


}
else if(((year%4==0&&year%100!=0)||year%400==0))//判断闰年2月
{
if(day>29||day<=0)
{cout<<"您输入的日期有误,请重新输入"<<endl;
cin>>day;
}

}
else
{
if(day>28||day<=0)
{cout<<"您输入的日期有误,请重新输入"<<endl;
cin>>day;}
return 0;
}
}
void Date_fish::sumdays() //判断平闰年函数并计算天数
{
int YEAR_0=2010; //定义初始变量YEAR_0为2010
for (YEAR_0;YEAR_0<year;YEAR_0++) //距当前年份几年,循环几次
{
if((year%400==0)||(year%4==0&&year%100!=0)) //当前年份为闰年,||前为世纪年判断,||后为普通年
{
sum+=366;//闰年,总天数加366天
}
else//为平年
{
sum+=365; //平年,总天数加365天
}
}
for(int i=0;i<month-1;i++)
{
if((year%400==0)||(year%4==0&&year%100!=0))
sum+=special_month_day[i]; //加当前月份的天数
else
sum+=normal_month_day[i];
}
sum+=day; //总天数
cout<<"到2010-01-01的总天数为:";
cout<<sum<<endl;

days_5=sum%5;//除5取余
sum=0;//初始化
//return days_5;
}


void Date_fish::display()
{

if (days_5>=1&&days_5<4)//余数1,2,3
{
//余数1,2,3打鱼
cout<<"这天在打鱼"<<endl;
}
else
{
//晒网
cout<<"这天在晒网"<<endl;
}
//return days_5;
}

int Date_fish::file()

{int a[3];//数组实现txt文档中三个值的传回
ifstream infile("in.txt",ios::in);
if(!infile)
{cerr<<"open in.txt error!"<<endl;
exit(1);
}
infile>>a[0]>>a[1]>>a[2];
year=a[0]; month=a[1]; day=a[2];

sumdays();//接收计算后的days_5
//
ofstream outfile("out.txt",ios::out);

{if (days_5>0&&days_5<4)
{
outfile<<year<<"."<<month<<"."<<day<<"该天打鱼"<<endl; //余数为1或2或3,将打鱼的信息写入out文件中
}
else
{
outfile<<year<<"."<<month<<"."<<day<<"该天晒网"<<endl;//余数为0或4,将晒网的信息写入out文件中

}
}
//关闭文件
infile.close();
outfile.close();
return 0;
}
int main()
{
Date_fish m;
cout<<"请选择日期读取方式:"<<endl;
cout<<"*******0为从键盘读取*******"<<endl;
cout<<"*******1为从文件读取*******"<<endl;
cin>>m.Choose;

//
switch(m.Choose)
{
case 0:
{m.Deal_key();
m.sumdays();
m.display();}
break;
case 1:
m.file();
break;
}
return 0;
}
/*-----------
auther @却水*/

个人总结

在完成本次题目时个人存在的问题
1.编程基础较差,程序遇到bug解决能力较弱 ,解决时间较长
2.代码风格较乱,还需改进
3.设计算法较为繁琐,判断日期时天的判断if—else语句繁琐,刚开始的算法较简洁但是出现计算时间错误,无奈之下只能改为if嵌套语句
4.c++语法不够熟练,尤其文件操作生疏,导致文件操作方面花费了大量的时间
5.因理解题目要求不到位,在文件的操作方面走了很多弯路

在本次完成题目时的收获
1.重温C++语法
2.学习了以前忽略的C语言文件操作
3.通过不断调试错误,对错误的出现有了一些新的认识,如,顺序结构影响程序执行的逻辑,嵌套语句的使用不当导致程序异常
4.做出成果增强了学习其他语言的信心及决心

流程图

  • © 2019-2020 卻水
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信