Skip to content
Snippets Groups Projects
Commit a1b106f7 authored by Peter Gerwinski's avatar Peter Gerwinski
Browse files

Vorbereitung 18.1.2024

parent 53904994
Branches
No related tags found
No related merge requests found
Showing
with 2518 additions and 2 deletions
No preview for this file type
...@@ -929,6 +929,8 @@ ...@@ -929,6 +929,8 @@
\end{frame} \end{frame}
\iffalse
\begin{frame} \begin{frame}
\showsection \showsection
...@@ -1103,8 +1105,6 @@ ...@@ -1103,8 +1105,6 @@
\end{frame} \end{frame}
\iffalse
\begin{frame} \begin{frame}
\shownosectionnonumber \shownosectionnonumber
......
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int content;
struct node *next;
} node;
void output_list (node *first)
{
for (node *p = first; p; p = p->next)
printf ("%d ", p->content);
printf ("\n");
}
void insert_into_list (node *what, node *where)
{
what->next = where->next;
where->next = what;
}
int main (void)
{
node *element3 = malloc (sizeof (node));
node *element7 = malloc (sizeof (node));
node *element137 = malloc (sizeof (node));
element3->content = 3;
element7->content = 7;
element137->content = 137;
node *first = element3;
element3->next = element7;
element7->next = element137;
element137->next = NULL;
output_list (first);
node *element5 = malloc (sizeof (node));
element5->content = 5;
insert_into_list (element5, element3);
output_list (first);
return 0;
}
#include <stdio.h>
#include <string.h>
void insert_into_string (char src, char *target, int pos) {
// Bestimme die Länge des Strings target
int len = strlen(target);
// Verschiebe alle Zeichen des Strings ab der Stelle pos um eine Stelle nach rechts
for (int i = len; i > pos; i--) {
target[i] = target[i-1];
}
// Füge das Zeichen src an der Stelle pos ein
target[pos] = src;
}
int main (void)
{
char test[] = "Hochshule Bochum";
insert_into_string ('c', test, 5);
printf ("%s\n", test);
return 0;
}
#include <stdio.h>
#include <string.h>
void insert_into_string (char src, char *target, int pos) {
// Bestimme die Länge des Strings target
int len = strlen(target);
// Verschiebe alle Zeichen des Strings ab der Stelle pos um eine Stelle nach rechts
for (int i = len; i > pos; i--) {
target[i] = target[i-1];
}
// Füge das Zeichen src an der Stelle pos ein
target[pos] = src;
}
void insert_into_string_sorted (char src, char *target) {
// Bestimme die Länge des Strings target
int len = strlen(target);
// Iteriere über alle Zeichen des Strings target
for (int i = 0; i < len; i++) { // Wenn das aktuelle Zeichen alphabetisch hinter src liegt, füge src an dieser Stelle ein
if (target[i] > src) {
insert_into_string(src, target, i);
return;
}
}
// Wenn src das letzte Zeichen im String ist, füge es am Ende des Strings ein
insert_into_string(src, target, len);
}
int main (void)
{
char test[100] = "";
insert_into_string_sorted ('c', test);
insert_into_string_sorted ('a', test);
insert_into_string_sorted ('d', test);
insert_into_string_sorted ('b', test);
printf ("%s\n", test);
return 0;
}
#include <stdio.h>
#include <string.h>
void insert_into_string (char src, char *target, int pos) {
// Bestimme die Länge des Strings target
int len = strlen(target);
// Verschiebe alle Zeichen des Strings ab der Stelle pos um eine Stelle nach rechts
for (int i = len; i > pos; i--) {
target[i] = target[i-1];
}
// Füge das Zeichen src an der Stelle pos ein
target[pos] = src;
}
void insert_into_string_sorted (char src, char *target) {
// Bestimme die Länge des Strings target
int len = strlen(target);
// Setze die Grenzen für die binäre Suche auf das erste und letzte Zeichen des Strings
int left = 0;
int right = len - 1;
// Führe die binäre Suche durch, bis left und right auf dasselbe Zeichen zeigen
while (left < right) { // Bestimme die Mitte des aktuellen Suchbereichs
int mid = (left + right) / 2;
// Wenn src alphabetisch vor dem aktuellen Zeichen liegt, suche im linken Teilbereich weiter
if (src < target[mid]) {
right = mid;
}
// Wenn src alphabetisch hinter dem aktuellen Zeichen liegt, suche im rechten Teilbereich weiter
else {
left = mid + 1;
}
}
// Füge src an der Stelle left in den String ein
insert_into_string(src, target, left);
}
int main (void)
{
char test[100] = "";
insert_into_string_sorted ('c', test);
insert_into_string_sorted ('a', test);
insert_into_string_sorted ('d', test);
insert_into_string_sorted ('b', test);
printf ("%s\n", test);
return 0;
}
#include <gtk/gtk.h>
#define WIDTH 320
#define HEIGHT 240
double t = 0.0;
double dt = 0.2;
int r = 5;
double x = 10;
double y = 200;
double vx = 20;
double vy = -60;
double g = 9.81;
gboolean draw (GtkWidget *widget, cairo_t *c, gpointer data)
{
GdkRGBA blue = { 0.0, 0.5, 1.0, 1.0 };
gdk_cairo_set_source_rgba (c, &blue);
cairo_arc (c, x, y, r, 0, 2 * G_PI);
cairo_fill (c);
return FALSE;
}
gboolean timer (GtkWidget *widget)
{
t += dt;
x += vx * dt;
y += vy * dt;
vx = vx;
vy = 0.5 * g * (t * t);
if (y + r >= HEIGHT)
vy = -vy * 0.9;
if (x + r >= WIDTH)
vx = -vx * 0.9;
if (x - r <= 0)
vx = -vx * 0.9;
gtk_widget_queue_draw_area (widget, 0, 0, WIDTH, HEIGHT);
g_timeout_add (50, (GSourceFunc) timer, widget);
return FALSE;
}
int main (int argc, char **argv)
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_show (window);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
GtkWidget *drawing_area = gtk_drawing_area_new ();
gtk_widget_show (drawing_area);
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_set_size_request (drawing_area, WIDTH, HEIGHT);
gtk_main ();
return 0;
}
../common/hello-gtk.png
\ No newline at end of file
File added
This diff is collapsed.
File added
This diff is collapsed.
File added
% hp-uebung-20240118.pdf - Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 Peter Gerwinski
%
% This document is free software: you can redistribute it and/or
% modify it either under the terms of the Creative Commons
% Attribution-ShareAlike 3.0 License, or under the terms of the
% GNU General Public License as published by the Free Software
% Foundation, either version 3 of the License, or (at your option)
% any later version.
%
% This document is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this document. If not, see <http://www.gnu.org/licenses/>.
%
% You should have received a copy of the Creative Commons
% Attribution-ShareAlike 3.0 Unported License along with this
% document. If not, see <http://creativecommons.org/licenses/>.
% README: Einfach und doppelt verkettete Listen, ternärer Baum, hüpfender Ball
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{tikz}
\begin{document}
\thispagestyle{empty}
\section*{Hardwarenahe Programmierung\\
Übungsaufgaben -- 18.\ Januar 2024}
Diese Übung enthält Punkteangaben wie in einer Klausur.
Um zu "`bestehen"', müssen Sie innerhalb von 60 Minuten
unter Verwendung ausschließlich zugelassener Hilfsmittel
18 Punkte (von insgesamt \totalpoints) erreichen.
\exercise{Einfach und doppelt verkettete Listen}
Das Beispiel-Programm \gitfile{hp}{2023ws/20240118}{aufgabe-1.c}
demonstriert zwei Funktionen zur Verwaltung einfach verketteter Listen:
\lstinline{output_list()} zum Ausgeben der Liste auf den Bildschirm und
\lstinline{insert_into_list()} zum Einfügen in die Liste.
\begin{enumerate}[\quad(a)]
\item
Ergänzen Sie eine Funktion \lstinline{delete_from_list()}
zum Löschen eines Elements aus der Liste
mit Freigabe des Speicherplatzes.
\points{5}
\item
Ergänzen Sie eine Funktion \lstinline{reverse_list()}
die die Reihenfolge der Elemente in der Liste umdreht.\\
\points{3}
\end{enumerate}
Eine doppelt verkettete Liste hat in jedem Knotenpunkt (\lstinline{node})
\emph{zwei\/} Zeiger -- einen auf das nächste Element (\lstinline{next})
und einen auf das vorherige Element (z.\,B.\ \lstinline{prev} für "`previous"').
Dadurch ist es leichter als bei einer einfach verketteten Liste,
die Liste in umgekehrter Reihenfolge durchzugehen.
\begin{quote}
\begin{tikzpicture}
\color{blendedblue}
\node(first) at (0,3.5) {first};
\node(NULL1) at (-1,1.25) {NULL};
\node[shape=rectangle,draw,line width=1pt](3) at (1,2) {3};
\node[shape=rectangle,draw,line width=1pt](7) at (3,2) {7};
\node[shape=rectangle,draw,line width=1pt](137) at (5,2) {137};
\node(NULL2) at (7,2.75) {NULL};
\draw[-latex](first)--(3);
\draw[-latex](3) to[out=45,in=135] (7);
\draw[-latex](3) to[out=-135,in=0] (NULL1);
\draw[-latex](7) to[out=-135,in=-45] (3);
\draw[-latex](7) to[out=45,in=135] (137);
\draw[-latex](137) to[out=-135,in=-45] (7);
\draw[-latex](137) to[out=45,in=180] (NULL2);
\end{tikzpicture}
\end{quote}
Der Rückwärts-Zeiger (\lstinline{prev}) des ersten Elements zeigt,
genau wie der Vorwärts-Zeiger (\lstinline{next}) des letzten Elements,
auf \emph{nichts}, hat also den Wert \lstinline{NULL}.
\begin{enumerate}[\quad(a)]\setcounter{enumi}{2}
\item
Schreiben Sie das Programm um für doppelt verkettete Listen.
\points{5}
\end{enumerate}
\vspace{3cm}
\exercise{Ternärer Baum}
Der in der Vorlesung vorgestellte \newterm{binäre Baum\/}
ist nur ein Spezialfall;
im allgemeinen können Bäume auch mehr als zwei Verzweigungen
pro Knotenpunkt haben.
Dies ist nützlich bei der Konstruktion \emph{balancierter Bäume},
also solcher, die auch im \emph{Worst Case\/}
nicht zu einer linearen Liste entarten,
sondern stets eine -- möglichst flache -- Baumstruktur behalten.
Wir betrachten einen Baum mit bis zu drei Verzweigungen pro Knotenpunkt,
einen sog.\ \newterm{ternären Baum}.
Jeder Knoten enthält dann nicht nur einen,
sondern \emph{zwei\/} Werte als Inhalt:
\begin{lstlisting}
typedef struct node
{
int content_left, content_right;
struct node *left, *middle, *right;
} node;
\end{lstlisting}
Wir konstruieren nun einen Baum nach folgenden Regeln:
\vspace{-\medskipamount}
\begin{itemize}\itemsep0pt
\item
Innerhalb eines Knotens sind die Werte sortiert:
\lstinline{content_left} muß stets kleiner sein als \lstinline{content_right}.
\item
Der Zeiger \lstinline{left} zeigt auf Knoten,
deren enthaltene Werte durchweg kleiner sind als \lstinline{content_left}.
\item
Der Zeiger \lstinline{right} zeigt auf Knoten,
deren enthaltene Werte durchweg größer sind als \lstinline{content_right}.
\item
Der Zeiger \lstinline{middle} zeigt auf Knoten,
deren enthaltene Werte durchweg größer sind als \lstinline{content_left},
aber kleiner als \lstinline{content_right}.
\item
Ein Knoten muß nicht immer mit zwei Werten voll besetzt sein;
er darf auch \emph{nur einen\/} gültigen Wert enthalten.
Der Einfachheit halber lassen wir in diesem Beispiel
nur positive Zahlen als Werte zu.
Wenn ein Knoten nur einen Wert enthält,
setzen wir \lstinline{content_right = -1},
und der Zeiger \lstinline{middle} wird nicht verwendet.
\item
Wenn wir neue Werte in den Baum einfügen,
werden \emph{zuerst\/} die nicht voll besetzten Knoten aufgefüllt
und \emph{danach erst\/} neue Knoten angelegt und Zeiger gesetzt.
\item
Beim Auffüllen eines Knotens darf nötigenfalls \lstinline{content_left}
nach \lstinline{content_right} verschoben werden.
Ansonsten werden einmal angelegte Knoten nicht mehr verändert.
\end{itemize}
\vspace*{-\medskipamount}
(In der Praxis dürfen Knoten gemäß speziellen Regeln
nachträglich verändert werden,
um Entartungen gar nicht erst entstehen zu lassen --
siehe z.\,B.\ \url{https://en.wikipedia.org/wiki/2-3_tree}.)
\begin{enumerate}[\quad(a)]
\item
Zeichnen Sie ein Schaubild, das veranschaulicht,
wie die Zahlen 7, 137, 3, 5, 6, 42, 1, 2 und 12
nacheinander und in dieser Reihenfolge
in den oben beschriebenen Baum eingefügt werden
-- analog zu den Vortragsfolien (\gitfile{hp}{2023ws/20240118}{hp-20221219.pdf}),
Seite 33.
\points{3}
%
% Lösung:
%
% 7 137
% / |
% 3 5 12 42
% / \
% 1 2 6
%
% (NULL-Zeiger sind hier nicht dargestellt,
% gehören aber dazu.)
%
\item
Dasselbe, aber in der Reihenfolge
2, 7, 42, 12, 1, 137, 5, 6, 3.
\points{3}
%
% Lösung:
%
% 2 7
% / | \
% 1 5 6 12 42
% / \
% 3 137
%
% (NULL-Zeiger sind hier wieder nicht dargestellt,
% gehören aber dazu.)
%
\item
Beschreiben Sie in Worten und/oder als C-Quelltext-Fragment,
wie eine Funktion aussehen müßte, um den auf diese Weise entstandenen Baum
sortiert auszugeben.
\points{4}
\end{enumerate}
\vspace{3cm}
\exercise{Fehlerhaftes Programm: Hüpfender Ball}
Das auf der nächsten Seite abgedruckte GTK+-Programm
(Datei: \gitfile{hp}{2023ws/20240118}{aufgabe-3.c}) soll einen
hüpfenden Ball darstellen, ist jedoch fehlerhaft.
\begin{enumerate}[\quad(a)]
\item
Warum sieht man lediglich ein leeres Fenster?
Welchen Befehl muß man ergänzen, um diesen Fehler zu beheben?
\points{3}
\item
Nach der Fehlerbehebung in Aufgabenteil (a)
zeigt das Programm einen unbeweglichen Ball.
Welchen Befehl muß man ergänzen, um diesen Fehler zu beheben, und warum?
\points{2}
\item
Erklären Sie das merkwürdige Hüpfverhalten des Balls.
Wie kommt es zustande?
Was an diesem Verhalten ist korrekt, und was ist fehlerhaft? \points{5}
\item
Welche Befehle muß man in welcher Weise ändern,
um ein realistischeres Hüpf-Verhalten zu bekommen? \points{2}
\end{enumerate}
Hinweis: Das Hinzuziehen von Beispiel-Programmen aus der Vorlesung
ist ausdrücklich erlaubt -- auch in der Klausur.
Allgemeiner Hinweis:
Wenn Sie die Übungsaufgaben zu dieser Lehrveranstaltung
als PDF-Datei betrachten und darin auf die Dateinamen klicken,
können Sie die Beispiel-Programme direkt herunterladen.
Dadurch vermeiden Sie Übertragungsfehler.
\clearpage
\vbox to \textheight{\vspace*{-0.5cm}\begin{lstlisting}
#include <gtk/gtk.h>
#define WIDTH 320
#define HEIGHT 240
double t = 0.0;
double dt = 0.2;
int r = 5;
double x = 10;
double y = 200;
double vx = 20;
double vy = -60;
double g = 9.81;
gboolean draw (GtkWidget *widget, cairo_t *c, gpointer data)
{
GdkRGBA blue = { 0.0, 0.5, 1.0, 1.0 };
gdk_cairo_set_source_rgba (c, &blue);
cairo_arc (c, x, y, r, 0, 2 * G_PI);
cairo_fill (c);
return FALSE;
}
gboolean timer (GtkWidget *widget)
{
t += dt;
x += vx * dt;
y += vy * dt;
vx = vx;
vy = 0.5 * g * (t * t);
if (y + r >= HEIGHT)
vy = -vy * 0.9;
if (x + r >= WIDTH)
vx = -vx * 0.9;
if (x - r <= 0)
vx = -vx * 0.9;
gtk_widget_queue_draw_area (widget, 0, 0, WIDTH, HEIGHT);
g_timeout_add (50, (GSourceFunc) timer, widget);
return FALSE;
}
int main (int argc, char **argv)
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_show (window);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
GtkWidget *drawing_area = gtk_drawing_area_new ();
gtk_widget_show (drawing_area);
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_set_size_request (drawing_area, WIDTH, HEIGHT);
gtk_main ();
return 0;
}
\end{lstlisting}\vss}\vspace*{-1cm}
\begin{flushright}
\textit{Viel Erfolg -- auch in den Prüfungen!}
\end{flushright}
\makeatletter
\immediate\write\@mainaux{\string\gdef\string\totalpoints{\arabic{points}}}
\makeatother
\end{document}
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int content;
struct node *next;
} node;
void output_list (node *first)
{
for (node *p = first; p; p = p->next)
printf ("%d ", p->content);
printf ("\n");
}
void insert_into_list (node *what, node *where)
{
what->next = where->next;
where->next = what;
}
void delete_from_list (node *what, node **first)
{
if (what == *first)
*first = what->next;
else
{
node *p = *first;
while (p && p->next != what)
p = p->next;
if (p)
p->next = what->next;
}
free (what);
}
int main (void)
{
node *element3 = malloc (sizeof (node));
node *element7 = malloc (sizeof (node));
node *element137 = malloc (sizeof (node));
element3->content = 3;
element7->content = 7;
element137->content = 137;
node *first = element3;
element3->next = element7;
element7->next = element137;
element137->next = NULL;
output_list (first);
node *element5 = malloc (sizeof (node));
element5->content = 5;
insert_into_list (element5, element3);
output_list (first);
delete_from_list (element5, &first);
output_list (first);
delete_from_list (element3, &first);
output_list (first);
delete_from_list (element137, &first);
output_list (first);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int content;
struct node *next, *prev;
} node;
void check_list (node *first)
{
for (node *p = first; p; p = p->next)
{
if (p->next && p->next->prev != p)
fprintf (stderr, "List inconsistency!\n");
if (p->prev && p->prev->next != p)
fprintf (stderr, "List inconsistency!\n");
}
}
void output_list (node *first)
{
for (node *p = first; p; p = p->next)
printf ("%d ", p->content);
printf ("\n");
}
void insert_into_list (node *what, node *where)
{
what->next = where->next;
if (where->next)
where->next->prev = what;
what->prev = where;
where->next = what;
}
void delete_from_list (node *what, node **first)
{
if (what == *first)
{
*first = what->next;
if (*first)
(*first)->prev = NULL;
}
else
{
node *p = *first;
while (p && p->next != what)
p = p->next;
if (p)
p->next = what->next;
if (what->next)
what->next->prev = p;
}
free (what);
}
int main (void)
{
node *element3 = malloc (sizeof (node));
node *element7 = malloc (sizeof (node));
node *element137 = malloc (sizeof (node));
element3->content = 3;
element7->content = 7;
element137->content = 137;
node *first = element3;
element3->prev = NULL;
element3->next = element7;
element7->prev = element3;
element7->next = element137;
element137->prev = element7;
element137->next = NULL;
output_list (first);
check_list (first);
node *element5 = malloc (sizeof (node));
element5->content = 5;
insert_into_list (element5, element3);
output_list (first);
check_list (first);
delete_from_list (element5, &first);
output_list (first);
check_list (first);
delete_from_list (element3, &first);
output_list (first);
check_list (first);
delete_from_list (element137, &first);
output_list (first);
check_list (first);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int content_left, content_right;
struct node *left, *middle, *right;
} node;
void insert_into_tree (node **root, int value)
{
if (*root)
{
if ((*root)->content_right >= 0)
if (value < (*root)->content_left)
insert_into_tree (&(*root)->left, value);
else if (value < (*root)->content_right)
insert_into_tree (&(*root)->middle, value);
else
insert_into_tree (&(*root)->right, value);
else
if (value < (*root)->content_left)
{
(*root)->content_right = (*root)->content_left;
(*root)->content_left = value;
}
else
(*root)->content_right = value;
}
else
{
*root = malloc (sizeof (node));
(*root)->left = NULL;
(*root)->content_left = value;
(*root)->middle = NULL;
(*root)->content_right = -1;
(*root)->right = NULL;
}
}
void output_tree (node *root)
{
if (root)
{
output_tree (root->left);
printf ("%d\n", root->content_left);
output_tree (root->middle);
if (root->content_right >= 0)
printf ("%d\n", root->content_right);
output_tree (root->right);
}
}
int main (void)
{
node *root = NULL;
insert_into_tree (&root, 7);
insert_into_tree (&root, 137);
insert_into_tree (&root, 3);
insert_into_tree (&root, 5);
insert_into_tree (&root, 6);
insert_into_tree (&root, 42);
insert_into_tree (&root, 1);
insert_into_tree (&root, 2);
insert_into_tree (&root, 12);
output_tree (root);
return 0;
}
#include <stdio.h>
int sum; // globale Variable für die Summe
void add_to_sum (int x)
{
if (x > 0)
{
sum += x;
}
}
void foreach (int *a, void (*fun) (int x))
{
for (int *p = a; *p >= 0; p++)
{
fun (*p);
}
}
int main (void)
{
int numbers[] = { 12, 17, 32, 1, 3, 16, 19, 18, -1 };
foreach (numbers, add_to_sum);
printf ("Summe der positiven Zahlen: %d\n", sum);
return 0;
}
../common/logo-hochschule-bochum-cvh-text-v2.pdf
\ No newline at end of file
../common/logo-hochschule-bochum.pdf
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment