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

Musterlösung zu den Übungsaufgaben vom 16.1.2017

parent 0936d4f0
Branches
No related tags found
No related merge requests found
File added
% hp-musterloesung-20170109.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017 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/>.
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{ifthen}
\usepackage{gensymb}
\usepackage{sfmath}
\usepackage{enumerate}
\usepackage{tikz}
\newcounter{exercise}
\newcommand{\exercise}[1]{\addtocounter{exercise}{1}\subsection*{Aufgabe \arabic{exercise}: #1}}
\newcommand{\solution}{\goodbreak\subsubsection*{Lösung}}
\newcounter{points}
\newcommand{\points}[1]{\ifthenelse{#1=1}{(1 Punkt)}{(#1 Punkte)}\addtocounter{points}{#1}}
\newcommand{\ItwoC}{I\raisebox{0.5ex}{\footnotesize 2}C}
\newcommand{\ITWOC}{I\raisebox{0.5ex}{\normalsize 2}C}
\newcommand{\gitfile}[2]{\href{https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/#1/#2}{\file{#2}}}
\begin{document}
% \thispagestyle{empty}
\section*{Hardwarenahe Programmierung / Angewandte Informatik\\
Musterlösung zu den Übungsaufgaben -- 9.\ Januar 2017}
\exercise{Stack-Operationen}
Wir betrachten das folgende Programm (\gitfile{20170116}{aufgabe-1.c}):
\begin{minipage}[t]{0.5\textwidth}
\begin{lstlisting}[gobble=6]
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
int pop (void)
{
return stack[--stack_pointer];
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
\end{lstlisting}
\end{minipage}\hfill
\begin{minipage}[t]{0.5\textwidth}
\begin{lstlisting}[gobble=6]
void insert (int x, int pos)
{
for (int i = pos; i < stack_pointer; i++)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = 0;
while (i < stack_pointer && x < stack[i])
i++;
insert (x, i);
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
return 0;
}
\end{lstlisting}
\end{minipage}
\begin{enumerate}[\quad(a)]
\item
Ändern Sie das Programm so,
daß die Funktion \lstinline{insert()} ihren Parameter \lstinline{x}
an der Stelle \lstinline{pos} in den Stack einfügt,
und den sonstigen Inhalt des Stacks verschiebt, aber nicht zerstört.
\points{3}
\item
Ändern Sie das Programm so,
daß die Funktion \lstinline{insert_sorted()} ihren Parameter \lstinline{x}
an derjenigen Stelle einfügt, an die er von der Sortierung her gehört.
(Der Stack wird hierbei vor dem Funktionsaufruf als sortiert vorausgesetzt.)
\points{2}
\item
Schreiben Sie eine zusätzliche Funktion \lstinline{int search (int x)},
die die Position (Index) des Elements \lstinline{x}
innerhalb des Stack zurückgibt
-- oder \lstinline{-1}, wenn \lstinline{x} nicht im Stack enthalten ist.
Der Rechenaufwand darf höchstens $\mathcal{O}(n)$ betragen.
\points{3}
\item
Wie (c), aber der Rechenaufwand darf höchstens $\mathcal{O}(\log n)$ betragen.
\points{4}
\end{enumerate}
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{Ändern Sie das Programm so,
daß die Funktion \lstinline{insert()} ihren Parameter \lstinline{x}
an der Stelle \lstinline{pos} in den Stack einfügt,
und den sonstigen Inhalt des Stacks verschiebt, aber nicht zerstört.}
Die \lstinline{for}-Schleife in der Funktion \lstinline{insert()}
durchläuft das Array von unten nach oben.
Um den Inhalt des Arrays von unten nach oben zu verschieben,
muß man die Schleife jedoch von oben nach unten durchlaufen.
\goodbreak
Um die Funktion zu reparieren, ersetze man also
\begin{lstlisting}[gobble=8]
for (int i = pos; i < stack_pointer; i++)
\end{lstlisting}
durch:
\begin{lstlisting}[gobble=8]
for (int i = stack_pointer - 1; i >= pos; i--)
\end{lstlisting}
(Siehe auch: \gitfile{20170116}{loesung-1.c})
\item
\textbf{Ändern Sie das Programm so,
daß die Funktion \lstinline{insert_sorted()} ihren Parameter \lstinline{x}
an derjenigen Stelle einfügt, an die er von der Sortierung her gehört.
(Der Stack wird hierbei vor dem Funktionsaufruf als sortiert vorausgesetzt.)}
Der Vergleich \lstinline{x < stack[i]}
als Bestandteil der \lstinline{while}-Bedingung
paßt nicht zur Durchlaufrichtung der Schleife (von unten nach oben).
Um die Funktion zu reparieren, kann man daher entweder
das Kleinerzeichen durch ein Größerzeichen ersetzen
(\lstinline{x > stack[i]} -- siehe \gitfile{20170116}{loesung-1b-1.c})
oder die Schleife von oben nach unten durchlaufen
(siehe \gitfile{20170116}{loesung-1b-2.c}).
Eine weitere Möglichkeit besteht darin,
das Suchen nach der Einfügeposition
mit dem Verschieben des Arrays zu kombinieren
(siehe \gitfile{20170116}{loesung-1.c}).
Hierdurch spart man sich eine Schleife; das Programm wird schneller.
(Es bleibt allerdings bei $\mathcal{O}(n)$.)
\item
\textbf{Schreiben Sie eine zusätzliche Funktion \lstinline{int search (int x)},
die die Position (Index) des Elements \lstinline{x}
innerhalb des Stack zurückgibt
-- oder \lstinline{-1}, wenn \lstinline{x} nicht im Stack enthalten ist.
Der Rechenaufwand darf höchstens $\mathcal{O}(n)$ betragen.}
Man geht in einer Schleife den Stack (= den genutzten Teil des Arrays) durch.
Bei Gleichheit gibt man direkt mit \lstinline{return} den Index zurück.
Nach dem Schleifendurchlauf steht fest,
daß \lstinline{x} nicht im Stack vorhanden ist;
man kann dann direkt \lstinline{-1} zurückgeben.
Da es sich um eine einzelne Schleife handelt,
ist die Ordnung $\mathcal{O}(n)$.
\item
\textbf{Wie (c), aber der Rechenaufwand darf höchstens $\mathcal{O}(\log n)$ betragen.}
Um $\mathcal{O}(\log n)$ zu erreichen,
halbiert man fortwährend das Intervall von (einschließlich) \lstinline{0}
bis (ausschließlich) \lstinline{stack_pointer}
(siehe \gitfile{20170116}{loesung-1d.c}) --
wie in der Funktion \lstinline{push_sorted()}
im Beispiel-Programm \gitfile{20170116}{stack-11.c}.
Ein wichtiger Unterschied besteht darin,
daß man nach dem Durchlauf der Schleife noch auf die Gleichheit
\lstinline{x == stack[left]} (insbesondere nicht: \lstinline{stack[right]})
prüfen und ggf.\ \lstinline{left} bzw.\ \lstinline{-1} zurückgeben muß.
\end{enumerate}
\goodbreak
\exercise{Iterativer Floodfill}
In Übungsaufgabe 3 vom 14.\,11.\,2016
(siehe \gitfile{20161114}{hp-uebung-20161114.pdf})
haben wir einen rekursiven Floodfill-Algorithmus implementiert.
\begin{enumerate}[\quad(a)]
\item
Ergänzen Sie die Funktion \lstinline{fill()} so,
daß Sie verfolgen können ("`Animation"'),
in welcher Reihenfolge die Punkte auf dem Bildschirm "`ausgemalt"' werden.
\points{4}
Hinweis: Eine Möglichkeit,
den Bildschirm zu löschen und eine kurze Zeit lang zu warten,
können Sie den Beispielaufgaben zum Sortieren
(z.\,B.\ \gitfile{20161114}{sort-2.c}) entnehmen.
(Um \lstinline{usleep()} nutzen zu können,
ist beim Compilieren mit \lstinline[style=cmd]{gcc}
die Option \lstinline[style=cmd]{-std=gnu99} erforderlich.)
\item
Unter Verwendung eines Stack ist es möglich,
den Floodfill-Algorithmus iterativ (also mit Schleife)
statt rekursiv zu implementieren.
Informieren Sie sich per Web-Suche über die Details
und implementieren Sie einen iterativen Floodfill-Algorithmus mit Stack
für die Text-Grafik-Bibliothek.
Die Punkte sollen dabei in derselben Reihenfolge "`ausgemalt"' werden
wie bisher in der rekursiven Floodfill-Implementation.
\points{4}
\item
Ersetzen Sie nun den Stack durch einen FIFO.
Der Floodfill-Algorithmus sollte weiterhin funktionieren,
nur daß die Punkte in einer anderen Reihenfolge "`ausgemalt"' werden.
Beschreiben Sie diesen Unterschied.
\points{3}
(Ein iterativer Floodfill mit FIFO ist nützlich für die Wegfindung
und verwandte Aufgabenstellungen.)
\end{enumerate}
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{Ergänzen Sie die Funktion \lstinline{fill()} so,
daß Sie verfolgen können ("`Animation"'),
in welcher Reihenfolge die Punkte auf dem Bildschirm "`ausgemalt"' werden.}
Siehe die Funktion \lstinline{fill_animated()}
in \gitfile{20170116}{textgraph.c}
(mit \lstinline{extern}-Deklaration in \gitfile{20170116}{textgraph.h}
und Test-Aufruf in \gitfile{20170116}{test-textgraph.c}).
Um den Bildschirm zu löschen, wurde eine zusätzliche Funktion
\lstinline{clear_display()} eingeführt; für das Warten wird
\lstinline{usleep()} verwendet.
\item
\textbf{Unter Verwendung eines Stack ist es möglich,
den Floodfill-Algorithmus iterativ (also mit Schleife)
statt rekursiv zu implementieren.}
\textbf{Informieren Sie sich per Web-Suche über die Details
und implementieren Sie einen iterativen Floodfill-Algorithmus mit Stack
für die Text-Grafik-Bibliothek.
Die Punkte sollen dabei in derselben Reihenfolge "`ausgemalt"' werden
wie bisher in der rekursiven Floodfill-Implementation.}
Eine Web-Suche führt z.\,B.\ auf den Abschnitt "`Iterative Flutfüllung"'
des Wikipedia-Artikels zu "`Floodfill"',
\url{https://de.wikipedia.org/wiki/Floodfill#Iterative_Flutf.C3.BCllung}.
Für die Umsetzung des dort beschriebenen Algorithmus' benötigt man
einen Stack, der Koordinatenpaare speichern kann.
Hierzu dienen die Deklarationen \lstinline{struct pair},
\lstinline{pair stack[STACK_SIZE]} und \lstinline{int stack_pointer}
zusammen mit den Funktionen \lstinline{stack_push()}
und \lstinline{stack_pop()}
in \gitfile{20170116}{textgraph.c} und \gitfile{20170116}{textgraph.h}.
Man beachte, daß die Funktion \lstinline{stack_pop()} Zeiger verwendet,
um die aus dem Stack geholten Werte \lstinline{x} und \lstinline{y}
zurückzugeben. Beim Aufruf müssen entsprechend Adressen
(\lstinline{&x}, \lstinline{&y}) übergeben werden.
Die Funktion \lstinline{fill_stack()} realisiert den iterativen Floodfill.
Damit die Reihenfolge der ausgemalten Punkte
dieselbe ist wie beim rekursiven Floodfill,
müssen die Punkte im Vergleich zu den rekursiven Aufrufen in \lstinline{fill()}
\emph{in umgekehrter Reihenfolge\/} auf den Stack gelegt werden.
Dies liegt an der \emph{First-In-First-Out-\/}Natur des Stack.
\item
\textbf{Ersetzen Sie nun den Stack durch einen FIFO.
Der Floodfill-Algorithmus sollte weiterhin funktionieren,
nur daß die Punkte in einer anderen Reihenfolge "`ausgemalt"' werden.
Beschreiben Sie diesen Unterschied.}
Die Realisierung des FIFO erfolgt analog zu der des Stack,
nur daß es nicht einen einzelnen \lstinline{stack_pointer} gibt,
sondern zwei Indizes \lstinline{fifo_write} und \lstinline{fifo_read}.
Für das ringförmige Inkrementieren von \lstinline{fifo_write}
und \lstinline{fifo_read} verwenden die Funktionen \lstinline{fifo_push()}
und \lstinline{fifo_pop()} die Modulo-Operation (\lstinline{% FIFO_SIZE}).
Die Funktion \lstinline{fill_fifo()} realisiert
den iterativen Floodfill mit FIFO.
Hierbei wurde nur überall "`Stack"' durch "`FIFO"' ersetzt
und die \lstinline{while}-Bedingung angepaßt:
Die Bedingung, ob sich Daten im FIFO befinden,
lautet nicht \lstinline{stack_pointer > 0} wie beim Stack,
sondern \lstinline{fifo_write != fifo_read}.
Die Reihenfolge, in der die Punkte "`ausgemalt"' werden,
geht nun von nahen zu fernen Punkten.
Damit eignet sich dieser Algorithmus dazu,
unter den erreichbaren ("`auszumalenden"') Punkten
den nächstgelegenen zu finden,
um z.\,B.\ einen autonomen Roboter dorthin zu lenken.
(Dieses Verfahren wurde im Wintersemester 2011/12 eingesetzt,
um ein RP6-Roboterfahrzeug autonom durch ein Labyrinth steuern zu lassen.)
Im Gegensatz dazu geht beim iterativen Floodfill mit Stack
-- oder beim rekursiven Floodfill, der ja implizit ebenfalls
einen Stack verwendet, nämlich den CPU-Stack --
die Reihenfolge erst in eine Richtung (z.\,B.\ nach oben)
und dann erst in andere Richtungen
(z.\,B.\ noch ausstehende Punkte im unteren Bereich).
\end{enumerate}
\exercise{Doppelt verkettete Liste}
In der Vorlesung wurde ein Beispiel-Programm
% \href{https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20170116/hp-uebung-20170116.pdf}{(Link wird nachgereicht)}
(\gitfile{20170116}{lists-5.c})
zur Verwaltung einfach verketteter Listen erstellt
(an die Liste anhängen, in die Liste einfügen, Liste ausgeben usw.).
\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{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}{1}
\item
Schreiben Sie das Programm um für doppelt verkettete Listen.
\points{5}
\end{enumerate}
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{Ergänzen Sie eine Funktion \lstinline{delete_from_list()}
zum Löschen eines Elements aus der Liste
mit Freigabe des Speicherplatzes.}
Siehe: \gitfile{20170116}{loesung-3a.c}
Um ein Element aus einer verketteten Liste zu löschen,
müssen zuerst die Zeiger umgestellt werden,
um das Element von der Liste auszuschließen.
Erst danach darf der Speicherplatz für das Element freigegeben werden.
Da das Beispielprogramm (\gitfile{20170116}{lists-5.c})
nicht mit dynamischem Speicher arbeitet,
stellen wir dieses zunächst auf dynamischen Speicher um, z.\,B.:
\begin{lstlisting}[gobble=8]
node *element5 = malloc (sizeof (node));
\end{lstlisting}
Danach bezeichnet \lstinline{element5}
die Adresse der \lstinline{struct}-Variablen;
es wird also \lstinline{element5} an die Funktionen übergeben
und nicht \lstinline{&element5} (die Adresse des Zeigers).
Um nun ein Element aus der Liste zu entfernen,
benötigt man \emph{das vorherige Element},
dessen \lstinline{next}-Zeiger man dann auf
das übernächste Element \lstinline{next->next} weitersetzt.
Bei jedem Zeiger muß man vor dem Zugriff prüfen,
daß dieser nicht auf \lstinline{NULL} zeigt.
(Die Musterlösung ist in dieser Hinsicht nicht konsequent.
Für den Produktiveinsatz müßte z.\,B.\ \lstinline{delete_from_list()}
auch den übergebenen Zeiger \lstinline{what} auf \lstinline{NULL} prüfen.)
Ein Spezialfall tritt ein, wenn das erste Element einer Liste
entfernt werden soll. In diesem Fall tritt \lstinline{first}
an die Stelle des \lstinline{next}-Zeigers
des (nicht vorhandenen) vorherigen Elements.
Da \lstinline{delete_from_list()} \emph{schreibend\/} auf \lstinline{first}
zugreift, muß \lstinline{first} \emph{als Zeiger\/} übergeben werden
(\lstinline{node **first}).
Um alle Spezialfälle zu testen (am Anfang, am Ende und in der Mitte der Liste),
wurden die Testfälle im Hauptprogramm erweitert.
\item
\textbf{Schreiben Sie das Programm um für doppelt verkettete Listen.}
Siehe: \gitfile{20170116}{loesung-3b.c}
Bei allen Einfüge- und Löschaktionen müssen \emph{jeweils zwei\/}
\lstinline{next}- und \lstinline{prev}-Zeiger neu gesetzt werden.
Zum Debuggen empfiehlt es sich sehr,
eine Funktion zu schreiben, die die Liste auf Konsistenz prüft
(hier: \lstinline{check_list()}).
Das Testprogramm macht von der Eigenschaft der doppelt verketteten Liste,
daß man sie auch rückwärts effizient durchgehen kann, keinen Gebrauch.
Um diese Eigenschaft als Vorteil nutzen zu können, empfiehlt es sich,
zusätzlich zu \lstinline{first}
auch einen Zeiger auf das letzte Element (z.\,B.\ \lstinline{last})
einzuführen. Dieser muß dann natürlich bei allen Operationen
(Einfügen, Löschen, \dots) auf dem aktuellen Stand gehalten werden.
\end{enumerate}
\end{document}
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
int pop (void)
{
return stack[--stack_pointer];
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
void insert (int x, int pos)
{
for (int i = stack_pointer - 1; i >= pos; i--)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = 0;
while (i < stack_pointer && x > stack[i])
i++;
insert (x, i);
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
return 0;
}
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
int pop (void)
{
return stack[--stack_pointer];
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
void insert (int x, int pos)
{
for (int i = stack_pointer - 1; i >= pos; i--)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = stack_pointer - 1;
while (i >= 0 && x < stack[i])
i--;
insert (x, i + 1);
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
return 0;
}
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
int pop (void)
{
return stack[--stack_pointer];
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
void insert (int x, int pos)
{
for (int i = stack_pointer - 1; i >= pos; i--)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = stack_pointer - 1;
while (i >= 0 && x < stack[i])
{
stack[i + 1] = stack[i];
i--;
}
stack[i + 1] = x;
stack_pointer++;
}
int search (int x)
{
for (int i = 0; i < stack_pointer; i++)
if (stack[i] == x)
return i;
return -1;
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
printf ("%d\n", search (42));
printf ("%d\n", search (1117));
return 0;
}
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
int pop (void)
{
return stack[--stack_pointer];
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
void insert (int x, int pos)
{
for (int i = stack_pointer - 1; i >= pos; i--)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = stack_pointer - 1;
while (i >= 0 && x < stack[i])
{
stack[i + 1] = stack[i];
i--;
}
stack[i + 1] = x;
stack_pointer++;
}
int search (int x)
{
int left = 0;
int right = stack_pointer;
while (left < right - 1)
{
int middle = (left + right) / 2;
if (x < stack[middle])
right = middle;
else
left = middle;
}
if (x == stack[left])
return left;
else
return -1;
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
printf ("%d\n", search (2));
printf ("%d\n", search (4));
printf ("%d\n", search (42));
printf ("%d\n", search (67));
printf ("%d\n", search (137));
printf ("%d\n", search (1117));
return 0;
}
#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 <unistd.h>
#include "textgraph.h"
void draw_smiley (void)
{
clear (' ');
put_point (-5, 10, 'X');
for (int i = 16; i < 24; i++)
put_point (i, 5, '*');
put_point (15, 6, '*');
put_point (14, 7, '*');
put_point (13, 8, '*');
put_point (13, 9, '*');
put_point (14, 10, '*');
put_point (15, 11, '*');
for (int i = 16; i < 24; i++)
put_point (i, 12, '*');
put_point (24, 11, '*');
put_point (25, 10, '*');
put_point (26, 9, '*');
put_point (26, 8, '*');
put_point (25, 7, '*');
put_point (24, 6, '*');
put_point (18, 8, 'O');
put_point (21, 8, 'O');
put_point (17, 10, '`');
for (int i = 18; i < 22; i++)
put_point (i, 10, '-');
put_point (22, 10, '\'');
put_point (13, 42, 'Y');
printf ("get_point (%d, %d): '%c'\n", 13, 9, get_point (13, 9));
printf ("get_point (%d, %d): '%c'\n", 14, 9, get_point (14, 9));
printf ("get_point (%d, %d): '%c'\n", 94, 9, get_point (94, 9));
}
int main (void)
{
draw_smiley ();
fill_animated (21, 7, '.', ' ');
sleep (5);
draw_smiley ();
fill_stack (21, 7, '.', ' ');
sleep (5);
draw_smiley ();
fill_fifo (21, 7, '.', ' ');
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include "textgraph.h"
char buffer[HEIGHT][WIDTH];
void clear (char c)
{
for (int y = 0; y < HEIGHT; y++)
for (int x = 0; x < WIDTH; x++)
buffer[y][x] = c;
}
static int check_coordinates (int x, int y, char *function)
{
if (x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT)
return 1;
else
{
fprintf (stderr, "coordinates (%d,%d) out of range in %s\n", x, y, function);
return 0;
}
}
void put_point (int x, int y, char c)
{
if (check_coordinates (x, y, "put_point"))
buffer[y][x] = c;
}
char get_point (int x, int y)
{
if (check_coordinates (x, y, "get_point"))
return buffer[y][x];
else
return 0;
}
void fill (int x, int y, char c, char o)
{
if (get_point (x, y) == o)
{
put_point (x, y, c);
fill (x - 1, y, c, o);
fill (x + 1, y, c, o);
fill (x, y - 1, c, o);
fill (x, y + 1, c, o);
}
}
void display (void)
{
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
printf ("%c", buffer[y][x]);
printf ("\n");
}
}
void clear_display (void)
{
printf ("\e[H\e[J");
}
void fill_animated (int x, int y, char c, char o)
{
if (get_point (x, y) == o)
{
put_point (x, y, c);
clear_display ();
display ();
usleep (200000);
fill_animated (x - 1, y, c, o);
fill_animated (x + 1, y, c, o);
fill_animated (x, y - 1, c, o);
fill_animated (x, y + 1, c, o);
}
}
pair stack[STACK_SIZE];
int stack_pointer = 0;
void stack_push (int x, int y)
{
stack[stack_pointer].x = x;
stack[stack_pointer].y = y;
stack_pointer++;
}
void stack_pop (int *x, int *y)
{
stack_pointer--;
*x = stack[stack_pointer].x;
*y = stack[stack_pointer].y;
}
void fill_stack (int x, int y, char c, char o)
{
stack_push (x, y);
while (stack_pointer > 0)
{
stack_pop (&x, &y);
if (get_point (x, y) == o)
{
put_point (x, y, c);
clear_display ();
display ();
usleep (200000);
stack_push (x, y + 1);
stack_push (x, y - 1);
stack_push (x + 1, y);
stack_push (x - 1, y);
}
}
}
pair fifo[FIFO_SIZE];
int fifo_read = 0;
int fifo_write = 0;
void fifo_push (int x, int y)
{
fifo[fifo_write].x = x;
fifo[fifo_write].y = y;
fifo_write = (fifo_write + 1) % FIFO_SIZE;
}
void fifo_pop (int *x, int *y)
{
*x = fifo[fifo_read].x;
*y = fifo[fifo_read].y;
fifo_read = (fifo_read + 1) % FIFO_SIZE;
}
void fill_fifo (int x, int y, char c, char o)
{
fifo_push (x, y);
while (fifo_write != fifo_read)
{
fifo_pop (&x, &y);
if (get_point (x, y) == o)
{
put_point (x, y, c);
clear_display ();
display ();
usleep (200000);
fifo_push (x, y + 1);
fifo_push (x, y - 1);
fifo_push (x + 1, y);
fifo_push (x - 1, y);
}
}
}
#ifndef TEXTGRAPH_H
#define TEXTGRAPH_H
#define WIDTH 40
#define HEIGHT 20
#define STACK_SIZE 100
#define FIFO_SIZE 100
typedef struct
{
int x, y;
} pair;
extern void clear (char c);
extern void put_point (int x, int y, char c);
extern char get_point (int x, int y);
extern void fill (int x, int y, char c, char o);
extern void display (void);
extern void clear_display (void);
extern void fill_animated (int x, int y, char c, char o);
extern void stack_push (int x, int y);
extern void stack_pop (int *x, int *y);
extern void fill_stack (int x, int y, char c, char o);
extern void fifo_push (int x, int y);
extern void fifo_pop (int *x, int *y);
extern void fill_fifo (int x, int y, char c, char o);
#endif
......@@ -78,6 +78,7 @@ Musterlösungen zu den Übungsaufgaben:
* [12.12.2016: Daten im Speicher, Zeigerarithmetik, XBM-Grafik](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20161212/hp-musterloesung-20161212.pdf)
* [19.12.2016: Bürgerentscheid, Lokale Variable im Speicher, Blinkende LEDs, objektorientierte Tier-Datenbank](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20161219/hp-musterloesung-20161219.pdf)
* [09.01.2017: Objektorientierte Programmierung mit dem C-Datentyp _union, objektorientierte Tier-Datenbank](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20170109/hp-musterloesung-20170109.pdf)
* [16.01.2017: Stack-Operationen, Iterativer Floodfill, Doppelt verkettete Listen](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20170116/hp-musterloesung-20170116.pdf)
Praktikumsunterlagen:
---------------------
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment