C++程序设计-第15周 数据结构扩展与GUI开发体验

简介: 课程首页地址:http://blog.csdn.net/sxhelijian/article/details/7910565【目的】1. 体验用面向对象的方法操作数组和动态链表2. 体验窗口程序的实现第一部分 引言  大学中的学习死守着课本非常的没有劲。我不是说课本和课堂没用,而是说在课内的学习之余要有所拓展和扩充。大学的课程(和课本)成为一个体系,受到各种因素的制约,势必会形成一个框框

课程首页地址:http://blog.csdn.net/sxhelijian/article/details/7910565


【目的】

1. 体验用面向对象的方法操作数组和动态链表
2. 体验窗口程序的实现

第一部分 引言
  大学中的学习死守着课本非常的没有劲。我不是说课本和课堂没用,而是说在课内的学习之余要有所拓展和扩充。大学的课程(和课本)成为一个体系,受到各种因素的制约,势必会形成一个框框,所涉及的内容可能就会形成“铁路警察,各管一段”的局面。课程和课本是有局限的,采用的是“统一”的体系,而各人形成自己的知识体系却是各有特色的。这是大学学习自由的一部分。
  大学生对课程的学习,要习惯于超越“老师讲过的”和“考试要考的”,按照学科(而不是有限学时的课程)和工程需求(而不是仅某门课程中狭窄的知识面)去学,要找到除了考试以外的目标。这个寻找和转变的过程中可能会遇到不少的困难,但却是必须的。其实,转变其实也并不难,也没有诀窍,尝试、体验、总结,直至将新的状态成为自然。
  本周的任务就基于这样的考虑。项目1-3体验用面向对象的方法操作数组和动态链表,代表的是将来在工程中更实用的对数据的操纵方法,项目4体验利用VS2008或VC++6.0中提供的向导,体验窗口程序的开发,而后会发现,我们在C++程序设计中所学的,也正是编程中的核心。


第二部分 实践项目
【项目1】建立专门的数组类处理有关数组的操作
  数组是几乎所支持的组织数据的方法。C和C++对数组类型提供了内置支持,使我们利用数组实现软件中需要的各种实用的功能。但是,这种支持仅限于用来读写单个元素的机制。C++不支持数组的抽象abstraction,也不支持对整个数组的操作。例如:把一个数组赋值给另外一个数组,对两个数组进行相等比较或者想知道数组的大小size,等等。对C++而言,数组是从C语言中继承来的,它反映了数据与对其进行操作的算法的分离,有浓厚的过程化程序设计的特征。数组并不是C++语言的一等公民。所以在实际项目中,对一个C++程序员,更多的是使用标准库中提供的Vector类型实现数组功能。这个任务也将从面向对象角度重新审视和理解数组,进而扫清自学Vector等标准类中可能存在的障碍。
  在下面代码的基础上,完成支持数组操作的类的设计,增强C++内置数组类型功能。

class MyArray
{
private:
    int *arr;		//用于存放动态分配的数组内存首地址
    int size;		//数组大小
public:
    MyArray(int sz=50);
    MyArray(int a[],int sz);	//由一个内置类型的数组初始化
    MyArray(const MyArray &A);	//复制构造函数
    ~MyArray(void);				//析构函数,注意释放空间
    MyArray&operator =(const MyArray &A); //重载“=”使得数组对象可以整体赋值
    bool operator == (MyArray& A);	//重载==,使得Array对象能整体判断两个数组是否相等(size相等且对应元素相等)
    friend ostream& operator << (ostream& out,MyArray& A);	//重载<<,输出数组
    int GetSize(void) const;	//取数组大小;
};
//以下为类成员函数的定义
……
//测试函数
int main()
{
    int a[10]= {1,2,3,4,5,6,7,8,9,10};
    int b[10]= {4,5,6,7,8,9,10,11,12,13};
    MyArray arr1(a,10);  //测试用内置的数组初始化新定义的数组对象
    MyArray arr2(b,10);
    MyArray arr3(10);   //测试只指定大小的新数组对象的初始化
    cout<<arr1;    //测试对<<的重载
    cout<<arr2;    //测试对<<的重载
    cout<<arr3;    //测试对<<的重载
    cout<<"The size of arr1 is: "<<arr1.GetSize()<<endl;   //测试GetSize()成员函数
    return 0;
}

【项目1扩展1(选做)】在MyArray基础上增加下面的成员或友元函数,扩充MyArray类的功能,并修改main函数完成测试。
//重载[],使得Array对象也可以如C++普通数组一样,用a[i]形式取出值【选做】
int& operator[](int i);		
//重载+,使两个Array对象可以整体相加(前提大小相等)【选做】
MyArray operator + (MyArray& A);
//修改数组的大小,如果sz大于数组的原大小,增加的元素初始为;如果sz大于数组的原大小,舍弃后面的元素【选做】
void Resize(int sz);

【项目1扩展2(选做)】规定MyArray只能处理元素为整型的数据未免太弱了,请设计成模板类,使之适应各种类型(事实上,C++增加的标准类对些类情况均设计成了模板类)。
【项目1扩展3(选做)】可以施加于数组的操作还有很多,例如最经典的排序,还有求最大、最小、查找某一元素、截取其中的片段(取从第5个互第10个之间的所有元素,可以形成新的数组对象)、向量乘法,……。将这些操作构造为类的成员函数,开始拓展之旅吧!


【项目2】建立专门的链表类处理有关动态链表的操作
  动态链表也是程序设计中的一种非常有用的数据结构。可以说,是否能够理解有关操作的原理,决定了你是否有资格称为“科班”出身。在后续的专业基础课中,相关的内容还会从不同的角度,反复地认识,反复地实践。不过,在现阶段多些体验,也是很有必要的了。
  先阅读下面的程序,回顾一下动态链表,阅读程序过程中,请用笔画一画形成链表的过程中指针值的变化。
#include <iostream> 
using namespace std;
struct Student
{	int num;
	double score;
	struct Student *next;
};
int main( )
{	Student *head=NULL,*p,*q;
	//建立动态链表
	for(int i=0;i<3;i++)
	{
		p = new Student;
		cin>>p->num>>p->score;
		p->next=NULL;
		if (i==0) head=p;
		else q->next=p;
		q=p;
	}
	//输出动态链表
	p=head;
	while(p!=NULL)
	{	cout<<p->num<<" "<<p->score<<endl;   
		p=p->next;
	}
	return 0;
}

  上面一段代码产生的链表形如:

  

  现在我们通过下面的任务,用面向对象的程序设计的思维看待最简单的动态链表,初步体验有关的操作。

  现在,请在已有代码的基础上完善程序,完成动态链表的简单操作,程序运行的截图供参考。

class Student  //结点类
{
public:
	Student(int n,double s){num=n;score=s;next=NULL;}
	~Student();
	Student *next;   //指向下一个结点
	int num;
	double score;
};


class MyList  //链表类
{
public:
	MyList(){head=NULL;}
	MyList(int n,double s); //以Student(n,s)作为单结点的链表
	~MyList();
	int display();  //输出链表,返回值为链表中的结点数
	void insert(int n,double s);  //插入:将Student(n,s)结点插入链表,该结点作为第一个结点
	void append(int n,double s);  //追加:将Student(n,s)结点插入链表,该结点作为最后一个结点
	void cat(MyList &il); //将链表il连接到当前对象的后面
	int length();  //返回链表中的结点数
private:
	Student *head;   //链表的头结点
};
//以下为类成员函数的定义
……
//测试函数
int main()
{
	int n;
	double s;
	MyList head1;
	cout<<"input head1: "<<endl;  //输入head1链表
	for(int i=0;i<3;i++)
	{
		cin>>n>>s;
		head1.insert(n,s);  //通过“插入”的方式
	}
	cout<<"head1: "<<endl; //输出head1
	head1.display();


	MyList head2(1001,98.4);  //建立head2链表
	head2.append(1002,73.5);  //通过“追加”的方式增加结点
	head2.append(1003,92.8);
	head2.append(1004,99.7);
	cout<<"head2: "<<endl;   //输出head2
	head2.display();


	head2.cat(head1);   //把head1追加到head2后面
	cout<<"length of head2 after cat: "<<head2.length()<<endl;
	cout<<"head2 after cat: "<<endl;   //显示追加后的结果
	head2.display();
	return 0;
}
  运行结果示例:

  

