2章
a接口与实现
1.说法正确的是:同一个抽象数据类型可能用多种数据结构实现。
2.在一个初始为空的向量上依次执行:insert(0, 2), insert(1, 6), put(0, 1), remove(1), insert(0, 7) 后的结果是:{7, 1}
3.以下代码是向量复制代码的一个变体且语义与其相同,空格处应填入的内容为:
–hi
解析:该代码是从后向前复制。根据视频中代码的语义,复制的范围是A[lo, hi)。
b.可扩充接口
1.在一个初始最大容量为10的空向量上依次执行:insert(0, 2), insert(1, 6), put(0, 1), remove(1), insert(0, 7) 后的装填因子是:20%
解析:经过这些操作后的向量为{7, 1}。装填因子=实际所用容量/最大容量。
2.是否可以将视频里向量扩容代码中的:
for (int i = 0; i < _size; i++) _elem[i] = oldElem[i];
in the vector expansion code in the video with: 替代为:
memcpy(_elem, oldElem, _size * sizeof(T));
答:不能,因为后者能否达到目的与元素类型T有关。
解析:当T为非基本类型且有对应的赋值运算符以执行深复制时,前一段代码会调用赋值运算符,而后一段只能进行浅复制。
3.采用每次追加固定内存空间的扩容策略,规模为n的向量插入元素的分摊时间复杂度为:
Θ ( n ) \Theta(n) Θ(n)
4.分别采用每次追加固定内存空间和每次内存空间翻倍两种扩容策略,规模为n的向量插入元素的分摊时间复杂度分别为:
Θ ( n ) , Θ ( 1 ) \Theta(n),\Theta(1) Θ(n),Θ(1)
5.关于平均复杂度和分摊复杂度,说法错误的是:分摊复杂度得到的结果比平均复杂度低
解析:分摊复杂度和平均复杂度的结果并没有必然联系
c.无序向量
1.T & Vector::operator[](Rank r) { return _elem[r]; } 中的返回值T&是什么意义?
答:这是类型T的引用,使用它是因为返回值可以作为左值
解析: V[0] = 1 左值即位于赋值号“=”左边的值。只有返回值可以作为左值,才能通过以下表达式修改向量:V[0] = 1
2.如果insert()函数中的FOR循环更改为以下形式会发生什么?
答:会覆盖原向量中秩大于r的所有元素
解析:执行该代码后,原向量中秩为r的元素覆盖了后面的所有元素。
3. 为什么区间删除算法remove(lo, hi)中要从前向后移动被删除元素的后缀?
答:因为可能会覆盖部分元素
解析:不妨考虑在{1,2,3}中删除秩为0的元素
4.对于deduplicate()算法,向量规模为n时的最坏时间复杂度为:
Θ ( n 2 ) \Theta({n}^{2}) Θ(n2)
解析:外循环迭代 Θ ( n ) \Theta(n) Θ(n)次,每次内循环需要 Θ ( n ) \Theta(n) Θ(n)的时间
5.作为一个函数对象的类XXX,它必须显式定义以下哪个成员函数:
operator()()
解析:对于函数对象来说,()是用于执行函数调用的操作符
d1.有序向量-唯一化
1.disordered()算法的返回值是:相邻逆序对个数
解析:相邻逆序对即两个相邻的元素{…i, j…}且i>j。而逆序数是逆序对的个数,并不要求二者相邻。
4. 有序向量中的重复元素:必定全部紧邻分布
3.对于规模为n的向量,低效版uniquify()的最坏时间复杂度为: Θ ( n 2 ) \Theta(n^2) Θ(n