当前位置:文档之家› 《程序设计与问题求解II》实验指导书

《程序设计与问题求解II》实验指导书

程序设计与问题求解II 实验指导书

《程序设计与问题求解II》教改项目组编

2011年 3月

目录

实验一数组、结构体和函数综合编程 (3)

一、实验目的 (3)

二、实验内容 (3)

三、实验结果与分析 (5)

实验二递归程序设计 (6)

一、实验目的 (6)

二、实验内容 (6)

三、实验结果与分析 (7)

实验三类与对象(一) (8)

一、实验目的 (8)

二、实验内容 (8)

三、实验结果与分析 (11)

实验四类与对象(二) (12)

一、实验目的 (12)

二、实验内容 (12)

三、实验结果与分析 (14)

实验五继承与多态 (15)

一、实验目的 (15)

二、实验内容 (15)

实例讲解: (18)

三、实验结果与分析 (20)

实验六运算符重载和模板类 (21)

一、实验目的 (21)

二、实验内容 (21)

三、实验结果与分析 (22)

实验七流与文件操作编程 (23)

一、实验目的: (23)

二、实验内容: (23)

三、实验结果与分析 (23)

实验八链表编程 (24)

一、实验目的: (24)

二、实验内容: (24)

三、实验结果与分析 (25)

实验一数组、结构体和函数综合编程

一、实验目的

1.复习数组,结构体和函数的相关知识;

2.掌握利用数组存储数据和进行编程的方法;

3.进一步掌握函数的编写。

二、实验内容

1.学生成绩统计

从键盘输入一个班(全班最多不超过30人)学生某门课的成绩,当输入成绩为负值时,输入结束,分别实现下列功能:

(1)统计不及格人数并打印不及格学生名单;

(2)统计成绩在全班平均分及平均分之上的学生人数,并打印这些学生的名单;(3)统计各分数段的学生人数及所占的百分比。

注:将成绩分为六个分数段,60分以下为第0段,60~69为第1段,70~79为第2段,80~89为第3段,90~99为第4段,100分为第5段。

编程要求:

1.较好的用户输入输出提示信息

2.使用子函数来实现上述各个功能,并且要使用结构体数组来实现,该结构体中包括学生学号和成绩

3.最好不要使用全局变量

提示:

typedef tagStudent

{

long num;//学生学号

float score;//学生分数

}Student;

供参考的函数原型如下:

/*函数功能:从键盘输入一个班学生某门课的成绩及其学号

当输入成绩为负值时,输入结束

函数参数:存放学生信息的Student结构体数组

函数返回值:学生总数

*/

int ReadScore(Student stu[]);

/*函数功能:统计不及格人数并打印不及格学生名单

函数参数:存放学生信息的Student结构体数组

整型变量n,存放学生总数

函数返回值:不及格人数

*/

int GetFail(Student stu[], int n);

/*函数功能:计算全班平均分

函数参数:存放学生信息的Student结构体数组,整型变量n,存放学生总数函数返回值:平均分

*/

float GetAver(Student stu[], int n);

/*函数功能:统计成绩在全班平均分及平均分之上的学生人数并打印其学生名单函数参数:存放学生信息的Student结构体数组,整型变量n,存放学生总数函数返回值:成绩在全班平均分及平均分之上的学生人数

*/

int GetAboveAver(Student stu[], int n);

/*函数功能:统计各分数段的学生人数及所占的百分比

函数参数:存放学生信息的Student结构体数组,整型变量n,存放学生总数函数返回值:无

*/

void GetDetail(Student stu[], int n);

2.成绩排名次

某班期末考试科目为数学(MT)、英语(EN)和物理(PH),有最多不超过30人参加考试。要求:

(1)计算每个学生的总分和平均分;

(2)按总分成绩由高到低排出成绩的名次;

(3)打印出名次表,表格内包括学生编号、各科分数、总分和平均分;

(4)任意输入一个学号,能够查找出该学生在班级中的排名及其考试分数

编程要求:

1.较好的用户输入输出提示信息

2.使用子函数来实现上述各个功能

3.必须用结构体数组实现

提示:

设计好存放学生信息的结构体,方便编程。

用函数编程实现计算每个学生的总分;

用函数编程实现按总分由高到低对学生成绩排序

用函数编程实现查找学号为k的学生在班级中的排名名次及相关成绩等信息,找不到时返回-1值

三、实验结果与分析

将源程序、运行结果和分析以及实验中遇到的问题和解决问题的方法,写在实验报告上。

实验二 递归程序设计

一、实验目的

1.学习递归程序的一般设计方法;

2.了解和熟练多参数的递归函数的使用;

3.掌握用递归程序设计方法解决实际问题。

二、实验内容

1.求游戏人员的年龄

有5个人围坐在一起,问第五个人多大年纪,他说比第4个人大2岁;问第4个人,他说比第3个人大2岁;问第3个人,他说比第2个人大2岁;问第2个人,他说比第1个人大2岁。第一个人说自己10岁,问第5个人多大年纪。 提示:此程序为递归问题,递归公式为:

10

(1)()(1)2

(1)

n age n age n n =?=?

-+>?

2.计算最大公约数

利用计算最大公约数的三条性质,用递归方法计算两个整数的最大公约数。 性质1:如果x>y ,则x 和y 的最大公约数与x-y 和y 的最大公约数相同,即

gcd(,)gcd(,)

x y x y y x y =-> 性质2:如果y>x ,则x 和y 的最大公约数与x 和y-x 的最大公约数相同,即

gcd(,)gcd(,)

x y x y x x y =-<

性质3:如果x=y ,则x 和y 的最大公约数与x 值和y 值相同,即gcd(,)x y x y == 注意:上述两个代码的编写都非常简单,在代码编写成功后,需要自己再回忆一下代码的编写过程,复习以前学过的内容,学习代码的调试。 3.整数划分问题

将正整数n 表示成一系列正整数之和:n=n1+n2+…+nk ,其中n1≥n2≥…≥nk ≥1,k ≥1。 正整数n 的这种表示称为正整数n 的划分。求正整数n 的不同划分个数。 例如正整数6有如下10种不同的划分:

5+1; 4+2,4+1+1; 3+3,3+2+1,3+1+1+1; 2+2+2,2+2+1+1,2+1+1+1+1; 1+1+1+1+1+1。

前面的几个例子中,问题本身都具有比较明显的递归关系,因而容易用递归函数直接求解。

在本例中,如果设p(n)为正整数n 的划分数,则难以找到递归关系,因此考虑增加一个自变量:将最大加数n1不大于m 的划分个数记作q(n,m)。可以建立q(n,m)的如下递归关系。

如要求解6的整数划分,即是求q(6,5). 其中n=6,m=5。 编程要求:

(1) 编程求出任意10以内的整数的所有可能划分总数。(必做!) (2) 选作部分:打印输出6的所有划分形式。

三、实验结果与分析

将源程序、运行结果和分析以及实验中遇到的问题和解决问题的方法,写

在实验报告上。

??????

?

>>=<==-+--+=11,1)

,()1,()1,(1),(1),(m n m n m n m n m m n q m n q n n q n n q m n q

实验三类与对象(一)

一、实验目的

1. 初步掌握面向对象的思想,类的封装,多文件项目;

2. 掌握类的概念、类的成员的概念和类的封装性;

3.掌握类对象的定义;

4.理解类的成员的访问控制的含义,公有、私有和保护成员的区别;

5.初步掌握用类和对象编制基于对象的编程;

6.学习检查和调试基于对象的程序;

7. 掌握工程文件的编译方法;

8. 逐步从面向过程编程转到面向对象编程。

二、实验内容

1、验证题目

将下面的程序正确划分到不同的文件中,编译链接运行,观测运行结果与期望是否相符。

时间类:

//mytime.h

#ifndef MYTIME_H_

#define MYTIME_H_

#include

using namespace std;

class Time

{

private:

int hours;

int minutes;

public:

Time();

Time(int h,int m=0);

void AddMin(int m);

void AddHr(int h);

void Reset(int h=0,int m=0);

Time Sum(const Time& t) const;

void Show() const;

};

#endif

//mytime.cpp

#include "mytime.h"

Time::Time()

{

hours=minutes=0;

}

Time::Time(int h,int m)

{

hours=h;

minutes=m;

}

void Time::AddMin(int m)

{

minutes+=m;

hours+=minutes/60;

minutes%=60;

}

void Time::AddHr(int h)

{

hours+=h;

}

void Time::Reset(int h,int m)

{

hours=h;

minutes=m;

}

Time Time::Sum(const Time& t)const

{

Time sum;

sum.minutes=minutes+t.minutes;

sum.hours=hours+t.hours+sum.minutes/60;

sum.minutes%=60;

return sum;

}

void Time::Show()const

{

cout<

cout<

}

//usetime.cpp

#include

using namespace std;

#include "mytime.h"

int main()

{

Time A;

Time B(5,40);

Time C(2,55);

cout<<"A=";

A.Show();

cout<<"B=";

B.Show();

cout<<"C=";

C.Show();

A=B.Sum(C);

cout<<"B.Sum(C)=";

A.Show();

return 0;

}

2、找错误

请检查下面程序,找出其中的错误(先不要上机,自己先检查),并改正之。然后上机调试,使之能正常运行,运行时从键盘输入时、分、秒的值,检查输出是否正确。

#include

using namespace std;

class Time

{

int hour;

int minute;

int sec;

void set_time();

void show_time();

};

Time t;

int main( )

{

set_time();

show_time();

return 0;

}

void set_time()

{

cin>>t.hour;

cin>>t.minute;

cin>>t.sec;

}

void show_time()

{

cout<

}

3、应用类和对象编程求出长方体的体积

需要求三个长方柱的体积,请编写一个基于对象的程序,数据成员包括length(长)、width(宽)、height(高)。

要求用成员函数实现以下功能:

(1)、由键盘输入三个长方柱的长、宽、高;

(2)、计算三个长方柱的体积;

(3)、输出三个长方柱的体积;

三、实验结果与分析

将源程序、运行结果和分析以及实验中遇到的问题和解决问题的方法,写在实验报告上。

实验四类与对象(二)

一、实验目的

1.进一步加深对类和对象的理解;

2.掌握构造函数和析构函数的含义与作用、定义方式和使用方法,能够根据要求正确定义和重载构造函数。能够根据给定的要求定义类并实现类的成员函数;3.掌握友元函数的含义和使用,友元函数和成员函数的区别。

二、实验内容

1、设计一个类Cdateinfo,其私有数据成员有year(年)、month(月)、day(日),要求其满足下述要求。

(1)要求有一个无参数的构造函数,其初始的年、月、日分别为:2000,1,1。(2)要求有一个带参数的构造函数,起参数分别对应年、月、日。

(3)要求用一个成员函数实现日期的设置。

(4)要求用一个成员函数实现日期的输出。

在上述程序的基础上将(1)和(2)的两个构造函数改为一个带默认参数的构造函数,并使年、月、日的默认值分别为:2000,1,1。

2、分析以下程序,掌握程序的运行过程,进一步掌握普通构造函数、复制构造函数和析构函数:

#include

using namespace std;

class Box

{public:

Box(int=10,int=10,int=10);

Box::Box(Box& b);

int volume( );

private:

int height;

int width;

int length;

};

Box::Box(Box& b)

{

height = b.height;

width = b.width;

length = b.length;

cout<<"copy constructor"<

Box::Box(int h,int w,int len)

{

height=h;

width=w;

length=len;

cout<<"constructor"<

}

int Box::volume( )

{

return(height*width*length);

}

void func1(Box b)

{

cout<

}

Box func2( )

{

Box b(20,30);

return b;

}

int main( )

{

Box box1(10,20,10);

Box box2(box1);

cout<

func1(box1);

Box box3;

box3=func2();

cout<

return 0;

}

3、分析和运行下面的程序,注意友元函数dist(point a,point b)的作用。将友元函数dist(point a,point b)改为Point类的公有成员函数Point ::dist(point &b),请修改主函数中的相应代码,使程序功能不变。

#include

#include

using namespace std;

class Point

{

double x;

double y;

public:

Point(double a,double b)

{

x=a;

y=b;

}

friend double dist(Point a,Point b);

};

double dist(Point a,Point b)

{

return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));

}

