Accelerated C++学习笔记4—<使用批量数据>

第3章 使用批量数据


之前第二章我们讨论的都只不过是读一个字符串并且把它输出,有时候装饰一下输出的格式,在这章中我们要讨论跟多的处理批量数据的方法。
1、编写假设有一门课程中,每一个学生的总成绩都由期末考试成绩(40%),期中考试成绩(20%)和家庭作业的平均成绩(40%)构成。
<span style="font-family:KaiTi_GB2312;">// lesson3_1.cpp : 定义控制台应用程序的入口点。
//功能:假设有一门课程中,每一个学生的总成绩都由期末考试成绩(40%),期中考试成绩(20%)和家庭作业的平均成绩(40%)构成。
//时间:2014.5.8

#include "stdafx.h"
#include "iomanip"
#include "ios"
#include "iostream"
#include "string"
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
	//请求输入并读入学生的姓名
	cout << "Please enter your first name: ";
	string name;
	cin >> name;
	cout << "Hello, " << name << "!" << endl;

	//请求输入并读入期中和期末考试成绩
	cout << "Please enter your midterm and final exam grades: ";
	double midterm, final;
	cin >> midterm >> final;

	//请求输入家庭作业成绩
	cout << "Enter all your homework grades, "
		"followed by end-of-file: ";

	//到目前为止,读入的家庭作业成绩的个数及总和
	int count = 0;
	double sum = 0;

	//把家庭作业的成绩读到变量x中
	double x;

	//不变式:
	//到目前为止,我们已经读到了count个家庭作业成绩,
	//而且sum等于头count个成绩的总和
	while (cin >> x)
	{
		++count;
		sum += x;
	}

	//输出结果
	streamsize prec = cout.precision();
	cout << "Your final grade is " << setprecision(3)
		 << 0.2 * midterm + 0.4 * final + 0.4 * sum/count
		 << setprecision(prec) << endl;

	return 0;
}
</span>

运行结果:


程序说明:
1)声明指令中<iomanip>与<ios>我们不太熟悉,头文件<ios>定义了一个类型streamsize,输入/输出库就是用这个类型表示长度的;头文件<iomanip>定义了控制器setprecision,这个控制器可以绕过我们指明输出所包含的有效位数。
2)这里请求请求输入学生的家庭作业成绩,会连续地读入家庭作业成绩,知道遇到一个文件结束的标志为止(windows系统一般按ctrl+z键就可以了)
3)在程序中如果两个字符串直接量仅仅是用空白符隔开的话,那么这些字符串直接量就会被自动连接到一起。
<span style="font-family:KaiTi_GB2312;">	//请求输入家庭作业成绩
	cout << "Enter all your homework grades, "
		"followed by end-of-file: ";</span>

4)检测输入
<span style="font-family:KaiTi_GB2312;">while(cin >> x){……}
if(cin >> x){}//请求cin>>x的值等价于先执行cin>>x之后请求cin的值</span>

2、如果计算总成绩的时候用中值代替平均值呢?
分析:这里就必须用到排序了,但是这里又需要注意个数为奇数还是偶数了?
所以我们必须要完成以下三个工作:
1)储存大量的数值
2)在读取了所有的数值之后对他们进行排序
3)高效地获取中间的一个或者两个数值
<span style="font-family:KaiTi_GB2312;">// lesson3_2.cpp : 定义控制台应用程序的入口点。
//功能:假设有一门课程中,每一个学生的总成绩都由期末考试成绩(40%),期中考试成绩(20%)和家庭作业的中值成绩(40%)构成。
//时间:2014.5.8

#include "stdafx.h"
#include "algorithm"
#include "iomanip"
#include "ios"
#include "iostream"
#include "string"
#include "vector"
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	//请求输入并读出学生的姓名
	cout << "Please enter your first name: ";
	string name;
	cin >> name;
	cout << "Hello, " << name << "!" << endl;

	//请求输入并读入期中和期末成绩
	cout << "Please enter your midterm and final exam grades: ";
	double midterm, final;
	cin >> midterm >> final;

	//请求输入家庭作业成绩
	cout << "Enter all your homework grades, "
		"followed by end-of-file: ";
	
	vector<double> homework;
	double x;

	//不变式:homework包含了所有的家庭作业成绩
	while (cin >> x)
		homework.push_back(x);

	//检查homework是否为空
	typedef vector<double>::size_type vec_sz;
	vec_sz size = homework.size();
	if (size == 0)
	{
		cout << endl << "You must enter your grades. "
			         << "Please try again." << endl;
		return 1;
	}

	//对成绩进行排序
	sort(homework.begin(), homework.end());

	//计算家庭作业成绩的中值
	vec_sz mid = size/2;
	double median;
	median = (size % 2 == 0) ? (homework[mid] + homework[mid - 1]) / 2 : homework[mid];

	//计算并输出总成绩
	streamsize prec = cout.precision();
	cout << "Your final grade is " << setprecision(3)
		 << 0.2 * midterm + 0.4 * final + 0.4 * median
		 << setprecision(prec) << endl;


	return 0;
}
</span>

