Generic Algorithms Flashcards

1
Q

What happens when fill_n algorithm’s destination is smaller than as used in fil_n

A

The fill_n function assumes that it is safe to write the specified number ofelements. That is, for a call of the form
fill_n(dest, n, val)
fill_n assumes that dest refers to an element and that there are at least nelements in the sequence starting from dest. It is a fairly common beginner mistake to call fill_n (or similar algorithms that write to elements) on a container that has no elements:

vector vec; // empty vector
// disaster: attempts to write to ten (nonexistent) elements in vec
fill_n(vec.begin(), 10, 0);

This call to fill_n is a disaster. We specified that ten elements should be written, but there are no such elements—vec is empty. The result is undefined.

Algorithms that write to a destination iterator assume the destination is large
enough to hold the number of elements being written.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What is a back_inserter?

A

An insert iterator is an iterator that adds elements to a container. Ordinarily, when we assign to a container element through an iterator, we assign to the element that iterator denotes

Back_inserter takes a reference to a container and returns an insert iterator bound to that container. When we assign through that iterator, the assignment calls push_back to add an element with the given value to the container

vector vec; // empty vector
auto it = back_inserter(vec); // assigning through it adds elements to vec
*it = 42; // vec now has one element with value 42

vector vec; // empty vector
// ok: back_inserter creates an insert iterator that adds elements to vec
fill_n(back_inserter(vec), 10, 0); // appends ten elements to vec

This call to fill_n adds ten elements to the end of vec, each of which has the value 0.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

What is std::copy algorithm?

A

The copy algorithm is another example of an algorithm that writes to the elements of an output sequence denoted by a destination iterator.

int a1[] = {0,1,2,3,4,5,6,7,8,9};
int a2[sizeof(a1)/sizeof(*a1)]; // a2 has the same size as a1
// ret points just past the last element copied into a2
auto ret = copy(begin(a1), end(a1), a2); // copy a1 into a2
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is std::replace algorithm

A

The replace algorithm reads a sequence and replaces every instance of a given value with another value.

// replace any element with the value 0 with 42
replace(ilst.begin(), ilst.end(), 0, 42);

This call replaces all instances of 0 by 42. If we want to leave the original sequence unchanged, we can call replace_copy. That algorithm takes a third iterator argument denoting a destination in which to write the adjusted sequence:

// use back_inserter to grow destination as needed
replace_copy(ilst.cbegin(), ilst.cend(),
back_inserter(ivec), 0, 42);

After this call, ilst is unchanged, and ivec contains a copy of ilst with the exception that every element in ilst with the value 0 has the value 42 in ivec.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

How do we eliminate duplicates in vector

A

The unique algorithm rearranges the input range to “eliminate” adjacent duplicated entries, and returns an iterator that denotes the end of the range of the unique values. All elements after the unique end-of-range are duplicates of some value before end of range.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What is a predicate in algorithm

A

A predicate is an expression that can be called and that returns a value that can be used as a condition. The predicates used by library algorithms are either unary predicates (meaning they have a single parameter) or binary predicates (meaning they have two parameters).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What is stable sort

A

A stable sort maintains the original order among equal elements.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What is a labda expression

A

A lambda expression represents a callable unit of code.

[capture list] (parameter list) -> return type { function body }

where capture list is an (often empty) list of local variables defined in the enclosing function; return type, parameter list, and function body are the same as in any ordinary function.

The capture list is used for local nonstatic variables only; lambdas can use local statics and variables declared outside the function directly.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

What is lambda expression’s type

A
when we pass a lambda to a
function, we are defining both a new type and an object of that type: The argument is
an unnamed object of this compiler-generated class type. Similarly, when we use
auto to define a variable initialized by a lambda, we are defining an object of the
type generated from that lambda.
By default, the class generated from a lambda contains a data member
corresponding to the variables captured by the lambda. Like the data members of any
class, the data members of a lambda are initialized when a lambda object is created.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

When is a captured variable copied in lambda expression?

A

As with a parameter passed by value, it must be possible to copy such variables. Unlike parameters, the value of a captured variable is copied when the lambda is created, not when it is called:

