Exercise 10

Added Exercise 10 to Repo
This commit is contained in:
JirR02 2025-05-13 16:15:48 +02:00
parent 0a9a42efee
commit a20a6508da
6 changed files with 469 additions and 0 deletions

View File

@ -0,0 +1,46 @@
#+title: Task 1a: Understanding Pointers: - Lookup
#+author: JirR02
* Task Description
:PROPERTIES:
:CUSTOM_ID: task-description
:END:
Complete the definition of function lookup by editing the file
=lookup.cpp= according to its specified pre- and post conditions.
We provide a test program using the implemented function to perform
lookup on a vector.
** Input
:PROPERTIES:
:CUSTOM_ID: input
:END:
The program accepts
- the length of the vector, =l=,
- =l= vector elements, and
- a lookup index =i=.
For example:
means a 3-element vector =[9, 8, 7]= and the lookup index 1.
** Output
:PROPERTIES:
:CUSTOM_ID: output
:END:
The test program prints the value of the element at the lookup index.
For example, for the input given above, this value is 8.
* Solution
:PROPERTIES:
:CUSTOM_ID: solution
:END:
#+begin_src cpp
#include "lookup.h"
// PRE: 0 <= i < vec.size()
// POST: Returns the address of the i-th element of vec.
const int *lookup(const std::vector<int> &vec, const int i) { return &vec[i]; }
#+end_src

View File

@ -0,0 +1,45 @@
#+title: Task 1b: Understanding Pointers - Add
#+author: JirR02
* Task Description
:PROPERTIES:
:CUSTOM_ID: task-description
:END:
Complete the definition of function add by editing the file =add.cpp=
according to its specified pre- and post conditions.
We provide a test program using the implemented function to add two
values given by the user.
** Input
:PROPERTIES:
:CUSTOM_ID: input
:END:
Integers a, b.
For example
#+begin_src shell
21 35
#+end_src
** Output
:PROPERTIES:
:CUSTOM_ID: output
:END:
The test program prints the sum of a and b.
For example, for the input given above this value is 56.
* Solution
:PROPERTIES:
:CUSTOM_ID: solution
:END:
#+begin_src cpp
#include "add.h"
// PRE: a, b, and res are valid pointers to integer values.
// POST: integer at location res contains the result of adding the integer at
// location a and the integer at location b.
void add(int *res, const int *a, const int *b) { *res = *a + *b; }
#+end_src

View File

@ -0,0 +1,69 @@
#+title: Task 2: [Exam 2022.08 (ITET/MATH/PHYS/RW)] max difference
#+author: JirR02
* Task Description
:PROPERTIES:
:CUSTOM_ID: task-description
:END:
Given the iterators to a vector composed of integers between 0 and
2147483647 (included), return the highest absolute difference between
two neighbouring elements. You can assume that the given range always
includes at least two elements.
Note: The vector is propagated with values that are provided at the
beginning of the execution. The input accepts a sequence of numbers
terminated with -1.
** Function
:PROPERTIES:
:CUSTOM_ID: function
:END:
Implement the function largest_difference in functions.h according to
its pre- and postconditions.
*Rules*:
- The functions must satisfy their respective postconditions.
- You are not allowed to change the function signatures.
- You are not allowed to use additional libraries.
*Hints*:
- You do not need to check the pre- and postconditions (no asserts
necessary).
- The program must compile in order for the autograder to work.
- We recommend *strongly* to submit partial solutions as soon they are
successful.
* Solution
:PROPERTIES:
:CUSTOM_ID: solution
:END:
#+begin_src cpp
#pragma once
#include <vector>
using iterator = std::vector<int>::const_iterator;
// PRE: iterator pair [begin,end) specifies a valid range
// within a vector (begin is included, end is not) containing numbers
// in [0, 2147483647]. The range in the vector comprises at least two
// elements.
// POST: returns the largest absolute difference between two neighbouring
// numbers in the vector.
//
// Example:
// * [1, 5, 2, 5, 7, 6] ~~> 4
// * [2, 9, 1] ~~> 8
int largest_difference(iterator begin, iterator end) {
int max_dif = 0;
end = --end;
while (begin != end) {
int val1 = *begin;
int val2 = *++begin;
if (std::abs(val2 - val1) > max_dif)
max_dif = std::abs(val2 - val1);
}
return max_dif;
}
#+end_src

