アフィリエイト広告を利用しています

広告

posted by fanblog

2018年02月17日

《その294》 問題演習 p.381演習10-3 (2)



新版明解C++中級編 p.381 演習10-3
 次の (1)〜(4) のプログラムを作成せよ。

 (1) 演習2-1(本ブログの《116》)で作成した日付クラス Date の
   2次元配列(列数は一定)を作成するプログラム。
 (2) 上の (1) で、列数が行によって異なる2次元配列を作成するプログラム。
 (3) 下記の Twin<> を利用したクラスの2次元配列(列数は一定)を作成するプログラム。
 (4) 上の (3) で、列数が行によって異なる2次元配列を作成するプログラム。



// Twin.h
#include <utility>
#include <algorithm>

// クラステンプレート Twin<>
template <class Type> class Twin {
Type v1; // データメンバ
Type v2; // データメンバ

public:
// コンストラクタ
Twin(const Type& f = Type(), const Type& s = Type())
: v1(f), v2(s) { }
// コピーコンストラクタ
Twin(const Twin<Type>& t)
: v1(t.first()), v2(t.second()) { }

// ゲッタ等
Type first() const { return v1; }
Type& first() { return v1; } // セッタ兼用
Type second() const { return v2; }
Type& second() { return v2; } // セッタ兼用
void set(const Type& f, const Type& s) {
v1 = f; v2 = s;
}

// 小さいほうの値を返却
Type min() const {
return v1 < v2 ? v1 : v2;
}

// v1 < v2 であるか
bool ascending() const { return v1 < v2; }

// v1 < v2 にする
void sort() { if (!(v1 < v2)) std::swap(v1, v2); }
};

// 挿入子の多重定義
template <class Type>
inline std::ostream& operator<<(std::ostream& os,
const Twin<Type>& t) {
return os << "[" << t.first() << ", "
<< t.second() << "]";
}




// 解答<今回は (2) のみ>

// Date.h
#ifndef ___ClassDate
#define ___ClassDate

#include <string>
#include <iostream>

class Date {
int y; //【01】年
int m; // 月
int d; // 日

//【02】各月の日数(静的データメンバ)
static int days_in_month[];

//【03】うるう年であるか(静的メンバ関数)
static bool leap_year(int year);

public:
//【04】デフォルトコンストラクタ
Date();

//【05】コンストラクタ(年月日指定)
explicit Date(int yy, int mm = 1, int dd = 1);

//【06】曜日(0〜6)を求める
int day_of_week() const;

//【07】変換関数(1970/1/1からの日数)
operator long() const;

Date& operator+=(int dn); //【08】dn日進める
Date& operator-=(int dn); //【09】dn日戻す

//【10】日付の日数差
long operator-(const Date& day) const;

//【11】出力用の文字列作成
std::string to_string() const;

int& y_() { return y; } //【14】年にアクセス
int& m_() { return m; } //【15】月にアクセス
int& d_() { return d; } //【16】日にアクセス

//【17】年月日のセッタ
void set_ymd(int y, int m, int d);

Date d_before() const; //【18】前日の日付
Date next_day() const; //【19】翌日の日付
int ds_elpsd_y() const; //【20】年内経過日数

Date& operator++(); //【21】前置増分演算子
Date operator++(int); //【22】後置増分演算子
Date& operator--(); //【23】前置減分演算子
Date operator--(int); //【24】後置減分演算子

//【25-1】dn日後の日付
Date operator+(int dn) const;

//【25-2】dn日後の日付
friend Date operator+(int dn, const Date& x);

//【26】dn日前の日付
Date operator-(int dn) const;

//【27】operator==
bool operator== (const Date& x) const;

//【28】operator!=
bool operator!= (const Date& x) const;

//【29】operator<
bool operator< (const Date& x) const;

//【30】operator<=
bool operator<= (const Date& x) const;

//【31】operator>
bool operator> (const Date& x) const;

//【32】operator>=
bool operator>= (const Date& x) const;

//【33】うるう年であるか
bool leap_year() const;
};

//【12】挿入個の多重定義
std::ostream& operator<<(std::ostream& s, const Date& x);

//【13】抽出子の多重定義
std::istream& operator>>(std::istream& s, Date& x);

