Está en la página 1de 14

PIC 10B Big C++ Practice Problem Selected Solutions

Chapter 8 Inheritance (pp. 367-274)

R 8.3
B::B(3)
B::B();
B::B(-3)
D::D(3)

private member b gets initialized at output line 2 (it was not in the initializer list)
R 8.4

Function call stack:


B::print(1)

D::print(2)
D::print(4)
D::print(8)
D::print(16)
D::print(5)
D::print(10)
D::print(3)
R 8.5
Member b of class B is private and is consequently hidden (inaccessible) in class
D. Thus constructor D(int n) has an error and so does D::print(int n). To fix these
errors, define those functions as follows:
D::D(int n): B(n){ }

void D::print()const{
B::print();
}
R 8.6
a.
b.
c.
d.
e.
f.
g.

legal: B is a D
illegal: a D is not necessarily a B
illegal: a D* is not a B*
legal: a B* is a D*
a D is not a D*
legal
illegal: a D is not necessarily a B

R 8.7
b.p(); // statically bound
b.q(); // statically bound
d.p(); // statically bound
d.q(); // statically bound

pb->p(); // dynamically bound
pb->q(); // statically bound
pb->q(); // statically bound
pd->p(); // dynamically bound
pd->q(); // statically bound
pd2->p(); // dynamically bound
pd2->q(); // statically bound
Chapter 9 Streams (pp. 402-409)
R 9.1
#include<iostream>
#include<fstream>
#include<string>
using namespace std;

int main(){

ofstream out(Hello.txt);
out << Hello World!\n;
out.close();

string message;
ifstream in(Hello.txt);
getline(in, message);

return 0;
}

R 9.8
#include<sstream>
#include<string>
using namespace std;

string convert(double d){
ostringstream oss;
oss << d;
return oss.str();
}

double convert(string s){
double d;
istringstream iss(s);
iss >> d;
return d;
}

int main(){

double x = convert(3.14);
string s = convert(3.14);

return 0;
}
Chapter 10 Recursion (pp. 437-442)
R 10.7
#include<assert.h>
using namespace std;

double raise(double x, unsigned int n){
assert(x > = 0);
// base case
if(n == 0) return 1;
else{
return x*raise(x, n-1);
}
}

P 10.7
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;

int maximum(vector<int> values){
assert(values.size() > 0);
// base case
if(values.size() == 1) return values[0];
else{
// recursive case
int last = values.back();
values.pop_back();
int max_rest = maximum(values);
if(last > max_rest)

return last;
else

return max_rest;
}
}
int main(){
int nums[] = {1, 4, 2, 9, 8, 5, 0};
// elements of numbers are the values of nums
// arguments in vector constructor are pointers
// to array elements in nums (nums+7 is after 0)
vector<int> numbers(nums, nums+7);
cout << maximum(numbers) << endl;
return 0;
}
P 10.10
#include<iostream>
#include<vector>
#include<assert.h>
#include<string>
using namespace std;


vector<string> generate_substrings(string s){

vector<string> substrings;

// base case

if(s.length() == 0) {
substrings.push_back("");


return substrings;

}

// recursive case

else{

for(int i = 0; i < s.length(); i++)


substrings.push_back(s.substr(0, s.length() - i));
vector<string> othersubstrings =
generate_substrings(s.substr(1,s.length()-1 ));


for(int i = 0; i < othersubstrings.size(); i++){


substrings.push_back(othersubstrings[i]);


}
return substrings;
}
}

int main(){
vector<string> subs = generate_substrings("rum");
for(int i = 0; i < subs.size(); i++ ){
cout << "\"" << subs[i] << "\", ";
}
cout << endl;
return 0;
}
Chapter 11 Sorting and Searching (pp. 466-470)
R 11.3
a.
b.
c.
d.
e.
f.
g.
h.
i.
j.

O(n2)
O(n10)
O(n4)
O(n4)
O(n3)
O(n3)
O(n)
O(n2)
O(2n)
O(n)

R 11.5
T(1000) = 5
T(N) = cN for some c > 0 and for all N sufficiently large.
T(2000)/T(1000) = 2000c/1000c = 2
Thus T(2000) = 2T(1000) = 2(5) = 10 sec
T(10000)/T(1000) = 10000c/1000c = 10
So T(10000) = 10*T(1000) = 10(5) = 50 sec

R 11.6
1000
2000
3000
10000

O(n)
5
10
15
50

O(n2)
5
20
45
500

O(n3)
5
40
135
5000

O(nlogn)
5
11.00343332
17.38560627
66.66666667

O(2n)
5
5(21000)
5(22000)
5(29000)

If T(n) is O(n) then T(2n)/T(n) = 2, T(3n)/T(n) = 3, T(10n)/T(n) = 10