【项目2扩展一(选做)】项目2中的结点只处理包含包含学号和分数的学生信息。如何将之用于其他应用?结点类Students也可换作描述其他事物的类。请设计建立一个动态链表,其中有5个结点,分别描述5个三角形,从头结点开始,逐个输出三角形的信息。
【项目2扩展二(选做)】上面的处理,仍然不够抽象,所以,只能就事论事地做,这是设计的大忌。实际上,结点的类型可以定义为以下模板类:
template <class T>
class Node
{     
public:
	Node *next;
	T data;
};
  这样,“一劳永逸”地解决了data的类型,只要在定义类时,对T进行实例化即可。在这里,T类型中也不需要涉及有关链表中指针的内容。
  请按这种思路重写程序,为了测试,在main()函数中建立一个MyArray<double>型对象进行测试。另外,再建立一个MyArray<Triangle>型对象进行测试(Triangle为自定义三角形类)。


【项目2扩展三(选做)】本任务实现的是最简单的单向链表中的最基本的操作。从链表的类型上,还可以有双向链表(有头结点和尾结点,方便从前往后和从后往前的访问)、十字链表等,类似的方法可以构造二叉树、多叉树、图(例如,计算机网络结构可以抽象描述为图,社交网络中用户的关系也是图,顶有用的结构)。从操作角度,单链表在插入时,可以让结点保持有序;可以从链表中查找元素;很多的应用中涉及的算法需要借助于数据结构和算法的设计获得最佳的处理性能。关于这方面的内容不再以具体任务的形式给出,在后续的专业基础课中将会逐渐引出。另外,有程序设计基础,同学们是可以自己往前走一走,找相关的教材和书籍(数据结构、算法类)看一看,是否能依靠自己的力量往前走一走了。


【项目3】Josephus(约瑟夫环)问题

  n个小孩子围成一圈,从第一个小孩子开始顺时针方向数数字,到第m个小孩子离开,这样反反复复,最终只剩下一个小孩子,求第几个小孩子留下?
  提示:约瑟夫环即是一个首尾相连的链表,在建立好这个环以后,从头结点开始,每次间隔m孩子删除一个结点,直至只余下一个结点(删除了n-1个)。

  
  参考下面的代码,也可以自行设计类。

//链表结点kid,其中number为这个人的编号
struct kid
{
    int number;
    kid *next;
};


//约瑟夫环类
class joseph_ring
{
private:
    int n;//用于存放人数
    int m;//用于存放初始密码
    kid *head;//链表的头结点,初始化时指向1号孩子
public:
    joseph_ring(int nn, int mm);//创建nn个孩子,间隔为mm的约瑟夫环
    ~joseph_ring();
    void show();//运算并输出的成员函数
};
//定义joseph_ring类中的成员函数
……
int main()
{
    int n,m;
    cout<<"n=";
    cin>>n;
    cout<<"m=";
    cin>>m;
    joseph_ring j(n,m);
    j.show();
    return 0;
}

【项目4】窗口程序体验
  阅读 《C++“窗口”程序设计启蒙(之二)》,按照示例的提示完成三角形面积的求解器。如果不方便使用VS2008,要在VC++6.0下进行实践体验,请看 《C++“窗口”程序设计启蒙(之一)》,类似方法完成。
  要完成的任务:
  1、以示例为基础,为应用程序增加求周长的功能;
  2、设计分数类,开发一个窗口式程序,可以完成分数的四则运算。可供参考的一个界面如下图,在报告中展示主要的代码。

  拓展(选做):将上面的输入运算符的编辑框换为下拉列表框,使之只能选“+-*/”。 
  3、(选做)自己设计窗口布局,做一个利息计算器窗口程序。不一定用面向对象的编程(如《 C++“窗口”程序设计启蒙(之一)》),完成功能即可。

  关于项目4的说明:本项目目标仅在于同学们进行体验。从本项目中可以看出利用向导和可视化界面,自动生成部分代码的开发方法,这可以极大的减轻开发工作量,提供了一个应用程序的框架,这是在工程中非常有利的。在专业的开发中,如果用本项目的“拖”控件方式,C#已经提供了更为方便的操作。但这种方法有时缺乏灵活性,开发出的代码没有特色,只能够满足一般性的要求,更专业的开发要求技术人员掌握MFC,直接利用类族中提供的继承关系进行开发。另外,现在已经有不少比MFC更加优秀的类库可供使用,这将作为进一步学习有关的开发技术需要解决的问题。



  