void main()

{

Point p1(1,2);

Point p2(5,2);

cout<

}

三、实验结果与分析

将源程序、运行结果和分析以及实验中遇到的问题和解决问题的方法,写在实验报告上。

实验五继承与多态

一、实验目的

1.理解继承的含义,掌握派生类的定义方法和实现;

2.理解公有继承下基类成员对派生类成员和派生类对象的可见性,能正确地访问继承层次中的各种类成员;

3.理解保护成员在继承中的作用,能够在适当的时候选择使用保护成员以便派生类成员可以访问基类的部分非公开的成员;

4.理解虚函数在类的继承层次中的作用,虚函数的引入对程序运行时的影响,能够对使用虚函数的简单程序写出程序结果。

二、实验内容

1、编写一个学生和教师数据输入和显示程序,要求:

学生数据有编号、姓名、班级和成绩,教师数据有编号、姓名、职称和部门。要求将编号、姓名输入和显示设计成一个类person,并作为学生数据操作类student和教师类数据操作类teacher的基类。

2、利用虚函数实现的多态性来求四种几何图形的面积之和。这四种几何图形是:三角形、矩形、正方形和圆。几何图形的类型可以通过构造函数或通过成员函数来设置。

为设置几何图形的数据并求出几何图形的面积,需要定义一个包含两个虚函数的类:

class Shape

{public:

virtual float Area( void) =0; //求面积

virtual void Setdata(float ,float =0) =0; //设置图形数据

};

因面积的计算依赖于几何图形,故在类中只能定义一个纯虚函数Area。同理,设置几何图形数据的函数Setdata也只能定义为虚函数。

把这个基类派生出其它几何图形类。如派生出的三角形类为:

class Triangle:public Shape

{ float W,H; //三角形边长为W,高为H public:

Triangle(float w=0,float h=0){ W=w; H = h; }

float Area( void){ return W*H/2; }

void Setdata(float w,float h=0){ W=w; H = h; }

};

在派生类中定义了基类中两个虚函数的实现。为了实现求面积和设置数据的多态性,必须定义一个类,该类中定义一个指向基类Shape的指针数组,其元素分别指向由基类Shape派生出的不同的几何图形类,并完成求出所有几何图形面积之和,以及设置参数的函数。

一个完整的参考程序如下:

#include

#include

class Shape

{public:

virtual float Area( void) =0; //虚函数

virtual void Setdata(float ,float =0) =0; //虚函数

};

class Triangle:public Shape

{ float W,H; //三角形边长为W,高为H

public:

Triangle(float w=0,float h=0) { W=w;H = h; }

float Area( void) { return W*H/2; } //定义虚函数

void Setdata(float w,float h=0) { W=w; H = h; } //定义虚函数

};

class Rectangle:public Shape