View File

@ -0,0 +1,185 @@
#+title: Task 3: Dynamic Queue
#+author: JirR02
* Task 3: Dynamic Queue
:PROPERTIES:
:CUSTOM_ID: task-3-dynamic-queue
:END:
Your objective is to implement your own queue class with integer values
as a dynamic data structure.
A queue provides the two basic operations: enqueue and dequeue. The
operation enqueue adds a new element to the back of the queue. The
operation dequeue removes the first element from the queue:
[[/queue_example.png]]
A common way to implement a queue is using a linked list, as the one
that was shown in the lecture. In order to be able to both enqueue and
dequeue, we need to access respectively the first and last elements of
the list.
*Procedure*: The queue declaration is already provided. Your task is to
fill the missing definitions for the required functions, marked by
comments =// TODO= in =queue.cpp=. Function annotations (pre- and
postconditions), found along declarations in the header =queue.h=,
explain what each function is supposed to do. You may (and probably will
have to) add auxiliary non-member functions in =queue.cpp= in order to
implement some of the functions.
A class invariant helps to detect implementation problems early. For
this queue, we have the following class invariant: Either both pointers
=first= and =last= are set to =nullptr= or both are not set to
=nullptr=. The invariant is checked after every operation. If the
invariant is not satisfied, the program exits.
Subtasks:
1. Implement the default constructor of class Queue.
2. Implement the queue operations: member functions enqueue, dequeue and
=is_empty=.
3. Implement the member function =print_reverse= to print the content of
a queue to =std::cout= in reverse order. To output the queue content
(output operator), use the following format: bracket open ([) , zero
or more integer numbers separated by spaces, bracket close (]). E.g.,
the empty queue must be output like this: =[]=, the queue containing
elements =13, 7, and 42= (from first to last): =[42 7 13]=.
The function =print_reverse= must be implemented through an auxiliary
function traversing the queue recursively, from a Node pointer given as
argument. In particular, the implementation of =print_reverse= *must
not* use loop structures. We provide implementation of function =print=
printing the content of a queue in regular order as a reference.
/Optional/: Think of ways to implement =print= and =print_reverse= with
loops instead of recursion (do not change your submission). In
particular, try to find a way to implement =print_reverse= that does not
make use of unbounded auxiliary storage.
** Input & Output
:PROPERTIES:
:CUSTOM_ID: input-output
:END:
The =main= function of the program initially creates an empty queue and
enters an endless loop where the following operations can be executed:
- enqueue x: adds x to the end of the queue
- dequeue: removes the first element from the queue and prints it to the
console.
- is_empty: prints 1 to the console if the queue is empty, otherwise 0.
- print: prints the queue (in regular order) to the console.
- print_reverse: prints the queue in reverse order to the console.
- end: quits the program
*Example*:
#+begin_src shell
is_empty
1
enqueue 5
enqueue 7
print
[5 7]
print_reverse
[7 5]
is_empty
0
dequeue
5
dequeue
7
is_empty
1
end
#+end_src
*Note*: Invariant checking is already done outside the class, so there
is no need to invoke the check_invariant() method in your code.
* Solution
:PROPERTIES:
:CUSTOM_ID: solution
:END:
#+begin_src cpp
#include "queue.h"
#include <cassert>
#include <iostream>
/////////////////////////////////////////////////////////////////////////////
// IMPLEMENTATION
/////////////////////////////////////////////////////////////////////////////
Queue::Queue() /*TODO*/ {
first = nullptr;
last = nullptr;
}
void Queue::enqueue(int value) {
Node *enqVal = new Node(value, nullptr);
if (first == nullptr) {
first = enqVal;
last = enqVal;
} else {
last->next = enqVal;
last = enqVal;
}
}
int Queue::dequeue() {
const int n = first->value;
first = first->next;
if (is_empty()) {
last = nullptr;
}
return n;
}
bool Queue::is_empty() const {
if (first == nullptr)
return true;
else
return false;
}
void rec_print_reverse(Node *refLast, Node *last, Queue &revQueue) {
if (refLast == last) {
revQueue.enqueue(refLast->value);
return;
}
rec_print_reverse(refLast->next, last, revQueue);
revQueue.enqueue(refLast->value);
}
void Queue::print_reverse() const {
Queue revQueue;
if (first == nullptr)
revQueue.print();
else {
Node *refLast = first;
rec_print_reverse(refLast, last, revQueue);
revQueue.print();
}
}
// PRE: -
// POST: print the sequence of integers in nodes reachable from n,
// in order, with one space before each integer.
void print_node(Node *n) {
if (n != nullptr) {
std::cout << " " << n->value;
print_node(n->next);
}
}
void Queue::print() const {
std::cout << "[";
if (first != nullptr) {
std::cout << first->value;
print_node(first->next);
}
std::cout << "]";
}
#+end_src

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -0,0 +1,124 @@
#+title: Task 4: Decomposing a Set into Intervals
#+author: JirR02
* Task
:PROPERTIES:
:CUSTOM_ID: task
:END:
Any finite set of integers can be uniquely decomposed as a union of
disjoint maximal integer intervals, e.g as the union of non-overlapping
intervals which are as large as possible. For example, the set
\(X = \{ 1,2,3,5,6,8 \}\) decomposes as
\(X = [1,3] cup [5,6] cup [8,8]\). Note that
\(X = [1,2] cup [3,3] cup [5,6] cup [8,8]\) or
\(X = [1,2] cup [5,6] cup [5,6] cup [8,9]\) are not valid
decompositions, as \([1,2]\) and \([3,3]\) are not maximal interval
subsets of , and intervals may not repeat.
Write a program that inputs a set of integers, as the (possibly
repeating) sequence of its members, and outputs the interval
decomposition of the set in ascending order of boundaries.
/Reminder/: ordered sets can be represented in C++ using the
=std::set<...>= container, in which elements are added using the
=insert= method. Iteration (using iterators) in ordered sets takes place
in increasing order.
=Hint=: You may first define a function that, from two =std::set=
iterators =first= and =last=, finds the largest integer interval
starting from =first= and ending before =last=, and returns an iterator
just after this interval.
* Input
:PROPERTIES:
:CUSTOM_ID: input
:END:
A set of non-negative integer, given as the sequence of its members
followed by a negative integer. The sequence can be in any order and may
feature repetitions.
Example:
#+begin_src shell
3 5 8 6 5 3 2 1 -1
#+end_src
* Output
:PROPERTIES:
:CUSTOM_ID: output
:END:
The interval decomposition of the input set, with interval given in
increasing order of boundaries. The interval decomposition must be given
as a parenthesized sequence of intervals, with intervals separated by
the character U. Intervals themselves must be given by their lower and
upper bound, separated by a comma and parenthesized by brackets, with
the lower bound coming first.
Example:
#+begin_src shell
([1,3]U[5,6]U[8,8])
#+end_src
* Solution
:PROPERTIES:
:CUSTOM_ID: solution
:END:
#+begin_src cpp
#include <iostream>
#include <set>
using namespace std;
void find_interval(set<int>::iterator &first, set<int>::iterator &last,
set<pair<int, int>> &Interval) {
if (first == last)
return;
int firstElement = *first;
int curElement = *first;
while ((++first != last) && (*first - curElement <= 1)) {
curElement = *first;
}
pair<int, int> curInterval = {firstElement, curElement};
Interval.insert(curInterval);
find_interval(first, last, Interval);
}
int main() {
int in;
set<int> Set;
set<pair<int, int>> Interval;
cin >> in;
while (in >= 0) {
Set.insert(in);
cin >> in;
}
set<int>::iterator first = Set.begin();
set<int>::iterator last = Set.end();
find_interval(first, last, Interval);
int size = Interval.size();
int count = 1;
cout << "(";
for (pair<int, int> h : Interval) {
cout << "[" << h.first << "," << h.second;
if (count < size)
cout << "]" << "U";
else
cout << "]";
++count;
}
cout << ")";
return 0;
}
#+end_src