初阶模板
下面有关C++中为什么用模板类的原因,描述错误的是? ( )
A.可用来创建动态增长和减小的数据结构
B.它是类型无关的,因此具有很高的可复用性
C.它运行时检查数据类型,保证了类型安全
D.它是平台无关的,可移植性
A.模板可以具有非类型参数,用于指定大小,可以根据指定的大小创建动态结构
B.模板最重要的一点就是类型无关,提高了代码复用性
C.模板运行时不检查数据类型,也不保证类型安全,相当于类型的宏替换,故错误
D.只要支持模板语法,模板的代码就是可移植的
在下列对fun的调用中,错误的是( )
template < class T>
T fun(T x,T y){
return x *x+y *y;
}
A.fun(1, 2)
B.fun(1.0, 2)
C.fun(2.0, 1.0)
D.fun< float>(1, 2.0)
A.通过参数推导,T为int,不存在二义性,调用正确
B.由于参数类型不一样,模板不支持类型转换,推导参数会产生二义性,编译错误
C.通过参数推导,T为float,不存在二义性,调用正确
D.通过类型实例化函数,调用正确
下列关于模板的说法正确的是( )
A.模板的实参在任何时候都可以省略
B.类模板与模板类所指的是同一概念
C.类模板的参数必须是虚拟类型的
D.类模板中的成员函数全是模板函数
A. 模板实参省略意思为隐式实例化,一般情况下都使用隐式实例化,不需指定模板类型参数,让编译器进行推导
但有些情况下编译器推导时可能会有歧义,比如:模板参数只有一个类型T,但是用两个不同类型隐式实例化
template<class T>T Add(const T& x, const T& y){return x + y;}int main(){Add(10, 20); // 正确Add(1.2, 30); // 编译失败, 改正 Add<int>(1.2, 20) 或者 Add((int)1.2, 20)return 0;}
所以模板参数不是任何情况下都可以省略,要结合具体的使用场景,因此A的说法是错误的。
B.类模板是一个类家族,模板类是通过类模板实例化的具体类
C.C++中类模板的参数即为模板参数列表中内容,有两种方式:类型参数和非类型参数
类型参数:即类型参数化,将来实例化为具体的实际类型,有点像函数的形参,形参可以接受不同值的实参
非类型参数:在定义时给定了具体的类型,用该类型定义的为常量,比如:
template<class T, size_t N>class array{// ...};
D.正确,定义时都必须通过完整的模板语法进行定义。 因为所有类模板的成员函数,放在类外定义时,需要在函数名前加类名,而类名实际为ClassName< T>,所以定义时还需加模板参数列表
template<class T>size_t Stack<T>::size(){return _size;}
因此类模板中的成员函数都是函数模板
下列的模板声明中,其中几个是正确的( )
1)template
2)template<T1,T2>
3)template<class T1,T2>
4)template<class T1,class T2>
5)template<typename T1,T2>
6)template<typename T1,typename T2>
7)template<class T1,typename T2>
8)<typename T1,class T2>
A.2
B.3
C.4
D.5
A.1.模板语法错误,2.没有关键字class或typename指定类型,3.T2缺少class或typename
B.正确, 4,6,7为正确声明
C.5.T2缺少class或typename
D.8.缺少template
下列描述错误的是( )
A.编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础
B.函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具
C.模板分为函数模板和类模板
D. 模板类跟普通类以一样的,编译器对它的处理时一样的
A.模板是代码复用的重要手段
B.函数模板不是一个具体函数,而是一个函数家族
C.目前涉及到的模板就两类,函数模板与类模板
D.模板类是一个家族,编译器的处理会分别进行两次编译,其处理过程跟普通类不一样
}
return 0;
}
A.程序运行崩溃
B.1 2 3 4 5 0 6 7 8 9
C.1 2 3 4 5 6 7 8 9
D.1 2 3 4 6 7 8 9
分析:当迭代器的值为0时,此时会进行删除,删除后如果迭代器不重新赋值,会导致原来的迭代器失效,此时针对一个已经失效的迭代器在进行++,会导致程序崩溃
故答案为A
2.下面关于迭代器失效的描述哪个是错误的( )
A.vector的插入操作一定会导致迭代器失效
B.vector的插入操作有可能不会导致迭代器失效
C.vector的删除操作只会导致指向被删除元素及后面的迭代器失效
D.vector的删除操作只会导致指向被删除元素的迭代器失效
A.vector的插入操作如果导致底层空间重新开辟,则迭代器就会失效。如果空间足够,不扩容时,迭代器不一定失效,比如push_back尾插,元素插入到空间末尾,在不扩容时不会对迭代器产生影响
B.参考A的解释。
C.vector删除,当前元素肯定失效,后面元素会牵扯到移动数据,因此删除元素后面的迭代器也会失效
D. vector的删除操作不光会导致指向被删除元素的迭代器失效,删除元素后面的迭代器也会失效
list的特性及使用
1.下面有关vector和list的区别,描述错误的是( )
A.vector拥有一段连续的内存空间,因此支持随机存取,如果需要高效的随机存取,应该使用vector
B.list拥有一段不连续的内存空间,如果需要大量的插入和删除,应该使用list
C.vector::iterator支持“+”、“+=”、“<”等操作符
D.list::iterator则不支持“+”、“+=”、“<”等操作符运算,但是支持了[ ]运算符
答案:D
A.如果想大量随机读取数据操作,vector是首选的容器
B.如果想大量的插入和删除数据,list效率较高,是首选
C.由于vector底层是连续空间,其迭代器就是相应类型的指针,所以支持对应的操作
D.list迭代器不支持[]运算符
2.以下代码实现了从表中删除重复项的功能,请选择其中空白行应填入的正确代码( )
template
void removeDuplicates(list &aList)
{
T curValue;
list::iterator cur, p;
cur = aList.begin();
while (cur != aList.end())
{
curValue = *cur;
//空白行 1
while (p != aList.end())
{
if (*p == curValue)
{
//空白行 2
}
else
{
p++;
}
}
}
}
A. p=cur+1;aList.erase(p++);
B.p=++cur; p == cur ? cur = p = aList.erase§ : p = aList.erase§;
C.p=cur+1;aList.erase§;
D.p=++cur;aList.erase§;
答案:B
分析:迭代p需要迭代不重复节点的下一节点,重要的是cur迭代器需要往下迭代,因此cur需要往前移动,二答案A C的cur都不会改变,空白行2是当需要找到重复值时进行节点删除,当删除时当前迭代器会失效,因此需要将迭代器p往后迭代,所以答案为 B
3.以下程序输出结果为( )
int main()
{
int ar[] = { 0,1, 2, 3, 4, 5, 6, 7, 8, 9 };
int n = sizeof(ar) / sizeof(int);
list mylist(ar, ar+n);
list::iterator pos = find(mylist.begin(), mylist.end(), 5);
reverse(mylist.begin(), pos);
reverse(pos, mylist.end());
list::const_reverse_iterator crit = mylist.crbegin();
while(crit != mylist.crend())
{
cout<<*crit<<" ";
++crit;
}
cout<<endl;
}
A.4 3 2 1 0 5 6 7 8 9
B.0 1 2 3 4 9 8 7 6 5
C.5 6 7 8 9 0 1 2 3 4
D.5 6 7 8 9 4 3 2 1 0
答案:C
分析:list::iterator pos = find(mylist.begin(), mylist.end(), 5); //找到5的位置
reverse(mylist.begin(), pos);//逆置0 1 2 3 4 为 4 3 2 1 0
reverse(pos, mylist.end()); //逆置5 6 7 8 9 为 9 8 7 6 5
逆置完成之后其数据为:4 3 2 1 0 9 8 7 6 5
list::const_reverse_iterator crit = mylist.crbegin(); //反向迭代器进行反向访问
while(crit != mylist.crend()){}
所以答案为:5 6 7 8 9 0 1 2 3 4
C答案
下面程序的输出结果正确的是( )
int main()
{
int array[] = { 1, 2, 3, 4, 0, 5, 6, 7, 8, 9 };
int n = sizeof(array) / sizeof(int);
list mylist(array, array+n);
auto it = mylist.begin();
while (it != mylist.end())
{
if(* it != 0)
cout<<* it<<" ";
else
it = mylist.erase(it);
++it;
}
return 0;
}
A.1 2 3 4 5 6 7 8 9
B. 1 2 3 4 6 7 8 9
C.程序运行崩溃
D.1 2 3 4 0 5 6 7 8 9
分析:程序在使用迭代器取值时,如果不等于0就进行打印,为0时不打印并删除当前节点,所以答案为 B
对于list有迭代器it, 当erase(it)后,说法错误的是( )
A.当前迭代器it失效
B.it前面的迭代器仍然有效
C.it后面的迭代器失效
D.it后面的迭代器仍然有效
分析:删除节点后,只有指向当前节点的迭代器失效了,其前后的迭代器仍然有效,因为底层为不连续空间,只有被删除的 节点才会失效, 所以答案为 C
下面有关vector和list的区别,描述正确的是( )
A.两者在尾部插入的效率一样高
B.两者在头部插入的效率一样高
C.两者都提供了push_back和push_front方法
D.两者都提供了迭代器,且迭代器都支持随机访问
A.vector在尾部插入数据不需要移动数据,list为双向循环链表也很容易找到尾部,因此两者在尾部插入数据效率相同
B.vector头部插入效率极其低,需要移动大量数据
C.vector由于在头部插入数据效率很低,所以没有提供push_front方法
D.list不支持随机访问
stack和queue
下列代码的运行结果是( )
void main()
{
stack S;
char x,y;
x=‘n’;y=‘g’;
S.push(x);S.push(‘i’);S.push(y);
S.pop();S.push(‘r’);S.push(‘t’);S.push(x);
S.pop();S.push(‘s’);
while(!S.empty())
{
x = S.top();
S.pop();
cout<<x;
};
cout<<y;
}
A.gstrin
B.string
C.srting
D.stirng
分析:S.push(x);S.push(‘i’);S.push(y); 入栈了字母“nig” 左边栈底 右边栈顶
S.pop();S.push(‘r’);S.push(‘t’);S.push(x); 字母g出栈,然后入栈字母“rtn”,此时栈数据 为"nirtn"
S.pop();S.push(‘s’);字母n出栈,s入栈,最终的栈数据为nirts
while(!S.empty()){} 栈不空出栈打印,按相反顺讯出栈,所以打印结果为:strin
cout<<y;最后还打印了字母g
所以答案为B
下列代码的运行结果是( )
void main()
{
queue Q;
char x,y;
x=‘n’;y=‘g’;
Q.push(x);Q.push(‘i’);Q.push(y);
Q.pop();Q.push(‘r’);Q.push(‘t’);Q.push(x);
Q.pop();Q.push(‘s’);
while(!Q.empty())
{
x = Q.front();
Q.pop();
cout<<x;
};
cout<<y;
}
A.gstrin
B.grtnsg
C.srting
D.stirng
分析:Q.push(x);Q.push(‘i’);Q.push(y); 入队数据为:nig 左边队头,右边队尾
Q.pop();Q.push(‘r’);Q.push(‘t’);Q.push(x); n出队,rtn入队,队里数据为:igrtn
Q.pop();Q.push(‘s’); i出队,s入队,队里数据为:grtns
while(!Q.empty()){} 队不空,在出队打印为:grtns
cout<<y; 最后在打印一个g
故答案为:B
一个栈的输入顺序是a,b,c,d,e则下列序列中不可能是出栈顺序是( )
A.e,d,a,c,b
B.a,e,d,c,b
C.b,c,d,a,e
D.b,c,a,d,e
分析:首先此题要保证入栈的顺序不能改变,其次,某个字母出栈前,必须把其栈顶的元素都要出栈
A:e要先出栈,就必须把a b c d e 全部入栈,然后e才能出栈,对于e d 的出栈没有问题,只是a要出栈,就必须c d 先出栈后,才能轮到a出栈,因此A是不可能得到的出栈顺序,其他答案可以自行验证
以下是一个二叉树的遍历算法,queue是FIFO队列,请参考下面的二叉树,根节点是root,正确的输出是( )
1
2 3
4 5 6 7
queue.push(root);
while(!queue.empty())
{node = queue.top();queue.pop(); output(node->value) //输出节点对应数字if(node->left)queue.push(node->left);if(node->right)queue.push(node->right);
}
A.1376254
B.1245367
C.1234567
D.1327654
分析:此题是一个层次遍历的伪代码,能够看出是层次遍历,其结果就迎刃而解,答案 C