C++题目练习10
10.1 模板练习:数组最大值
设计一个函数模板,实现从int、long long、char、double、string类型的数组找出最大值元素。
提示:可用类型参数传递数组、用非类型参数传递数组大小。
#include <iostream>
#include <string>
using namespace std;
template<typename T>
T findMax(T *a, int n) {
T max;
max = a[0];
for (int i = 1; i < n; i++) {
if (max < a[i])
max = a[i];
}
return max;
}
int main() {
int n;
cin >> n;
int *a = new int[n];
for ( int i = 0; i < n; i++ )
cin >> a[i] ;
cout << "1 " << findMax( a, n ) << endl;
delete[] a;
cin >> n;
string *b = new string[n];
for ( int i = 0; i < n; i++ )
cin >> b[i] ;
cout << "2 " << findMax( b, n ) << endl;
delete[] b;
cin >> n;
long long *c = new long long[n];
for ( int i = 0; i < n; i++ )
cin >> c[i] ;
cout << "3 " << findMax( c, n ) << endl;
delete[] c;
cin >> n;
double *d = new double[n];
for ( int i = 0; i < n; i++ )
cin >> d[i] ;
cout << "4 " << findMax( d, n ) << endl;
delete[] d;
return 0;
}
10.2 设计模板类 MyStack
请按要求实现一个 MyStack 类模板,要求实现数据的封装和各种常用操作。
约定:
- 数据成员为私有属性,包括:
- data :一个指针,指向存放栈元素的空间,栈元素类型为 T
- tt : 指示栈顶位置
- siz : 当前栈空间的大小
- 成员函数为公有属性,包括:
- 默认构造函数,完成初始化动作,栈空间的默认大小是 100 。
- 带一个参数 s 的构造函数,s 表示栈空间的初始大小。
- 析构函数:负责释放动态申请的内存。
- 拷贝构造函数,实现深拷贝。
- top( &v ),函数返回如果为真,参数 v 带回栈顶元素的值;函数返回如果为假,参数 v 的值没有变化。
- pop(),如果栈不空,弹走栈顶元素;如果栈空,没有动作。
- push( v ),如果栈已满,没有动作;如果栈未满,参数 v 的值进栈。
- size(),返回当前栈内元素个数,如果栈空,返回 0 。
- 重载 流插入运算符 << :如果栈不空,自栈底到栈顶,输出栈内元素,每个元素后跟一个空格;如果栈空,没有输出。
- 重载 赋值运算符 = :将一个栈对象赋值给另一个栈对象,要实现深拷贝
- 重载 等于比较运算符 == : a 和 b 两个栈对象,当栈 a 的元素 与 栈 b 的元素个数相同且所有对应位置的元素相等时,表达式 a == b 为真
请实现上述功能。
完成 MyStack类 的 数据成员 以及 各成员函数 的实现。
#include<cstdio>
#include <iostream>
using namespace std;
template<typename T>
class MyStack {
public:
// 无参默认构造函数
MyStack();
// 带一个参数 int s 的构造函数
MyStack( unsigned s );
// 拷贝构造函数
MyStack( const MyStack &b );
// 析构函数
~MyStack();
// 读取栈顶元素的值,赋值给 v
bool top( T& v );
// 弹出栈顶元素
void pop();
// 压v进栈
bool push( const T& v );
// 当前栈内元素个数
unsigned size();
// 重载 流插入运算符 <<
friend ostream & operator<< ( ostream &out, const MyStack& a ) {
if(a.data == nullptr || a.tt == -1)
return out;
for(int i = 0;i<a.tt+1;i++)
out<< a.data[i] <<" ";
out<<endl;
return out;
}
// 重载 赋值运算符 =
MyStack & operator = ( const MyStack& b );
// 等于 比较运算符 ==
bool operator == ( const MyStack& b );
private:
T *data;
int tt;
unsigned siz;
};
template<typename T>
MyStack<T>::MyStack()
{
siz=100;
data=new T[siz];
tt=-1;
}
template<typename T>
MyStack<T>::MyStack(unsigned s)
{
siz = s;
data = new T[siz];
tt=-1;
}
template<typename T>
MyStack<T>::MyStack(const MyStack &b)
{
data = new T[b.siz];
siz = b.siz;
for(int i =0;i<b.tt+1;i++)
{
data[i] = b.data[i];
}
tt = b.tt;
}
template<typename T>
MyStack<T>::~MyStack()
{
if(data != nullptr)
delete[]data;
}
template<typename T>
bool MyStack<T>::top(T &v)
{
if(tt == -1)
return false;
v = data[tt];
return true;
}
template<typename T>
void MyStack<T>::pop()
{
if(tt == -1)
{
return;
}
tt--;
}
template<typename T>
bool MyStack<T>::push(const T &v)
{
if(tt==siz-1)
return false;
tt++;
data[tt] = v;
return true;
}
template<typename T>
unsigned MyStack<T>::size()
{
return tt+1;
}
template<typename T>
MyStack<T> &MyStack<T>::operator=(const MyStack &b)
{
if(this == &b)
{
return *this;
}
if(data!=nullptr)
{
delete[]data;
}
data = new T[b.siz];
siz = b.siz;
for(int i=0;i<b.tt+1;i++)
{
data[i] = b.data[i];
}
tt = b.tt;
return *this;
}
template<typename T>
bool MyStack<T>::operator==(const MyStack &b)
{
if(this == &b)
return true;
if(tt != b.tt)
return false;
for(int i=0;i<tt+1;i++)
{
if(data[i]!=b.data[i])
return false;
}
return true;
}
int main() {
int si;
cin >> si;
MyStack<int> s1( si ); // 创建一个栈空间大小为 si 的栈 s1
int command;
int c, v;
cin >> command; // 读入命令个数
while( command -- ) {
cin >> c; // 读入一条命令
switch( c ) {
case 1: // 进栈
cin >> v;
s1.push( v );
break;
case 2: // 出栈
s1.pop();
break;
case 3: // 读取栈顶元素
if( s1.top( v ) ) // 如果返回为真,说明成功读取栈顶元素
cout << v << endl; // 输出之
break;
case 4: // 栈内元素的个数
cout << s1.size() << endl;
break;
case 5: // 利用重载的 流插入运算符 输出 栈s1
cout << s1; // 笔记:换行符要放在 operator<<运算符重载函数里面输出,否则会造成PE
break;
}
}
MyStack<int> s2( s1 ); // 利用拷贝构造函数创建一个新对象 s2
cin >> command;
while( command -- ) {
cin >> c;
switch( c ) {
case 1: // 进栈
cin >> v;
s2.push( v );
break;
case 2: // 出栈
s2.pop();
break;
case 3: // 读取栈顶元素
if( s2.top( v ) ) // 如果返回为真,说明成功读取栈顶元素
cout << v << endl; // 输出之
break;
case 4: // 栈内元素的个数
cout << s2.size() << endl;
break;
case 5: // 利用重载的 流插入运算符 输出 栈s2
cout << s2;
break;
}
}
if( s1 == s2 ) // 利用重载的 等于比较运算符 判断 s1 == s2 是否为真
cout << "yes" << endl;
else
cout << "no" << endl;
MyStack<int> s3; // 调用默认构造函数创建一个新对象 s3
s3 = s1; // 赋值运算符
if( s3 == s1 ) // 利用重载的 等于比较运算符 判断 s3 == s1 是否为真
cout << "yes" << endl;
else
cout << "no" << endl;
cin >> command;
while( command -- ) {
cin >> c;
switch( c ) {
case 1: // 进栈
cin >> v;
s3.push( v );
break;
case 2: // 出栈
s3.pop();
break;
case 3: // 读取栈顶元素
if( s3.top( v ) ) // 如果返回为真,说明成功读取栈顶元素
cout << v << endl; // 输出之
break;
case 4: // 栈内元素的个数
cout << s3.size() << endl;
break;
case 5: // 利用重载的 流插入运算符 输出 栈s3
cout << s3;
break;
}
}
return 0;
}
10.3 模版类Array
请实现一个模版类 Array ,实现可以直接访问的线性群体,包括:私有数据成员:
- T* list; /// 用于存放动态分配的数组内存首地址
- int siz; /// 数组大小。为了避免与 size 同名而高亮显示,特意减少一个字符
成员函数:
- 构造函数 : Array( int sz = 10 )
- 拷贝构造函数 : Array( const Array<T> &a )
- 析构函数 : ~Array()
- 重载赋值运算符 operator = : operator = ( const Array<T> &rhs )
- 重载 下标运算符[] ,用于 左值: operator [] ( int i )
- 重载 下标运算符[] 常函数,用于 右值 : operator [] ( int i ) const
- 重载到 T* 类型的转换 :operator T * ()
- 取数组的大小 : getSize()
- 修改数组的大小 : resize( int sz )
#include <iostream>
#include <cassert>
#include <iomanip>
using namespace std;
template<class T>
class Array
{
private:
T *list;
int siz;
public:
Array(int sz = 10)
{
siz = sz;
list = new T[siz];
}
Array(const Array<T>&a)
{
siz = a.siz;
list = new T[siz];
for(int i = 0;i<siz;i++)
{
list[i] = a.list[i];
}
}
~Array()
{
delete[] list;
}
Array<T>& operator = (const Array<T> &rhs)
{
if(this != &rhs)
{
delete[] list;
siz = rhs.siz;
list = new T[siz];
for(int i = 0;i<siz;i++)
{
list[i] = rhs.list[i];
}
}
return *this;
}
T& operator[](int i)
{
assert(i>=0 && i<siz);
return list[i];
}
const T& operator[](int i) const {
assert(i >= 0 && i < siz);
return list[i];
}
operator T*() {
return list;
}
int getSize(){
return siz;
}
void resize(int sz) {
T* newList = new T[sz];
for (int i = 0; i < min(siz, sz); i++) {
newList[i] = list[i];
}
delete[] list;
list = newList;
siz = sz;
}
};
/// read() 用于验证 重载的指针转换运算符
void read( double *p, int n ) {
for ( int i = 0; i < n; i++ )
cin >> p[i];
}
int main() {
int n;
cin >> n;
Array<double> da(n); /// 创建一个 double类型元素 的 对象da
read( da, n );
/// 输出 Array类的 对象da 全部元素
for ( int i = 0; i < da.getSize(); i++ )
cout << da[i] << ' ';
cout << endl;
Array<int> prime(5); /// 创建一个 int类型元素 的 对象prime
/// 求 [2, n] 的全部素数,存放到 prime 中
int cnt = 0; /// 统计当前找到的素数的个数
cin >> n; /// 读入范围
for ( int i = 2; i <= n; i ++ ) { /// 检查 i 是否能被比它小的素数整除
bool isPrime = true;
for ( int j = 0; j < cnt; j ++ )
/// 若 i 被 prime[j] 整除,说明 i 不是质数
if ( i % prime[j] == 0 ) {
isPrime = false;
break;
}
if ( isPrime ) {
if ( cnt == prime.getSize() ) /// 当装满了
prime.resize( cnt * 2 ); /// 空间扩大一倍
prime[ cnt ++ ] = i;
}
}
for ( int i = 0; i < cnt; i ++ )
cout << setw(8) << prime[i];
cout << endl;
return 0;
}