#endif




// Date.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <ctime>
#include <sstream>
#include <iomanip>
#include "Date.h"

using namespace std;

//【02】各月の日数
int Date::days_in_month[]
= { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

//【03】うるう年であるか
bool Date::leap_year(int year) {
return year % 4 == 0 && year % 100 != 0 ||
year % 400 == 0;
}

//【04】デフォルトコンストラクタ(今日の日付)
Date::Date() {
time_t current = time(NULL);
struct tm* local = localtime(&current);
y = local->tm_year + 1900;
m = local->tm_mon + 1;
d = local->tm_mday;
}

//【05】コンストラクタ(年月日指定)
Date::Date(int yy, int mm, int dd)
: y(yy), m(mm), d(dd) { }

//【06】曜日(0〜6)を求める
int Date::day_of_week() const {
int yy = y; int mm = m;
if (mm == 1 || mm == 2) { yy--; mm += 12; }
return (yy + yy / 4 - yy / 100 + yy
/ 400 + (13 * mm + 8) / 5 + d) % 7;
}

//【07】変換関数(1970/1/1からの日数)
Date::operator long() const {
long dys = 0;
for (int i = 1970; i < y; i++)
dys += (365 + leap_year(i));
for (int i = 1; i < m; i++) {
dys += days_in_month[i - 1];
}
if (m > 2)
dys += leap_year(y);
return dys - 1 + d;
}

//【08】dn日進める 修正2018/2/16
Date& Date::operator+=(int dn) {
if (dn < 0)
return *this -= -dn;
d += dn;
int temp_ds = days_in_month[m - 1]
+ (m == 2 && leap_year(y));
while (d > temp_ds) {
d -= temp_ds;
if (++m > 12) {
y++; m = 1;
}
temp_ds = days_in_month[m - 1]
+ (m == 2 && leap_year(y));
}
return *this;
}

//【09】dn日戻す
Date& Date::operator-=(int dn) {
if (dn < 0)
return *this += -dn;
d -= dn;
while (d < 1) {
if (--m < 1) {
y--; m = 12;
}
d += days_in_month[m - 1]
+ (m == 2 && leap_year(y));
}
return *this;
}

//【10】日付の日数差
long Date::operator-(const Date& day) const {
return long(*this) - long(day);
}

//【11】出力用の文字列作成
string Date::to_string() const {
string wd[]
= { "日", "月", "火", "水", "木", "金", "土", };
ostringstream s;
s << y << "年" << setw(2) << m << "月" << setw(2)
<< d << "日" << "(" << wd[day_of_week()] << ")";
return s.str();
}

//【17】年月日のセッタ
void Date::set_ymd(int y, int m, int d) {
this->y = y;
this->m = m;
this->d = d;
}

//【18】前日の日付
Date Date::d_before() const {
Date temp = *this;
return temp -= 1;
}

//【19】翌日の日付
Date Date::next_day() const {
Date temp = *this;
return temp += 1;
}

//【20】年内経過日数
int Date::ds_elpsd_y() const {
return *this - Date(y) + 1;
}

//【21】前置増分演算子
Date& Date::operator++() { return *this += 1; }

//【22】後置増分演算子
Date Date::operator++(int) {
Date temp(*this);
++(*this);
return temp;
}

//【23】前置減分演算子
Date& Date::operator--() { return *this -= 1; }

//【24】後置減分演算子
Date Date::operator--(int) {
Date temp(*this);
--(*this);
return temp;
}

//【25-1】dn日後の日付
Date Date::operator+(int dn) const {
Date temp(*this);
return temp += dn;
}

//【25-2】dn日後の日付
Date operator+(int dn, const Date& x) {
return x + dn;
}

//【26】dn日前の日付
Date Date::operator-(int dn) const {
Date temp(*this);
return temp -= dn;
}

//【27】operator==
bool Date::operator== (const Date& x) const {
return y == x.y && m == x.m && d == x.d;
}

//【28】operator!=
bool Date::operator!= (const Date& x) const {
return !(*this == x);
}

//【29】operator<
bool Date::operator< (const Date& x) const {
return long(*this) < long(x);
}

//【30】operator<=
bool Date::operator<= (const Date& x) const {
return long(*this) <= long(x);
}
//【31】operator>
bool Date::operator> (const Date& x) const {
return long(*this) > long(x);
}
//【32】operator>=
bool Date::operator>= (const Date& x) const {
return long(*this) >= long(x);
}

//【33】うるう年であるか
bool Date::leap_year() const { return leap_year(y); }

//【12】挿入子の多重定義
ostream& operator<<(ostream& s, const Date& x) {
return s << x.to_string();
}

//【13】抽出子の多重定義
istream& operator>>(istream& s, Date& x) {
int yy, mm, dd; char c;
s >> yy >> c >> mm >> c >> dd;
x.set_ymd(yy, mm, dd);
return s;
}




// p381_10_3_2.cpp
// ・実は、前回《293》の演習10-3 (1) では、
//  データがある程度以上揃っている部分だ
//  けを使いました。
// ・今回は、データは不揃いになりますが、
//  全データを使っています。

#include <string>
#include <sstream>
#include <iomanip>
#include <vector>
#include <iostream>
#include "Date.h"
using namespace std;

// 月日の文字列を作成
string to_string(Date& x) {
ostringstream s;
s << x.m_() << "/" << setw(2) << x.d_();
return s.str();
}

// 月日の平均を算出
string ave(vector<Date>& x) {
int d = 0;
for (int unsigned i = 0; i < x.size(); i++) {
d += (long(x[i]) - long(Date(x[i].y_())));
}
d = d / x.size();
return to_string(Date(1970, 1, 1) + d);
// 西暦年は、ここでは不要なので、値は任意です。
}

int main() {
vector<Date> kuma{
Date(2014, 6, 30),
Date(2015, 6, 28),
Date(2016, 7, 10),
Date(2017, 7, 10)
};
vector<Date> niinii{
Date(2014, 6, 2),
Date(2015, 6, 30),
Date(2016, 7, 10),
Date(2017, 6, 20)
};
vector<Date> tsukutsuku{
Date(2013, 7, 29),
Date(2014, 8, 12),
Date(2015, 8, 15),
Date(2016, 7, 30),
Date(2017, 8, 2)
};
vector<Date> higurashi{
Date(2014, 6, 30),
Date(2015, 6, 23),
Date(2016, 7, 8),
Date(2017, 6, 15)
};
vector<Date> minmin{
Date(2014, 8, 10),
Date(2015, 7, 25),
Date(2016, 7, 24),
Date(2017, 8, 3)
};
vector<Date> abura{
Date(2016, 7, 10),
Date(2017, 7, 29)
};

vector<vector<Date> >
semi{ kuma, niinii, tsukutsuku, higurashi, minmin, abura };

string name[] = {
"クマゼニ ",
"ニイニイゼミ ",
"ツクツクボウシ ",
"ヒグラシ ",
"ミンミンゼミ ",
"アブラゼミ "
};

cout << "セミの初鳴き 2013 2014 2015 2016 2017\n";
cout << "-----------------------------------------------\n";

int nsemi = sizeof(name) / sizeof(name[0]); // セミの種類数
unsigned jmax = 0; // 1つ以上の初鳴きデータがある年度の数
// jmax の最大値を求める。
for (int i = 0; i < nsemi; i++)
if (semi[i].size() > jmax) jmax = semi[i].size();

for (int i = 0; i < nsemi; i++) {
cout << name[i];
for (unsigned j = 0; j < jmax; j++) {
int f = j - jmax + semi[i].size();
if (f < 0)
// データの無い年度は空白を出力
cout << " ";
else
cout << to_string(semi[i][f]) << " ";
}
cout << '\n';
}
cout << '\n';

cout << "初鳴き月日の平均\n";
for (int i = 0; i < nsemi; i++) {
cout << name[i];
cout << ave(semi[i]) << '\n';
}
}

f10_0302.png



この記事へのコメント
コメントを書く

お名前:

メールアドレス:


ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバックURL
https://fanblogs.jp/tb/7330506
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


検索
<< 2018年08月 >>
      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  
プロフィール
こうすけさんの画像
こうすけ

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


×

この広告は30日以上新しい記事の更新がないブログに表示されております。