diff --git a/Informatik_I/Exercise_10/Task_1a/README.org b/Informatik_I/Exercise_10/Task_1a/README.org new file mode 100644 index 0000000..f5555be --- /dev/null +++ b/Informatik_I/Exercise_10/Task_1a/README.org @@ -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 &vec, const int i) { return &vec[i]; } +#+end_src diff --git a/Informatik_I/Exercise_10/Task_1b/README.org b/Informatik_I/Exercise_10/Task_1b/README.org new file mode 100644 index 0000000..5783a11 --- /dev/null +++ b/Informatik_I/Exercise_10/Task_1b/README.org @@ -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 diff --git a/Informatik_I/Exercise_10/Task_2/README.org b/Informatik_I/Exercise_10/Task_2/README.org new file mode 100644 index 0000000..873f4ac --- /dev/null +++ b/Informatik_I/Exercise_10/Task_2/README.org @@ -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 +using iterator = std::vector::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 diff --git a/Informatik_I/Exercise_10/Task_3/README.org b/Informatik_I/Exercise_10/Task_3/README.org new file mode 100644 index 0000000..aa96fd4 --- /dev/null +++ b/Informatik_I/Exercise_10/Task_3/README.org @@ -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 +#include + +///////////////////////////////////////////////////////////////////////////// +// 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 diff --git a/Informatik_I/Exercise_10/Task_3/queue_example.png b/Informatik_I/Exercise_10/Task_3/queue_example.png new file mode 100644 index 0000000..bcbe531 Binary files /dev/null and b/Informatik_I/Exercise_10/Task_3/queue_example.png differ diff --git a/Informatik_I/Exercise_10/Task_4/README.org b/Informatik_I/Exercise_10/Task_4/README.org new file mode 100644 index 0000000..42c75d4 --- /dev/null +++ b/Informatik_I/Exercise_10/Task_4/README.org @@ -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 +#include + +using namespace std; + +void find_interval(set::iterator &first, set::iterator &last, + set> &Interval) { + if (first == last) + return; + + int firstElement = *first; + int curElement = *first; + + while ((++first != last) && (*first - curElement <= 1)) { + curElement = *first; + } + + pair curInterval = {firstElement, curElement}; + Interval.insert(curInterval); + + find_interval(first, last, Interval); +} + +int main() { + int in; + set Set; + set> Interval; + + cin >> in; + + while (in >= 0) { + Set.insert(in); + cin >> in; + } + + set::iterator first = Set.begin(); + set::iterator last = Set.end(); + + find_interval(first, last, Interval); + + int size = Interval.size(); + int count = 1; + + cout << "("; + for (pair h : Interval) { + cout << "[" << h.first << "," << h.second; + if (count < size) + cout << "]" << "U"; + else + cout << "]"; + ++count; + } + cout << ")"; + + return 0; +} +#+end_src