目录
相关文章
|
3月前
|
机器学习/深度学习 算法 算法框架/工具
为什么使用C++进行机器学习开发
C++作为一种高性能语言,在某些性能要求极高或资源受限的场景下也具有非常重要的地位。C++的高效性和对底层硬件的控制能力,使其在大规模机器学习系统中发挥重要作用,尤其是当需要处理大数据或实时响应的系统时。
56 3
|
4月前
|
安全 编译器 C语言
【C++数据结构】string的模拟实现
【C++数据结构】string的模拟实现
|
2月前
|
存储 C++ UED
【实战指南】4步实现C++插件化编程,轻松实现功能定制与扩展
本文介绍了如何通过四步实现C++插件化编程,实现功能定制与扩展。主要内容包括引言、概述、需求分析、设计方案、详细设计、验证和总结。通过动态加载功能模块,实现软件的高度灵活性和可扩展性,支持快速定制和市场变化响应。具体步骤涉及配置文件构建、模块编译、动态库入口实现和主程序加载。验证部分展示了模块加载成功的日志和配置信息。总结中强调了插件化编程的优势及其在多个方面的应用。
336 69
WK
|
1月前
|
机器学习/深度学习 人工智能 算法
那C++适合开发哪些项目
C++ 是一种功能强大、应用广泛的编程语言,适合开发多种类型的项目。它在游戏开发、操作系统、嵌入式系统、科学计算、金融、图形图像处理、数据库管理、网络通信、人工智能、虚拟现实、航空航天等领域都有广泛应用。C++ 以其高性能、内存管理和跨平台兼容性等优势,成为众多开发者的选择。
WK
71 1
|
2月前
|
机器学习/深度学习 存储 人工智能
数据结构在实际开发中的广泛应用
【10月更文挑战第20天】数据结构是软件开发的基础,它们贯穿于各种应用场景中,为解决实际问题提供了有力的支持。不同的数据结构具有不同的特点和优势,开发者需要根据具体需求选择合适的数据结构,以实现高效、可靠的程序设计。
100 7
|
2月前
|
Rust 资源调度 安全
为什么使用 Rust over C++ 进行 IoT 解决方案开发
为什么使用 Rust over C++ 进行 IoT 解决方案开发
84 7
WK
|
1月前
|
开发框架 移动开发 Java
C++和Java哪个更适合开发移动应用
本文对比了C++和Java在移动应用开发中的优劣,从市场需求、学习难度、开发效率、跨平台性和应用领域等方面进行了详细分析。Java在Android开发中占据优势,而C++则适合对性能要求较高的场景。选择应根据具体需求和个人偏好综合考虑。
WK
52 0
WK
|
1月前
|
安全 Java 编译器
C++和Java哪个更适合开发web网站
在Web开发领域,C++和Java各具优势。C++以其高性能、低级控制和跨平台性著称,适用于需要高吞吐量和低延迟的场景,如实时交易系统和在线游戏服务器。Java则凭借其跨平台性、丰富的生态系统和强大的安全性,广泛应用于企业级Web开发,如企业管理系统和电子商务平台。选择时需根据项目需求和技术储备综合考虑。
WK
70 0
|
2月前
|
NoSQL API Redis
如何使用 C++ 开发 Redis 模块
如何使用 C++ 开发 Redis 模块
|
3月前
|
物联网 C# C语言
物联网开发中C、C++和C#哪个更好用
在物联网(IoT)开发中,C、C++和C#各有优缺点,适用场景不同。C语言性能高、资源占用低,适合内存和计算能力有限的嵌入式系统,但开发复杂度高,易出错。C++支持面向对象编程,性能优秀,适用于复杂应用,但学习曲线陡峭,编译时间长。C#易于学习,与.NET框架结合紧密,适合快速开发Windows应用,但性能略低,平台支持有限。选择语言需根据具体项目需求、复杂性和团队技术栈综合考虑。