Zain Computer Assignment
Zain Computer Assignment
Q1: Complete the following function that adds up all the positive values in an integer vector. For
example, if vector vec contains the elements 3, -3, 5, 2, −1, and 2, the call sum_positive(vec) would
evaluate to 12, since 3 + 5 + 2 + 2 = 12. The function returns zero if the vector is empty. The function
does not affect the contents of the vector.
Q2: Complete the following function that counts the even numbers in an integer vector. For example, if
vector vec contains the elements 3, 5, 4, −1, and 0, the call count_evens(vec) would evaluate to 2, since
the vector contains two even numbers: 4 and 0. The function returns zero if the vector is empty. The
function does not affect the contents of the vector.
Q3: Complete the following function that counts the even numbers in a 2D vector of integers.
Q4: Complete the following function that compares two integer vectors to see if they contain the same
elements in the same positions. The function returns true if the vectors are equal; otherwise, it returns
false. For example, if vector vec1 contains the elements 3, 5, 2, −1, and 2, and vector vec2 contains the
elements 3, 5, 2, −1, and 2, the call equals(vec1, vec2) would evaluate to true. If instead vector vec2
contains the elements 3, 2, 5, −1, and 2, the call equals (vec1, vec2) would evaluate to false (the second
and third elements are not in the same positions). Two vectors of unequal sizes cannot be equal. The
function does not affect the contents of the vectors.
return true;
}
Assignment # 08
Q1: Complete the following function that determines if all the elements in one vector also appear in
another. The function returns true if all the elements in the second vector also appear in the first;
otherwise, it returns false. For example, if vector vec1 contains the elements 3, 5, 2, −1, 7, and 2, and
vector vec2 contains the elements 5, 7, and 2, the call contains(vec1, vec2) would evaluate to true. If
instead vector vec2 contains the elements 3, 8, −1, and 2, the call contains(vec1, vec2) would evaluate
to false (8 does not appear in the first vector). Also If vector vec2 contains the elements 5, 7, 2, and 5,
the call contains(vec1, vec2) would evaluate to false (5 appears twice in vec2 but only once in vec1, so
vec1 does not contain all the elements that appear in vec2). The function does not affect the contents of
the vectors.
return true;
}
This function is efficient because it only iterates over the vector v2 once. It is also correct because it
handles all possible cases, including empty vectors and vectors with different elements.
Here is an example of how to use the contains() function:
if (contains_all) {
std::cout << "The first vector contains all the elements of the second
vector." << std::endl;
} else {
std::cout << "The first vector does not contain all the elements of the
second vector." << std::endl;
}
Output:
The first vector contains all the elements of the second vector.
Q2: Suppose your task is to implement the function with the prototype
When you implement the body of proc, how can you determine the size of vector v?
Ans: There are two ways to determine the size of a vector v in the C++ function void
proc(std::vector v):
1. Use the std::vector::size() member function. This function returns the number of elements in
the vector.
2. Use the v.size() expression. This is a shorthand for the std::vector::size() member function
call.
For example, the following code shows how to use the std::vector::size() member function to
determine the size of a vector:
void proc(std::vector v) {
The following code shows how to use the v.size() expression to determine the size of a vector:
void proc(std::vector v) {
int size = v.size();
// Do something with the size of the vector
}
Both methods are equivalent and can be used interchangeably.
Which method you choose to use is a matter of personal preference. Some programmers prefer to use
the std::vector::size() member function call because it is more explicit. Other programmers
prefer to use the v.size() expression because it is more concise.
(c) Write the C++ code that prints all the elements in collection. All the elements in the same row should
appear on the same line, and but each successive row should appear on its own line.
Ans: (a) The expression collection[15][29] represents the 30th element in the 16th row of the 2D
vector collection. This is because the 2D vector is initialized with 100 rows, each containing 200
elements. The first element in the 16th row is at index 15, and the 30th element in the 16th row is at
index 29.
(b) The 2D vector collection holds 20,000 elements, because it has 100 rows, each containing 200
elements.
(c) The following C++ code prints all the elements in the 2D vector collection, with all the elements
in the same row appearing on the same line, and each successive row appearing on its own line:
#include <vector>
#include <iostream>
return 0;
}
Output:
0 1 2 3 ... 199
1 2 3 4 ... 200
2 3 4 5 ... 201
...
99 100 101 102 ... 298
(d) The expression collection[15] represents a reference to the 16th row in the 2D vector
collection. This is because the first row in the 2D vector is at index 0, and the 16th row is at index 15.
You can then use the collection[15] reference to access all the elements in the 16th row of the 2D
vector. For example, the following code prints all the elements in the 16th row of the 2D vector
collection:
#include <vector>
#include <iostream>
int main() {
vector<vector<int>> collection(100, vector<int>(200));
This is because the 4D vector is initialized with 100 rows, each containing 200 rows, each containing 100
rows, each containing 50 elements.
Assignment # 09
Ans: C++ arrays are static data structures, meaning that their size must be known at compile time. Once
an array is allocated, its size cannot be changed. Arrays are stored in contiguous memory locations,
which makes them efficient for accessing and manipulating elements.
C++ vectors are dynamic data structures, meaning that their size can grow and shrink as needed. Vectors
are also stored in contiguous memory locations, but they can be resized at any time. This makes vectors
more flexible than arrays, but it can also make them less efficient for accessing and manipulating
elements.
Here is a table that summarizes the key differences between C++ arrays and vectors:
Resizability No Yes
Memory
Manual Automatic
allocation
Element Less
Efficient
access efficient
Dynamic size: Vectors can grow and shrink as needed, while arrays must have a fixed size at compile
time. This makes vectors more flexible and easier to use.
Automatic memory management: Vectors automatically allocate and deallocate memory as needed,
while arrays must be manually managed. This can help to prevent memory leaks and other errors.
Iterators: Vectors provide iterators, which are objects that make it easy to traverse and manipulate the
elements in a vector. Arrays do not provide iterators, so you must use manual pointer arithmetic to
access and modify the elements.
Standard library support: Vectors are part of the C++ standard library, which means that they are widely
supported and well-tested. Arrays are not part of the standard library, so they may not be as well-
supported or tested.
Here is a table that summarizes the key advantages of C++ vectors over arrays:
Iterators Yes No
Q3: Provide the statement(s) that declares and create a static array named a that can hold 20 integers.
Ans: To declare and create a static array named a that can hold 20 integers, you can use the following
statement:
int a[20];
This statement declares an array named a of type int with a size of 20 elements. The array is static,
meaning that its size is fixed at compile time.
int a[20];
Output:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Note that static arrays are not as flexible as dynamic arrays, such as std::vector. However, they can
be more efficient for some applications.
Q4: Provide the statement(s) that declare and create a dynamic array named a that can hold 20 integers.
Ans: To declare and create a dynamic array named a that can hold 20 integers, you can use the following
statement:
std::vector<int> a(20);
This statement declares a dynamic array named a of type std::vector<int> with a size of 20
elements. The array is dynamic, meaning that its size can grow and shrink as needed.
std::vector<int> a(20);
Output:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Note that dynamic arrays are more flexible than static arrays, but they can be less efficient for some
applications.
Iterators No Yes
Standard library
No Yes
support
Q5: What extra attention does a programmer need to give to a static array when its use within a
program is finished?
Ans: Static arrays are allocated on the stack when a program is running. When the program finishes
running, the stack is automatically unwound and the static arrays are deallocated. This means that
programmers do not need to explicitly deallocate static arrays when they are finished using them.
However, there are a few things that programmers should keep in mind when using static arrays:
Static arrays should not be accessed outside of the scope in which they are declared. This is because
static arrays are deallocated when the program finishes running, and accessing a deallocated array will
result in undefined behavior.
Static arrays should not be used to store data that needs to persist after the program finishes running.
This is because static arrays are deallocated when the program finishes running, and any data stored in
them will be lost.
Static arrays should not be used to store large amounts of data. This is because static arrays are
allocated on the stack, and the stack has a limited size. Using large static arrays can lead to stack
overflows.
In general, programmers should avoid using static arrays unless they are absolutely necessary. Dynamic
arrays, such as std::vector, are a more flexible and reliable choice for most applications.
Avoid accessing static arrays outside of the scope in which they are declared.
Avoid using static arrays to store data that needs to persist after the program finishes running.
Avoid using static arrays to store large amounts of data.
If you need to use a static array, make sure to use it carefully and be aware of the potential risks.
Q6: What extra attention does a programmer need to give to a dynamic array when its use within a
program is finished?
Ans: Dynamic arrays, such as std::vector, are allocated on the heap when a program is running. The
heap is a region of memory that is managed by the operating system. When a dynamic array is no longer
needed, it must be explicitly deallocated by the programmer.
It is important to deallocate dynamic arrays when they are finished being used to prevent memory leaks.
Memory leaks occur when memory is allocated to a dynamic array but is never deallocated. This can
lead to performance problems and even crashes.
Always deallocate dynamic arrays when they are finished being used.
You can use the std::vector::clear() and std::vector::shrink_to_fit() methods to
deallocate dynamic arrays.
Be aware of the potential for memory leaks if you do not properly deallocate dynamic arrays.
By following these tips, you can help to prevent memory leaks and ensure that your programs are
efficient and reliable.
Q7: What extra attention does a programmer need to give to a vector array when its use within a program
is finished?
Ans: To properly deallocate a vector array in C++, you can use the following steps:
1. Call the std::vector::clear() method to remove all the elements from the vector. This does not
deallocate the underlying memory, but it does make the vector empty.
It is important to deallocate vector arrays when they are finished being used to prevent memory leaks.
Memory leaks occur when memory is allocated to a vector array but is never deallocated. This can lead
to performance problems and even crashes.
std::vector<int> a(20);
Additional attention:
In addition to deallocating vector arrays, programmers should also avoid accessing them outside of the
scope in which they are declared. This is because vector arrays are deallocated when they go out of
scope, and accessing a deallocated vector array will result in undefined behavior.
Programmers should also avoid using vector arrays to store data that needs to persist after the program
finishes running. This is because vector arrays are deallocated when the program finishes running, and
any data stored in them will be lost.
Finally, programmers should avoid using vector arrays to store large amounts of data. This is because
vector arrays are allocated on the heap, and the heap has a limited size. Using large vector arrays can
lead to heap overflows.
By following these tips, programmers can help to prevent memory leaks, avoid undefined behavior, and
ensure that their programs are efficient and reliable.
Q8: Consider the following function that processes the elements of an array using a range:
{ // Details omitted . . . }
(a) Provide the statement that correctly calls proc with array a.
(b) Provide the statement that correctly calls proc with vector v.
Ans: (a) To correctly call the function proc() with the array a, we can use the following statement:
proc(a, a + 10);
This statement passes the beginning and ending pointers of the array a to the function proc().The a +
10 expression points to the element past the last element in the array a.
(b) To correctly call the function proc() with the vector v, we can use the following statement:
The v.data() expression returns a pointer to the first element in the vector v. The v.data() +
v.size() expression points to the element past the last element in the vector v.
Here is an example of how to use the function proc() with the array a and the vector v:
int a[10];
std::vector v;
// Process the elements of the array and vector using the proc() function
proc(a, a + 10);
proc(v.data(), v.data() + v.size());
Q9: Can you declare an array to hold a mixture of ints and doubles?
Ans: No, you cannot declare an array to hold a mixture of ints and doubles in C++. C++ is a statically
typed language, which means that the type of each variable must be known at compile time. This also
applies to arrays.
If you need to store a mixture of ints and doubles, you can use a struct or a union. A struct is a data
structure that can contain multiple members of different types. A union is a data structure that can
contain only one member at a time, but the member can be of any type.
Here is an example of how to use a struct to store a mixture of ints and doubles:
struct MyData {
int i;
double d;
};
MyData data[10];
Here is an example of how to use a union to store a mixture of ints and doubles:
union MyData {
int i;
double d;
};
MyData data[10];
Which data structure you choose to use depends on your specific needs. If you need to access the
elements of the data structure individually, then you should use a struct. If you only need to access the
data structure as a whole, then you can use a union.
It is important to note that using a union to store a mixture of ints and doubles can be dangerous, as it is
easy to accidentally access the wrong type of data. It is generally recommended to use a struct instead.
Q10: What happens if you attempt to access an element of an array using a negative index?
Ans: If you attempt to access an element of an array using a negative index in C++, the behavior is
undefined. This means that anything can happen, including program crashes, data corruption, and
unexpected results.
The reason for this is that arrays are stored in memory in contiguous blocks. When you access an
element of an array using a positive index, the compiler calculates the address of the element based on
the offset from the beginning of the array. However, when you use a negative index, the compiler
cannot calculate the address of the element correctly.
Here is an example of what can happen if you attempt to access an element of an array using a negative
index:
int a[10];
This code will most likely crash the program, but it is also possible that it will corrupt the data in the
array or produce unexpected results.
int list[100];
Ans: (a) What expression represents the very first element of list?
The expression list[0] represents the very first element of the array list. This is because the first
element of an array in C++ has index 0.
The expression list[99] represents the very last element of the array list. This is because the last
element of an array in C++ has index list.size() - 1, where list.size() is the number of
elements in the array.
(c) Write the code fragment that prints out the contents of list.
The following code fragment prints out the contents of the array list:
This code fragment uses a for loop to iterate over the elements of the array list and print each element
to the console.
The expression list[3.0] is illegal. Array indices must be integers, and 3.0 is a floating point number.
Therefore, the compiler will generate an error if you try to compile this code.
Here is an example of a legal expression for accessing an element of the array list:
int i = list[3];
This expression will access the element at index 3 of the array list.
This is because arrays are not assignable in C++. You cannot assign one array to another.
To copy the contents of one array to another, you can use a for loop to iterate over the elements of the
first array and copy them to the second array. Here is an example:
This code fragment will copy the contents of the array list2 to the array list1.
Another way to copy the contents of one array to another is to use the std::copy() function. The
std::copy() function copies a range of elements from one source container to another destination
container. Here is an example:
#include <algorithm>
This code fragment will use the std::copy() function to copy the contents of the array list2 to the
array list1.
Q13: Provide a single declaration statement that declares an integer array named list that contains the
values 45, −3, 16 and 8?
Ans: The following single declaration statement declares an integer array named list that contains the
values 45, −3, 16 and 8:
This statement declares an array named list of type int with four elements. The elements of the
array are initialized to the values 45, −3, 16, and 8, respectively.
Assignment # 10
Ans: Yes, an array keeps track of the number of elements it contains. This is because arrays are stored in
contiguous blocks of memory. When an array is created, the compiler allocates a block of memory that
is large enough to store the specified number of elements. The compiler also keeps track of the address
of the first element in the array and the size of the array in bytes.
where:
// Iterate over the elements of the array and add up all the positive
values
for (int i = 0; i < n; i++) {
if (a[i] > 0) {
sum += a[i];
}
}
This function works by first checking if the array is empty. If the array is empty, the function returns
zero. Otherwise, the function initializes a variable sum to zero and then iterates over the elements of
the array. For each element in the array, the function checks if the element is positive. If the element is
positive, the function adds the element to the variable sum.
After iterating over all the elements of the array, the function returns the variable sum. This is the sum
of all the positive values in the array.
int main() {
int arr[] = {3, -3, 5, 2, -1, 2};
int n = sizeof(arr) / sizeof(arr[0]);
return 0;
}
Output:
Q3: Complete the following function that sums the even numbers in an array of integers. For example, if
array arr contains the elements 3, 5, 2, −1, and 2, the call sum_evens(arr) would evaluate to 4, since 2 +
2 = 4. The function returns zero if the array is empty (that is, n < 1). The function does not affect the
contents of the array.
// Iterate over the elements of the array and add up all the even values
for (int i = 0; i < n; i++) {
if (a[i] % 2 == 0) {
sum += a[i];
}
}
This function works by first checking if the array is empty. If the array is empty, the function returns
zero. Otherwise, the function initializes a variable sum to zero and then iterates over the elements of
the array. For each element in the array, the function checks if the element is even. If the element is
even, the function adds the element to the variable sum.
After iterating over all the elements of the array, the function returns the variable sum. This is the sum
of all the even values in the array.
Q4: Suppose your task is to implement the function with the prototype
When you implement the body of proc, how can you determine the size of array a?
Ans: The function with the prototype void proc(int a[]) takes an array of integers as input and does
not return any value. This means that the function can perform any operation on the array, but it cannot
change the size of the array.
This function uses a for loop to iterate over the elements of the array in reverse order. For each element
in the array, the function prints the element to the console.
There are two ways to determine the size of an array a in the body of the function proc() with the
prototype void proc(int a[]);:
1. Using the sizeof() operator: The sizeof() operator returns the size of a variable or data type in
bytes. To determine the size of the array a in the body of the function proc(), you can use the
following expression:
sizeof(a) / sizeof(a[0])
2. Using the pointer arithmetic: You can also use pointer arithmetic to determine the size of the array a. To
do this, you can use the following steps:
3. Declare a pointer variable p and initialize it to the address of the first element in the array a.
4. Increment the pointer variable p until it points to the element past the last element in the array a.
5. The difference between the pointer variables p and a will be the size of the array a in bytes.
int collection[100][200];
Ans: The expression collection[15][29] represents the element at row 15 and column 29 of the
two-dimensional array collection. This array has 100 rows and 200 columns, so the element at row
15 and column 29 is the 3000th element in the array.
To access an element of a two-dimensional array, you use two indices: one for the row and one for the
column. The first index specifies the row number and the second index specifies the column number.
The indices start at 0, so the element at row 15 and column 29 is accessed using the indices 15 and 29,
respectively.
Ans: The array collection has 100 rows and 200 columns, so it has 100 * 200 = 20000 elements.
To calculate the number of elements in a two-dimensional array, you multiply the number of rows by
the number of columns. This is because each element in a two-dimensional array is identified by a
unique pair of indices: one for the row and one for the column.
Q7: Consider the declaration int collection[100][200]; Write the C++ code that prints all the elements in
collection. All the elements in the same row should appear on the same line, but each successive row
should appear on its own line.
Ans: To print all the elements in the two-dimensional array collection in C++, you can use the following
code:
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 200; j++) {
std::cout << collection[i][j] << " ";
}
std::cout << std::endl;
}
This code snippet uses two nested for loops to iterate over the rows and columns of the array. The inner
for loop iterates over the elements in each row, and the outer for loop iterates over the rows.
For each element in the array, the code snippet prints the element to the console and then prints a
space. After printing all the elements in a row, the code snippet prints a newline character.
This will print all the elements in the array collection in a tabular format, with each row appearing
on its own line.
1 2 3 4
5 6 7 8
9 10 11 12
...
19997 19998 19999 20000
Q8: Consider the declaration int collection[100][200]; What does the expression collection[15] represent?
Ans: The expression collection[15] does not represent anything valid in C++. Arrays in C++ are
indexed starting from 0, so the largest valid index for an array of size 100 is 99. Trying to access an element
of an array using an out-of-bounds index will result in undefined behavior.
In practice, this could mean anything from the program crashing to returning unexpected results. It is
important to avoid accessing arrays using out-of-bounds indices.
Q9: Consider the declaration int mesh[100][200][100][50]; How many elements does mesh hold?
Ans: The four-dimensional array mesh has dimensions 100 x 200 x 100 x 50, so it has 100 * 200 * 100 *
50 = 100000000 elements.
To calculate the number of elements in a multidimensional array, you multiply the dimensions together.
This is because each element in a multidimensional array is identified by a unique set of indices: one for
each dimension.
Q10: Rewrite the following expressions using pointer notation instead of array notation.
(a) a[4]
(b) a[1]
(c) a[0]
Ans: To rewrite the following expressions using pointer notation instead of array notation:
(a) a[4]
(b) a[1]
(c) a[0]
(a) *(a + 4)
(b) *(a + 1)
(c) *a
This is because the expression a[i] is equivalent to the expression *(a + i), where a is a pointer to
the first element of the array and i is the index of the element.
Q11: Rewrite the following expressions using array notation instead of pointer notation.
(a) *(a + 3)
(b) *a
(c) *(a + 0)
Ans: To rewrite the following expressions using array notation instead of pointer notation:
(a) *(a + 3)
(b) *a
(c) *(a + 0)
(a) a[3]
(b) a[0]
(c) a[0]
This is because the expression *(a + i) is equivalent to the expression a[i], where a is a pointer to
the first element of the array and i is the index of the element.
Q12: Rewrite the following code fragment using array notation instead of pointer notation:
{ while (n)
Ans: To rewrite the following code fragment using array notation instead of pointer notation.
This code fragment is equivalent to the original code fragment, but it uses array notation instead of
pointer notation.
Q13: Rewrite the following code fragment using pointer notation instead of array notation:
{ int s = 0;
s += a[i]; return s; }
Ans: To rewrite the following code fragment using pointer notation instead of array notation.
This code fragment is equivalent to the original code fragment, but it uses pointer notation instead of
array notation.
(a) Where will the elements of the nums array live—static memory, the stack, or the heap?
(b) Where will the elements of the grid array live—static memory, the stack, or the heap?
Ans: The elements of the nums array will live in static memory, while the elements of the grid array will
live in the heap.
Static memory is the memory that is allocated to the program when it is compiled and loaded into
memory. It is used to store global variables and static variables.
Dynamic memory is the memory that is allocated to the program at runtime. It is used to store dynamic
arrays, objects, and other data structures that need to be allocated and deallocated on the fly.
The nums array is a static array, which means that it is declared with a fixed size. It is also initialized with
values, which means that it will be allocated memory when the program is compiled and loaded into
memory. Therefore, the elements of the nums array will live in static memory.
The grid array is a dynamic array, which means that its size is not fixed. It is allocated memory at
runtime using the new operator. Therefore, the elements of the grid array will live in the heap.
Q15: What operator should eventually be used when the new operator is used to allocate memory? What
is the consequence of its omission?
Ans: When the new operator is used to allocate memory, the delete operator should eventually be used
to free up that memory. Otherwise, the memory will leak.
Memory leaks can occur when memory is allocated but not freed. This can happen if the delete
operator is not called explicitly, or if the pointer to the allocated memory is lost.
Therefore, it is important to always call the delete operator when freeing up memory that was
allocated with the new operator.
Q16: List some common errors programmers make when dealing with dynamic memory.
Ans: Some common errors programmers make when dealing with dynamic memory include:
Forgetting to free memory: When memory is allocated dynamically, it must also be freed explicitly. If
you forget to free memory, it will leak. Memory leaks can lead to performance problems and system
instability.
Using the wrong deallocation operator: The new operator is used to allocate memory dynamically, and
the delete operator is used to free it. It is important to use the correct deallocation operator for the
type of memory that was allocated. For example, if you use the new[] operator to allocate memory for a
dynamic array, you must use the delete[] operator to free it.
Accessing memory after it has been freed: Once memory has been freed, it should not be accessed
again. Accessing freed memory can lead to undefined behavior, such as program crashes.
Using dangling pointers: A dangling pointer is a pointer that points to memory that has been freed.
Dereferencing a dangling pointer can lead to undefined behavior, such as program crashes.
Using invalid memory addresses: If you try to access memory using an invalid memory address, this can
lead to undefined behavior, such as program crashes.
Q17: Complete the following function that counts the number of negative values in a 10 × 10 integer 2D
array.
Ans: To complete the function count_negatives() that counts the number of negative values in a 10
× 10 integer 2D array, we can use the following code:
int count_negatives(int a[10][10]) {
// Initialize a counter to store the number of negative values
int count = 0;
This function works by iterating over the rows and columns of the array and checking each element. If
the element is negative, the function increments the counter. After iterating over the entire array, the
function returns the counter value.
Assignment # 11
Q1: Complete the following function that reorders the contents of a vector so they are reversed from their
original order. For example, a vector containing the elements 2, 6, 2, 5, 0, 1, 2, 3 would be transformed
into 3, 2, 1, 0, 5, 2, 6, 2. Note that your function must physically rearrange the elements within the vector,
not just print the elements in reverse order.
void reverse(std::vector& v)
Ans: To complete the function reverse() that reorders the contents of a vector so they are reversed
from their original order, we can use the following code:
void reverse(std::vector& v) {
// Get the length of the vector.
int n = v.size();
// Iterate over the vector, swapping the elements at the beginning and end.
for (int i = 0; i < n / 2; i++) {
std::swap(v[i], v[n - i - 1]);
}
}
This function works by iterating over the vector and swapping the elements at the beginning and end.
This process continues until the middle of the vector is reached. At this point, all of the elements in the
vector have been swapped and the vector is reversed.
Q2: Complete the following function that reorders the contents of a vector so that all the even numbers
appear before any odd number. The even values are sorted in ascending order with respect to
themselves, and the odd numbers that follow are also sorted in ascending order with respect to
themselves. For example, a vector containing the elements 2, 1, 10, 4, 3, 6, 7, 9, 8, 5 would be
transformed into 2, 4, 6, 8, 10, 1, 3, 5, 7, 9 Note that your function must physically rearrange the
elements within the vector, not just print the elements in reverse order.
void special_sort(std::vector& v)
Ans: To complete the function special_sort() that reorders the contents of a vector so that all the
even numbers appear before any odd number, with the even values sorted in ascending order with
respect to themselves and the odd numbers that follow also sorted in ascending order with respect to
themselves, we can use the following code:
void special_sort(std::vector& v) {
// Initialize two vectors to store the even and odd numbers.
std::vector<int> even_numbers;
std::vector<int> odd_numbers;
// Iterate over the vector and partition the elements into the even and odd
vectors.
for (int i = 0; i < v.size(); i++) {
if (v[i] % 2 == 0) {
even_numbers.push_back(v[i]);
} else {
odd_numbers.push_back(v[i]);
}
}
// Clear the original vector and append the even and odd vectors to it.
v.clear();
v.insert(v.end(), even_numbers.begin(), even_numbers.end());
v.insert(v.end(), odd_numbers.begin(), odd_numbers.end());
}
This function works by first partitioning the elements of the vector into two vectors: one for the even
numbers and one for the odd numbers. Then, the two vectors are sorted in ascending order. Finally, the
original vector is cleared and the even and odd vectors are appended to it.
Q3: Complete the following function that shifts all the elements of a vector backward one place. The last
element that gets shifted off the back end of the vector is copied into the first (0th) position. For example,
if a vector containing the elements 2, 1, 10, 4, 3, 6, 7, 9, 8, 5 is passed to the function, it would be
transformed into 5, 2, 1, 10, 4, 3, 6, 7, 9, 8 Note that your function must physically rearrange the elements
within the vector, not just print the elements in the shifted order.
void rotate(std::vector& v)
Ans: To complete the following function that shifts all the elements of a vector backward one place, with
the last element that gets shifted off the back end of the vector copied into the first (0th) position, we can
use the following code:
void rotate(std::vector& v) {
// Get the last element of the vector.
int last_element = v.back();
This function works by first getting the last element of the vector. Then, it removes the last element of
the vector. Finally, it inserts the last element at the beginning of the vector.
Assignment # 12
Q1: Complete the following function that determines if the number of even and odd values in a vector is
the same. The function will return true if the vector contains 5, 1, 0, 2 (two evens and two odds), but it
would return false for the vector containing 5, 1, 0, 2, 11 (too many odds). The function should return true
if the vector is empty, since an empty vector contains the same number of evens and odds (0). The
function does not affect the contents of the vector.
Ans: To complete the following function that determines if the number of even and odd values in a
vector is the same, we can use the following code:
// Iterate over the vector and count the number of even and odd values.
for (auto element : v) {
if (element % 2 == 0) {
even_count++;
} else {
odd_count++;
}
}
// Return true if the number of even and odd values is the same.
return even_count == odd_count;
}
This function works by first initializing two counters to store the number of even and odd values. Then, it
iterates over the vector and counts the number of even and odd values. Finally, it returns true if the
number of even and odd values is the same.
Q2: Complete the following function that returns true if vector a contains duplicate elements; it returns
false if all the elements in a are unique. For example, the vector 2, 3, 2, 1, 9 contains duplicates (2 appears
more than once), but the vector 2, 1, 0, 3, 8, 4 does not (none of the elements appear more than once).
An empty vector has no duplicates. The function does not affect the contents of the vector.
Ans: To complete the following function that returns true if vector a contains duplicate elements; it
returns false if all the elements in a are unique, we can use the following code:
bool has_duplicates(const std::vector& v) {
// Create a set from the vector.
std::set<int> s(v.begin(), v.end());
// If the length of the set is not equal to the length of the vector, then
there are duplicate elements in the vector.
return s.size() != v.size();
}
This function works by first creating a set from the vector. A set is a data structure that stores unique
elements. If the length of the set is not equal to the length of the vector, then there are duplicate
elements in the vector.
Q3: Can binary search be used on an unsorted vector? Why or why not?
Ans: No, binary search cannot be used on an unsorted vector. Binary search works by repeatedly dividing
the search space in half until the target element is found. This requires that the elements in the search
space be sorted in ascending order. If the elements are not sorted, then the binary search algorithm will
not be able to find the target element correctly.
[5, 3, 2, 1, 4]
If we try to search for the element 4 using binary search, the algorithm will start by dividing the search
space in half, giving us the following two subvectors:
[5, 3, 2, 1]
[4]
The algorithm will then compare the target element 4 with the middle element of the first subvector,
which is 2. Since 4 is greater than 2, the algorithm will discard the first subvector and focus on the
second subvector.
The algorithm will then compare the target element 4 with the middle element of the second subvector,
which is 4. Since the target element is equal to the middle element, the algorithm will return the index
of the middle element, which is 1.
However, the element 4 is actually at index 4 in the original vector. This is because the binary search
algorithm assumed that the vector was sorted in ascending order, but it is not.
Therefore, binary search cannot be used on an unsorted vector. If you need to search for an element in
an unsorted vector, you can use a linear search algorithm, which compares the target element to each
element in the vector until it is found.
Q4: Can linear search be used on an unsorted vector? Why or why not?
Ans: Yes, linear search can be used on an unsorted vector. Linear search is a simple algorithm that works
by comparing the target element to each element in the vector until it is found. Since linear search does
not require the vector to be sorted, it can be used on unsorted vectors.
[5, 3, 2, 1, 4]
If we try to search for the element 4 using linear search, the algorithm will start by comparing the target
element 4 with the first element of the vector, which is 5. Since the target element is not equal to the
first element, the algorithm will move on to the next element.
The algorithm will continue comparing the target element to each element in the vector until it finds the
target element or it reaches the end of the vector. In this case, the algorithm will find the target element
at index 4.
Linear search is a simple and straightforward algorithm, but it is not the most efficient algorithm for
searching for elements in vectors. Linear search has a time complexity of O(n), which means that the
worst-case time for the algorithm to find the target element is proportional to the length of the vector.
If you need to search for elements in large vectors, you may want to use a more efficient algorithm, such
as binary search. However, linear search can be a good choice for searching for elements in small
vectors.
Q5: Complete the following function is_ascending that returns true if the elements in a vector of
integers appear in ascending order (more precisely, non-descending order, if the vector contains
duplicates). For example, the following statement
would print true. The nonexistent elements in an empty vector are in ascending order because they
cannot be out of order.
bool is_ascending(std::vector& v)
Ans: To complete the function is_ascending that returns true if the elements in a vector of integers
appear in ascending order (more precisely, non-descending order, if the vector contains duplicates), we
can use the following code:
bool is_ascending(std::vector& v) {
// If the vector is empty, return true.
if (v.empty()) {
return true;
}
// Iterate over the vector and compare each element to the previous
element.
for (int i = 1; i < v.size(); i++) {
if (v[i] < v[i - 1]) {
return false;
}
}
// If we reach the end of the vector without finding any elements that are
out of order, then the vector is in ascending order and we can return true.
return true;
}
This function works by first checking if the vector is empty. If the vector is empty, then there are no
elements to compare and the vector is considered to be in ascending order.
Otherwise, the function iterates over the vector and compares each element to the previous element. If
any element is less than the previous element, then the vector is not in ascending order and the
function returns false.
If we reach the end of the vector without finding any elements that are out of order, then the vector is
in ascending order and the function returns true.
Q6: Consider a sort function that uses the is_ascending function from the previous problem. It uses a
loop to test the permutations of a vector of integers. When it finds a permutation that contains all the
vector’s elements in ascending order it exits the loop. Do you think this would be a good sorting
algorithm? Why or why not?
Ans: The sorting algorithm you described, which uses the is_ascending function to test permutations
of a vector of integers, would not be a good sorting algorithm. It would be very inefficient and slow,
especially for large vectors.
The time complexity of this algorithm would be O(n!), where n is the number of elements in the vector.
This is because the algorithm has to test all possible permutations of the vector, which is a factorial of n.
For example, if the vector has 10 elements, the algorithm would have to test 10! = 3,628,800
permutations.
Even for a small vector of 10 elements, this algorithm would be very slow. For a larger vector, such as a
vector with 100 elements, the algorithm would be impractical to run.
There are much more efficient sorting algorithms available, such as quicksort and mergesort. These
algorithms have a time complexity of O(n log n), which is much better than O(n!).
In addition, the sorting algorithm you described would not be stable. A stable sorting algorithm is one
that preserves the original order of equal elements in the sorted output. The algorithm you described
would not preserve the original order of equal elements because it simply tests permutations of the
vector.
{1, 2, 2, 3}
If we sort this vector using the algorithm you described, the sorted output could be either of the
following:
{1, 2, 2, 3}
{1, 2, 3, 2}
The original order of the equal elements 2 has not been preserved.
In conclusion, the sorting algorithm you described would not be a good sorting algorithm because it is
very inefficient, slow, and not stable. There are much better sorting algorithms available that are
efficient, fast, and stable.