void fcn1()
{
	size_t v1 = 42; // local variable
	// copies v1 into the callable object named f
	auto f = [v1] { return v1; };
	v1 = 0;
	auto j = f(); // j is 42; f stored a copy of v1 when we created it
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Comment about capturing variables by value in lambda expression

A

As with a parameter passed by value, it must be possible to copy such variables. Unlike parameters, the value of a captured variable is copied when the lambda is created, not when it is called:

void fcn1()
{
	size_t v1 = 42; // local variable
	// copies v1 into the callable object named f
	auto f = [v1] { return v1; };
	v1 = 0;
	auto j = f(); // j is 42; f stored a copy of v1 when we created it
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What is std::bind ?

A

The bind function can be thought of as a general-purpose function adaptor (§ 9.6, p. 368). It takes a callable object and generates a new callable that “adapts” the parameter list of the original object. The general form of a call to bind is:

auto newCallable = bind(callable, arg_list);

where newCallable is itself a callable object and arg_list is a comma-separated list of
arguments that correspond to the parameters of the given callable.

The arguments in arg_list may include names of the form _n, where n is an integer. These arguments are “placeholders” representing the parameters of newCallable. They stand “in place of” the arguments that will be passed to newCallable. The number n is the position of the parameter in the generated callable: _1 is the first parameter in newCallable, _2 is the second, and so forth.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Can we use std::bind to rearrange a function call’s

A

Yes, we can use bind to bind or rearrange the parameters in the given callable. For example, assuming f is a callable object that has five parameters, the following call to bind:

// g is a callable object that takes two arguments
auto g = bind(f, a, b, _2, c, _1);

That is, the first argument to g is bound to _1, and the second argument is bound to _2. This call to bind maps

g(_1, _2)
to
f(a, b, _2, c, _1)

That is, calling g calls f using g’s arguments for the placeholders along with the bound arguments, a, b, and c. For example, calling g(X, Y) calls
f(a, b, Y, c, X)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

How can we use std::bind to bind to a functions whos arguements can’t be copied

A
If we want to pass an object to bind without copying it, we must use the library std::ref function. There is also a cref function that generates a class that holds a reference to
const.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What are other types of iterators ?

A

In addition to the iterators that are defined for each of the containers, the library defines several additional kinds of iterators in the iterator header. These iterators include
• Insert iterators: These iterators are bound to a container and can be used to insert elements into the container.
• Stream iterators: These iterators are bound to input or output streams and can be used to iterate through the associated IO stream.
• Reverse iterators: These iterators move backward, rather than forward. The library containers, other than forward_list, have reverse iterators.
• Move iterators: These special-purpose iterators move rather than copy their elements.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What is an insert iterator?

A

An inserter is an iterator adaptor that takes a container and yields an iterator that adds elements to the specified container. There are three kinds of inserters. Each differs from the others as to where elements are inserted:

  • back_inserter creates an iterator that uses push_back.
  • front_inserter creates an iterator that uses push_front.
  • inserter creates an iterator that uses insert. This function takes a second argument, which must be an iterator into the given container. Elements are inserted ahead of the element denoted by the given iterator.

We can use front_inserter only if the container has push_front. Similarly, we can use back_inserter only if it has push_back.

17
Q

Where do inserter(s) intsert elements

A

When we call inserter(c, iter), we get an iterator that, when used successively, inserts elements ahead of the element originally denoted by iter.

  • it = va1;
    behaves as
    it = c.insert(it, val); // it points to the newly added element
    ++it; // increment it so that it denotes the same element as before

The iterator generated by front_inserter behaves quite differently from the one created by inserter. When we use front_inserter, elements are always inserted ahead of the then first element in the container.

list 1st = {1,2,3,4};
list lst2, lst3; // empty lists

// after copy completes, 1st2 contains 4 3 2 1
copy(1st.cbegin(), lst.cend(), front_inserter(lst2));
// after copy completes, 1st3 contains 1 2 3 4
copy(1st.cbegin(), lst.cend(), inserter(lst3, lst3.begin()));
18
Q

what are iostream iterators

A

An istream_iterator reads an input stream, and an ostream_iterator writes an output stream.

As an example, we can use an istream_iterator to read the standard input into a vector:

istream_iterator in_iter(cin); // read ints from cin
istream_iterator eof; // istream ‘‘end’’ iterator
while (in_iter != eof) // while there’s valid input to read
// postfix increment reads the stream and returns the old value of the iterator
// we dereference that iterator to get the previous value read from the stream
vec.push_back(*in_iter++);

we can rewrite this program as

istream_iterator in_iter(cin), eof; // read ints from cin
vector vec(in_iter, eof); // construct vec from an iterator range

We can also use iostream iteratos with algorithms like so:

istream_iterator in(cin), eof;
cout << accumulate(in, eof, 0) << endl;
19
Q

Can istream_iteratos use lazy evaluation?

A

Yes, istream_iterators Are Permitted to Use Lazy Evaluation
When we bind an istream_iterator to a stream, we are not guaranteed that it will read the stream immediately. The implementation is permitted to delay reading the stream until we use the iterator. We are guaranteed that before we dereference the iterator for the first time, the stream will have been read. F

20
Q

What are ostream_iterator ?

A

An ostream_iterator can be defined for any type that has an output operator (the &laquo_space;operator). When we create an ostream_iterator, we may (optionally) provide a second argument that specifies a character string to print following each element.

There is no empty or off-the-end ostream_iterator.

ostream_iterator out_iter(cout, “ “);
for (auto e : vec)
*out_iter++ = e; // the assignment writes this element to cout
cout &laquo_space;endl;

We can write this loop equivalently as

for (auto e : vec)
out_iter = e; // the assignment writes this element to cout
cout &laquo_space;endl;

The * and ++ operators do nothing on an ostream_iterator, so omitting them has no effect on our program.We can easily change this loop to execute on another iterator type. Moreover, the behavior of this loop will be clearer to readers of our code.

using std::copy to do the same thing

copy(vec.begin(), vec.end(), out_iter);
cout &laquo_space;endl;

21
Q

What are reverse iterators

A

A reverse iterator is an iterator that traverses a container backward, from the last element toward the first. A reverse iterator inverts the meaning of increment (and decrement). Incrementing (++it) a reverse iterator moves the iterator to the previous element; derementing (–it) moves the iterator to the next element.

For example, we can sort our vector in descending order by passing sort a pair of reverse iterators:

sort(vec.begin(), vec.end()); // sorts vec in ‘‘normal’’ order
// sorts in reverse: puts the smallest element at the end of vec
sort(vec.rbegin(), vec.rend());

// find the last element in a comma-separated list
auto rcomma = find(line.crbegin(), line.crend(), ',');

The seemingly obvious way

// WRONG: will generate the word in reverse order
cout << string(line.crbegin(), rcomma) << endl;

generates bogus output. For example, had our input been
FIRST,MIDDLE,LAST
then this statement would print TSAL!

iter -> position
cbegin() -> 1
comma -> 2
rcomma.base() -> 3
cend() -> 4
rcomma -> 5
crbegin() -> 6

1 2 3 4
FIRST,MIDDLE,LAST
5 6

Technically speaking, the relationship between normal and reverse iterators accommodates the properties of a left-inclusive range. The point is that [line.crbegin(), rcomma) and [rcomma.base(), line.cend()) refer to the same elements in line. In order for that to happen, rcomma and rcomma.base() must yield adjacent positions, rather than the same position, as must crbegin() and cend().

The fact that reverse iterators are intended to represent ranges and that these ranges are asymmetric has an important consequence: When we initialize or assign a reverse iterator from a plain iterator, the resulting iterator does not refer to the same element as the original.

22
Q

What are the Iterator categories

A

Input iterators: can read elements in a sequence. An input iterator must provide
• Equality and inequality operators (==, !=) to compare two iterators
• Prefix and postfix increment (++) to advance the iterator
• Dereference operator () to read an element; dereference may appear only on the right-hand side of an assignment
• The arrow operator (->) as a synonym for (
it).member—that is,dereference the iterator and fetch a member from the underlying object

23
Q

Describe Input Iterator

A

Input iterators: can read elements in a sequence. An input iterator must provide
• Equality and inequality operators (==, !=) to compare two iterators
• Prefix and postfix increment (++) to advance the iterator
• Dereference operator () to read an element; dereference may appear only on the right-hand side of an assignment
• The arrow operator (->) as a synonym for (
it).member—that is, dereference the iterator and fetch a member from the underlying object

Input iterators may be used only sequentially. We are guaranteed that *it++ is valid, but incrementing an input iterator may invalidate all other iterators into the stream. As a result, there is no guarantee that we can save the state of an input iterator and examine an element through that saved iterator. Input iterators, therefore, may be used only for single-pass algorithms. The find and accumulate algorithms require input iterators; istream_iterators are input iterators.

24
Q

Describe Output iterators

A

Output iterators: can be thought of as having complementary functionality to input iterators; they write rather than read elements. Output iterators must provide
• Prefix and postfix increment (++) to advance the iterator
• Dereference (*), which may appear only as the left-hand side of an assignment (Assigning to a dereferenced output iterator writes to the underlying element.)

We may assign to a given value of an output iterator only once. Like input iterators, output iterators may be used only for single-pass algorithms. Iterators used as a destination are typically output iterators. For example, the third parameter to copy is an output iterator. The ostream_iterator type is an output iterator.

25
Q

What are forward iterators

A

Forward iterators: can read and write a given sequence. They move in only one direction through the sequence. Forward iterators support all the operations of both input iterators and output iterators. Moreover, they can read or write the same element multiple times. Therefore, we can use the saved state of a forward iterator.
Hence, algorithms that use forward iterators may make multiple passes through the sequence. The replace algorithm requires a forward iterator; iterators on forward_list are forward iterators.

26
Q

What are Bidirectional iterators

A

Bidirectional iterators: can read and write a sequence forward or backward. In addition to supporting all the operations of a forward iterator, a bidirectional iterator also supports the prefix and postfix decrement (–) operators. The reverse algorithm requires bidirectional iterators, and aside from forward_list, the library containers supply iterators that meet the requirements for a bidirectional iterator.

27
Q

What are random access iterators?

A

Random-access iterators: provide constant-time access to any position in the sequence. These iterators support all the functionality of bidirectional iterators. In addition, random-access iterators support the operations:
• The relational operators (, and >=) to compare the relative positions of two iterators.
• Addition and subtraction operators (+, +=, -, and -=) on an iterator and an integral value. The result is the iterator advanced (or retreated) the integral number of elements within the sequence.
• The subtraction operator (-) when applied to two iterators, which yields the distance between two iterators.
• The subscript operator (iter[n]) as a synonym for * (iter + n).

The sort algorithms require random-access iterators. Iterators for array, deque, string, and vector are random-access iterators, as are pointers when used to access elements of a built-in array.

28
Q

What are the various algorithm parameter/naming patters

A

Algorithm Parameter Patterns

alg(beg, end, other args);
alg(beg, end, dest, other args);
alg(beg, end, beg2, other args);
alg(beg, end, beg2, end2, other args);

Algorithms with a Single Destination Iterator
A dest parameter is an iterator that denotes a destination in which the algorithm can write its output. Algorithms assume that it is safe to write as many elements as needed.

Algorithms with a Second Input Sequence
Algorithms that take either beg2 alone or beg2 and end2 use those iterators to denote a second input range.

Some Algorithms Use Overloading to Pass a Predicate
Algorithms that take a predicate to use in place of the < or == operator, and that do not take other arguments, typically are overloaded.

unique(beg, end); // uses the == operator to compare the elements
unique(beg, end, comp); // uses comp to compare the elements

Algorithms with _if Versions
Algorithms that take an element value typically have a second named (not overloaded) version that takes a predicate (§ 10.3.1, p. 386) in place of the value. The algorithms that take a predicate have the suffix _if appended:

find(beg, end, val); // find the first instance of val in the input range
find_if(beg, end, pred); // find the first instance for which pred is true

Algorithms that write to a destination append _copy to their names:
reverse(beg, end); // reverse the elements in the input range
reverse_copy(beg, end, dest);// copy elements in reverse order into dest

29
Q

what are list / forward_list specific functions

A

These operations return void.
lst.merge ( list2 ) / lst _merge ( ist 2 , comp)
Merges elements from lst2 onto lst. Both lst and lst2 must be sorted. Elements are removed from lst2. After the merge, lst2 is empty. The first version uses the < operator; the second version uses the given comparison operation.

lst. remove (val) / lst . remove_if (pred)
Calls erase to remove each element that is == to the given value or for which the given unary predicate succeeds.

lst . reverse () Reverses the order of the elements in lst.

lst. sort ( ) / lst . sort (comp)
Sorts the elements of lst using < or the given comparison operation.

lst . unique () / lst.unique(pred)
Calls erase to remove consecutive copies of the same value. The first version uses ==; the second uses the given binary predicate.

30
Q

What are list specific splice functions ( or forward_list::splice_after )

A

lst.splice(args) or flst.splice_after(args)

(p, lst2) -> p is an iterator to an element in lst or an iterator just before an element in flst. Moves all the element(s) from lst2 into lst just before p or into fist just after p. Removes the element(s) from lst 2. lst2 must have the same type as lst or flst and may not be the same list.

(p, lst2, p2) -> p2 is a valid iterator into lst 2. Moves the element denoted by p2 into lst or moves the element just after p2 into flst. lst2 can be the same list as lot or flst.

(p, lst2, b, e) -> b and e must denote a valid range in lst2. Moves the elements in the given range from lst2. lst2 and lst (or f lst) can be the same list but p must not denote an element in the given range.