运行结果:


程序说明:
1)vector<double> homework;向量是一个储存数值集合的容器,在一个向量中的所有数值都具有相同的类型,但是不同的向量可以保存不同类型的对象。无论什么时候,我们只要定义了一个向量,我们就必须制定向量所保存的数值的类型。
2)homework.push_back(x); push_back看做一个成员函数,所做的就是添加一个新的元素到向量的末尾,它会给新元素一个值,这个值就是我们传递给它的参数。
注意:副作用是push_back会使向量的长度加1。
3)typedef vector<double>::size_type vec_sz;我们要养成使用库定义size_type来表示容器的长度的编程良好习惯还有就是要养成使用typedef来替代作为替代名。
4)最后一个需要说明的就是排序sort(homework.begin(), homework.end())

3、把一个整数集合分为个数相等的四部分,而且第一部分含有的整数值比其他各部分的都大,第二部分的值比第一部分小,但是比其他部分都大
<span style="font-family:KaiTi_GB2312;">// lesson3_3.cpp : 定义控制台应用程序的入口点。
//功能:把一个整数集合分为个数相等的四部分,而且第一部分含有的整数值比其他各部分的都大,第二部分的值比第一部分小,但是比其他部分都大
//时间:2014.5.8
#include "stdafx.h"
#include "algorithm"
#include "iostream"
#include "vector"
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	//请求输入并读入一个整数集合
	cout << "Please enter the integer: ";
	vector<int> integer;
	int x;

	//不变式:integer包含了所有的家庭作业成绩
	while (cin >> x)
		integer.push_back(x);

	//检查integer是否为空
	typedef vector<int>::size_type vec_sz;
	vec_sz size = integer.size();
	if (size == 0)
	{
		cout << "It is not integer!" << endl;
		return 1;
	}
	
	//对这些数进行排序
	sort(integer.begin(),integer.end());
    vec_sz size_avg = size/4;

	//输出四部分
	cout << "The first part: " << endl;
	for(vec_sz i = 0;i <= (size_avg - 1) ; i++)
	{
		cout << integer[i] << endl;
	}

	cout << "The second part: " << endl;
	for(vec_sz i = size_avg;i <= (2*size_avg - 1) ; i++)
	{
		cout <<  integer[i] << endl;
	}

	cout << "The third part: "  << endl;

	for(vec_sz i = 2*size_avg;i <= (3*size_avg - 1) ; i++)
	{
		cout << integer[i] << endl;
	}
	
	cout << "The fourth part: " << endl;
	for(vec_sz i = 3*size_avg;i <= (4*size_avg - 1) ; i++)
	{
		cout << integer[i] << endl;
	}


	return 0;
}
</span>

运行结果:


4、编写一个程序来计算在它的输入中每一个不同的单词所出现的次数
<span style="font-family:KaiTi_GB2312;">// lesson3_4.cpp : 定义控制台应用程序的入口点。
//功能:编写一个程序来计算在它的输入中每一个不同的单词所出现的次数
//时间:2014.5.8
#include "stdafx.h"
#include "iostream"
#include "string"
#include "vector"
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
	//请求输入并读入单词
	cout << "Please enter words: ";
	vector<string> words;
	vector<int> counts;
	string x;

	typedef vector<string>::size_type vec_sz;

	//不变式:words包含所有的不同的单词
	while (cin >> x)
	{	
		bool found = false;

		for(vec_sz i = 0; i < words.size(); ++i)
		{
			if(x == words[i])
			{
				++counts[i];
				found = true;
			}
		}
		if (!found)
		{
			words.push_back(x);
			counts.push_back(1);
		}
	}

	for(vec_sz i = 0; i < words.size(); ++i)
		cout << words[i] << " appeared " << counts[i] << " times" << endl;


	return 0;
}
</span>

运行程序:


5、编写一个程序来报告它的输入中最长以及最短的字符串的长度
<span style="font-family:KaiTi_GB2312;">// lesson3_5.cpp : 定义控制台应用程序的入口点。
//功能:编写一个程序来报告它的输入中最长以及最短的字符串的长度
//2014.5.8

