Exercise 10
Added Exercise 10 to Repo
This commit is contained in:
parent
0a9a42efee
commit
a20a6508da
46
Informatik_I/Exercise_10/Task_1a/README.org
Normal file
46
Informatik_I/Exercise_10/Task_1a/README.org
Normal 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
|
45
Informatik_I/Exercise_10/Task_1b/README.org
Normal file
45
Informatik_I/Exercise_10/Task_1b/README.org
Normal 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
|
69
Informatik_I/Exercise_10/Task_2/README.org
Normal file
69
Informatik_I/Exercise_10/Task_2/README.org
Normal 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
|
185
Informatik_I/Exercise_10/Task_3/README.org
Normal file
185
Informatik_I/Exercise_10/Task_3/README.org
Normal 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
|
BIN
Informatik_I/Exercise_10/Task_3/queue_example.png
Normal file
BIN
Informatik_I/Exercise_10/Task_3/queue_example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
124
Informatik_I/Exercise_10/Task_4/README.org
Normal file
124
Informatik_I/Exercise_10/Task_4/README.org
Normal 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
|
Loading…
x
Reference in New Issue
Block a user