If T(n) is O(n2) then T(2n)/T(n) = 4, T(3n)/T(n) = 9, T(10n)/T(n) = 100
If T(n) is O(n3) then T(2n)/T(n) = 8, T(3n)/T(n) = 27, T(10n)/T(n) = 1000
If T(n) is O(nlogn) then T(2n)/T(n) = 2 + 2log(2)/log(n),
Thus T(2000) = T(1000)[2 + 2log(2)/log(1000)]
T(3n)/T(n) = 3 + 3log(3)/log(n),
Thus T(3000) = T(1000)[3 + 3log(3)/log(1000)]
T(10n)/T(n) = 10 + 10log(10)/log(n)
Thus T(10000) = T(1000)[10 + 10log(10)/log(1000)]
If T(n) = c2n
Then T(2n)/T(n) = 22n/2n = 2n
So T(2000) = 21000T(1000)
Then T(3n)/T(n) = 23n/2n = 22n
Then T(10n)/T(n) = 210n/2n = 29n
R 11.7
O(logn), O(n), O(n), O(nlogn), O(nn), O(n2logn), O(n3), O(nlogn), O(nn), O(2n)
R 11.9
O(n)
R 11.10
O(n2)
R 11.14
a.
4 7 11 4 9 5 11 7 3 5
3 7 11 4 9 5 11 7 4 5
3 4 11 7 9 5 11 7 4 5
3 4 4 7 9 5 11 7 11 5
3 4 4 5 9 7 11 7 11 5
3 4 4 5 5 7 11 7 11 9

3 4 4 5 5 7 11 7 11 9
3 4 4 5 5 7 7 11 11 9
3 4 4 5 5 7 7 9 11 11
3 4 4 5 5 7 7 9 11 11
R 11.15
a.
5 11 7 3 5 4 7 11 4 9
5 11 7 3 5
4 7 11 4 9
5 11 7 3 5
4 7 11 4 9
5 11 7
3 5 4 7 11 4 9
5 7 11 3 5
4 7 11 4 9
3 5 5 7 11
4 4 7 9 11
3 4 4 5 5 7 7 9 11 11

R 11.16
a.
-7 1 3 3 4 7 11 13
-7 1 3 3 4 7 11 13
-7 1 3 3 4 7 11 13
-7 1 3 3 4 7 11 13
-7 1 3 3 4 7 11 13
-7 1 3 3 4 7 11 13
b.
-7 2 2 3 4 7 8 11 13
7 8 11 13
c.
-7 1 2 3 5 7 10 13
5 7 10 13
10 13

Chapter 12 Lists, Queues ,and Stacks (pp. 498-503)


R 12.1
You may insert a new element before any node. You may also insert after the last
node. Thus there are n+1 legal positions for inserting a new element.
There are n legal positions for erasing an element since there are n nodes.
R 12.3
void print(const list<int>& l){
for(list<int>::iterator i = l.end(); i != l.begin(); i--){
if(i != l.end()) cout << *i << ;
}
if(l.begin() != l.end()) cout << *l.begin() << endl;
}

R 12.4
Tom <->Harry <-> Dick
^
^
first
last
R 12.5
Dick
Tom
Harry
R 12.6

R 12.7
List advantages over vectors
Adding or removing elements in the middle of a list is more efficient: O(1) time.
Vector advantages over lists
Random access of elements is more efficient: O(1) time.
R 12.8
Due to the large number of lookups, I would use a vector instead of a linked list
since random access of elements is more efficient.

R 12.9
A collection of appointments would have more insertion and removal operations
than lookup operations. Thus I would use a linked list instead of a vector to hold
a collection of appointment objects.
R 12.10
Since cards are removed from the top of the deck, but inserted at the bottom of
the deck, I would use a queue to store the cards.
R 12.12
Inserting an element in the middle of a list is a constant time operation. However,
since you would have to shift vector elements to the right of the inserted element
over by 1, insertion in the middle of a vector at index k is an O(k) algorithm.
R 12.15
Standard Notation (SN) Polish Notation (PN)
3+4
+34
1x2+3
+*12 3
1x (2+3)
*1+23
(2-4) x (3+4)
*-24+34
1+2+3+4
+ + + 12 3 4

Reverse Polish Notation (RPN)


34+
12*3+
123+*
2434+*
12+3 +4+

R 12.16
The first stack reverses the order of the strings. Starting with Z and ending at
A, these letters are pushed onto a second stack (with A ending on top).
Popping these letters form the second stack will make the strings appear in
alphabetical order.
R 12.17
When implementing a stack using a linked list, push and pop are both constant
time O(1) operations since insertion and removal of a list element are O(1) at the
beginning of the list
R 12.18
When implementing a stack using a vector,
push() (resp pop()) is usually constant time O(1) but occasionally much slower
O(N) since the push_back() (resp pop_back()) function for vector is what will be
used. When the vector does not need to resize itself before inserting (resp
removing) an element, push_back (resp pop_back()) is O(1). However, the