#include "stdafx.h"
#include "iostream"
#include "string"
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	typedef string::size_type str_sz;

	string longest;
	str_sz longest_length = 0;
	string shortest;
	str_sz shortest_length = 0;

	//请求输入字符串
	cout << "Please enter character: ";
	string s;

	//不变式
	while (cin >> s)
	{
		if(longest_length == 0 || s.size() > longest_length)
		{
			longest = s;
			longest_length = s.size();
		}

		if(shortest_length == 0 || s.size() < shortest_length)
		{
			shortest = s;
			shortest_length = s.size();
		}
	}

	cout << "Longest: " << longest << longest_length << endl;
	cout << "Shortest: " << shortest << shortest_length << endl;

	
	return 0;
}
</span>

运行结果:


6)编写一个程序来同时跟踪n个学生的成绩,要求程序能够保持两个向量的同步:第一个应保存学生的姓名
<span style="font-family:KaiTi_GB2312;">// lesson3_6.cpp : 定义控制台应用程序的入口点。
//功能:编写一个程序来同时跟踪n个学生的成绩,要求程序能够保持两个向量的同步:第一个应保存学生的姓名;第二个保存总成绩 这个其实和lesson3_1一样的
//时间:2014.5.8

#include "stdafx.h"
#include "iomanip"
#include "ios"
#include "iostream"
#include "string"
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
	//请求输入并读入学生的姓名
	cout << "Please enter your first name: ";
	string name;
	cin >> name;
	cout << "Hello, " << name << "!" << endl;

	//请求输入并读入期中和期末考试成绩
	cout << "Please enter your midterm and final exam grades: ";
	double midterm, final;
	cin >> midterm >> final;

	//请求输入家庭作业成绩
	cout << "Enter all your homework grades, "
		"followed by end-of-file: ";

	//到目前为止,读入的家庭作业成绩的个数及总和
	int count = 0;
	double sum = 0;

	//把家庭作业的成绩读到变量x中
	double x;

	//不变式:
	//到目前为止,我们已经读到了count个家庭作业成绩,
	//而且sum等于头count个成绩的总和
	while (cin >> x)
	{
		++count;
		sum += x;
	}

	double homework_grade = (count > 0) ? sum / count : 0.0;

	//输出结果
	streamsize prec = cout.precision();
	cout << "Your final grade is " << setprecision(3)
		 << 0.2 * midterm + 0.4 * final + 0.4 * homework_grade
		 << setprecision(prec) << endl;

	return 0;
}

</span>

运行结果:


7、假设我们需要找出一个数值集合的中值,同时假定到目前为止,我们已经读了一些数值,但是不清楚我们还需要再读多少个数值,证明我们不能丢掉已经读过的任何值。(备注:这道题答案是网上找的,我也不是完全理解这答案说明,有想法可以留言,共同讨论与交流)

证明:在已经读了N个值后,我们丢弃了一个值x。可以计算出,在已读集合中,比x大的值有n1个,比x小的值有n2个,n1+n2 < N(注意n1+n2不一定等于N-1,因为可能存在于x相等的值)。

    1) 首先考虑在已读集合中,x只有一个,那么令d = max(n1,n2) - min(n1,n2)。再令集合s = { n1 > n2 ? d个(x-1) : d个(x+1) },s就是使的x成为整个集合中值的后续数值集合,从而x不能丢弃。

    2) 在考虑x有多个的情况,设为n3个,此时n1+n2+n3 = N,并令y1为输入值中比x大的所有值中最小的一个(即大于x的子集的下确界),类似,令y2为小于x的子集的上确界。

    令d= max(n1,n2) - min(n1,n2)。令集合s = { n1 > n2 ? d个y2 : d个y1 }

    再令 y3 = (x-y2)/2,令集合s\' = {(n3-1)个 y3 }。s并s\'即是令x为中值的后续数值集合。因为当整个集合中有n3个x时,中值是x,如果去掉一个x,则要根据中值在此时的定义决定:

    a)如果整个集合为偶数时,取中间偏小的那个为中值,那么去掉x后,y3就成为中值,这是错误的,说明x不能去除。

    b)如果整个集合为偶数时,取中间偏大的那个为中值,可以令y3\' = (y1-x)/2代替上面的y3,则y3\'就是新的中值。这是错误的,同样说明x不能去除。

    综上,在任何情况下去除输入数值中的任何一个,都有可能(即存在一个未输入数值集合)使得整个集合的中值发生改变。

8、小结:本节主要讲解了如何处理批量数据,还有如何计算中值,这一节中一些常用的语句用法需要大家多多熟练。
                                                                                                                                                         ——To_捭阖_youth

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值