{ float W,H; //矩形边长为W,高为H

public:

Rectangle(float w=0,float h=0){ W=w; H = h; }

float Area( void) {return W*H; } //定义虚函数

void Setdata(float w,float h=0) {W=w; H = h;} //定义虚函数};

class Square:public Shape

{ float S; //正方形边长S

public:

Square(float a=0) {S=a; }

float Area( void) {return S*S/2; } //定义虚函数

void Setdata(float w,float h=0) {S=w; } //定义虚函数

};

class Circle:public Shape

{ float R; //圆的半径为R

public:

Circle(float r=0) {R=r; }

float Area( void) {return 3.1415926*R *R ; } //定义虚函数void Setdata(float w,float h=0) {R=w; } //定义虚函数

};

class Compute

{ Shape **s; //指向基类的指针数组

public:

Compute()

{ s= new Shape *[4]; //给几何图形设置参数

s[0] = new Triangle(3,4);

s[1] = new Rectangle(6,8);

s[2] = new Square(6.5);

s[3] = new Circle(5.5);

}

float SumArea(void ) ;

~Compute();

void Setdata(int n, float a,float b=0) //A

{ s[n]->Setdata(a,b); } //B

};

Compute::~Compute() //释放动态分配的存储空间

{ for(int i= 0; i<4; i++) delete s[i];

delete [ ] s;

}

float Compute::SumArea(void )

{ float sum =0;

for( int i =0; i< 4; i++)

sum += s[i]->Area(); //通过基类指针实现多态性return sum;

}

void main(void )

{ Compute a;

cout<<"四种几何图形的面积="<

a.Setdata(2,10); //设置正方形的边长

cout<<"四种几何图形的面积="<

a.Setdata(0, 10,12); //设置三角形的边长和高

cout<<"四种几何图形的面积="<

a.Setdata(1,2,5); //设置正方形的长和宽

cout<<"四种几何图形的面积="<

a.Setdata(3,15.5);

cout<<"四种几何图形的面积="<

}

程序中A行的Setdata函数属于函数重载,它不是虚函数。该函数中的B行通过基类指针实现多态性。

实例讲解:

#include

using std::cout;

using std::endl;

class BaseClass{

public:

/*virtual*/ void print() { //请去掉注释后查看结果有何不同, 并思考为什么?

//virtual 只能在声明时使用, 在定义时(cpp中)不能有!

cout<<"AAA"<

}

};

class SubClass: public BaseClass{

public:

void print(){

cout<<"BBB"<

}

};

void main(){

BaseClass baseClass, *baseClass_p=0;

SubClass subClass;

//SubClass sub = baseClass; //编译错误, 因为父类对象(右值)不是子类类型(左值)

//同样子类指针不能指向父类对象, 也不能将父类对象强制转换为子类对象,很容易造成内存访问错误

//BaseClass base = subClass; //编译正确, 因为子类对象(右值) 是父类类型(左值)

baseClass.print(); //打印 AAA

subClass.print(); //打印 BBB

baseClass_p = & baseClass; //父类指针指向父类对象

baseClass_p->print(); //virtual: AAA; !virtual: AAA

baseClass_p = & subClass; //父类指针指向子类对象

baseClass_p->print(); //virtual: BBB; !virtual: AAA

}

解释:

override 与 overload

override 可以理解为覆盖, 重定义, 重写, 是指子类可以写一个函数原型(包括参数列表, 返回值类型)

与父类一模一样的成员方法,

overload 可以理解为重载, 它不涉及类的层次, 它是指可以通过参数列表的不同同时写出多个同名函数!

上述的 baseClass.print(); subClass.print(); 均可以属于 override; virtual的含义:

不用virtual的话, 父类指针指向子类对象时, 它会根据指针的类型确定调用父类还是子类的方法;

若用virtual的话, 父类指针指向子列对象时, 它会根据指针所指对象的类型(而非指针的类型)来确定该调用子类还是父类的方法!!

三、实验结果与分析

将源程序、运行结果和分析以及实验中遇到的问题和解决问题的方法,写在实验报告上。

相关主题
文本预览
相关文档 最新文档