resize operation is O(N) due to the copy of the old dynamic array into the new
larger (resp smaller) dynamic array inside the vector object.
R 12.19
When implementing a queue using a linked list, pop is constant time O(1) since
removal of the first element of a linked list is always O(1).
When implementing a queue using a linked list, push is linear time O(N) since
insertion will be at the end of the list so we have to visit every node in the list with
an iterator to reach the penultimate element. The actual insertion at the end of
the linked list is O(1) provided we already have an iterator to the penultimate
element.
R 12.20
When implementing a queue using a vector, pop is usually constant time O(1) but
occasionally much slower O(N) (see R 12.18).
When implementing a queue using a vector, push is O(N) since we have to add
an element to the end of the vector (vector function push_back is usually O(1) but
occasionally O(N) thus, we say that push_back takes amortized O(1) time
which is written as O(1)+) and then shift all elements one position to the right (a
O(N) operation) before inserting the new element at index 0.
P 12.4
template<typename T>
list<T> merge(list<T>& l1, list<T>& l2){

list<T> merged;

list<T>::iterator i = l1.begin();
list<T>::iterator j = l2.begin();

while( !(i == l1.end() || j == l2.end() ) ) {


merged.insert(merged.end(), *i);


++i;

merged.insert(merged.end(), *j);

++j;

}

while( !(i == l1.end() ) ){

merged.insert(merged.end(), *i);


++i;

}

while( !(j == l2.end() ) ) {

merged.insert(merged.end(), *j);


++j;

}

return merged;}

P 12.7
// using List class defined on p.487
void List::push_front(string data){
insert(begin(), data);
}
P 12.9
// using List class defined on p.487
unsigned int List::get_size()const{
unsigned int size = 0;
for(Iterator i = begin(); !(i.equals(end())); i.next()) {
size++;
}
return size;
}
P 12.11
R 13.1

Chapter 13 Sets, Maps, and Priority Queues (pp. 540-544)

set
R 13.2
map
R 13.3
multimap
R 13.4
Priority queue
R 13.6
Nodes should store data of type vector<T>

R 13.9
Adam
Eve
Dick
Romeo
Juliet Tom
Harry
P 13.3
P 13.6
P 13.10
Chapter 14 Operator Overloading (pp. 586-588)
R 14.5
When that operator needs access to private data. Certain operators such as the
assignment operator = and the compound assignment operators +=, -=, /=, *=,
%= must be member functions.
R 14.7
The operators << and >> cannot be defined as member functions since the
calling object of a member operator must be the left operand. For operator <<,
the left operand is an ostream object, not an object of your class,
R 14.8
There is a prefix and a postfix version for both the increment ++ and the
decrement -- operators. The function call operator () can also have multiple
versions.
R 14.9
The prefix operator returns a reference. The postfix operator returns a value.
Thus the prefix should be called when you have a choice since returning by
reference is more efficient.
R 14.13
You must override the assignment operator if objects of your class manage
dynamic (heap) memory to avoid a shallow copy. An object manages heap
memory if it contains pointers to variables defined on the heap.

Chapter 15 Categories of Memory (pp. 631-640)


R 15.3
master_count is global variable (static data memory)
internal_count is static variable (static data memory)
increment is a stack variable (stack memory)
i is a stack variable (stack memory)
counting_function points to code memory
R 15.5
secret_message returns a pointer to a local variable message_buffer which is in
stack memory. When secret_message returns, message_buffer will be
deallocated and the pointer secret_message returns will be a wild pointer.
R 15.8
In the definition of the assignment operator, buffer needs to point to a different
size array since it may have fewer than n elements.
R 15.9
In the definition of operator=, a local variable of type char* called buffer is
declared which hides the member variable called buffer. You need to remove the
char* before the name buffer.
R 15.10
In base class
In derived class, value is 7
R 15.11
In base class, value is 7
In derived class, value is 5
R 15.13
The nodes of e contain Employee pointers. The Employee pointees are not
deallocated when the function f returns. The list nodes are all deallocated,
leaving the Employee objects on the heap with no pointer variables pointing to
them. Hence this code creates memory leak.
R 15.14
You cannot define a constructor of the form X(X b). Passing b by value will
cause an infinite recursion: Since b is passed by value, the constructor X(X b) will
call itself to make a clone of b inside the function. This triggers an infinite

recursion. If b were passed by reference, the copy constructor would not call
itself and thus would not cause an infinite chain of constructor calls.
Chapter 16 Templates (pp. 663-664)

R 16.2
a. Cannot deduce value of type parameter T from the function call
b. Redefinition of type parameter T (it appears twice in the template prefix)
c. Cannot not deduce the template argument from T2 from the function call.
R 16.3
You have to specify type parameters when you instantiate a class template, but
not when you instantiate a function template since template type parameter
values are inferred from the arguments in a template function call.
P 16.1
template<typename T>
void selection_sort(T a[], const int size){
T smallest;

for(int i = 0; i < size-1; i++){

smallest = i;
// find the index of the smallest unsorted item
// (ith smallest overall)

for(int j = i+1; j < size; j++){



if(a[j] < a[smallest]){



smallest = j;



}


}


// swap the ith element with the ith smallest element


T temp = a[i];
a[i] = a[smallest];
a[smallest] = temp;

}
}

También podría gustarte