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

Beispiele und Notizen 11.2.2021

parent b2b8c540
No related branches found
No related tags found
No related merge requests found
Showing
with 2587 additions and 0 deletions
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
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 = 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;
}
#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;
}
Zahlen von 0 bis 14 in einem Baum
best case: O(log n) - "ausbalancierter Baum"
7
3 11
1 5 9 13
0 2 4 6 8 10 12 14
worst case: O(n) - "entarteter Baum"
0
1
2
3
4
...
14
#include <stdio.h>
#define FIFO_SIZE 10
int fifo[FIFO_SIZE];
int fifo_pointer = 0;
void push (int x)
{
fifo[fifo_pointer++] = x;
}
int pop (void)
{
return fifo[0];
fifo[0] = fifo[1];
fifo[1] = fifo[2];
fifo[2] = fifo[3];
/* ... */
}
int main (void)
{
push (3);
push (7);
push (137);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
printf ("%d\n", pop ());
return 0;
}
#include <stdio.h>
#define FIFO_SIZE 10
int fifo[FIFO_SIZE];
int fifo_pointer = 0;
void push (int x)
{
fifo[fifo_pointer++] = x;
}
int pop (void)
{
fifo[0] = fifo[1];
fifo[1] = fifo[2];
fifo[2] = fifo[3];
/* ... */
return fifo[0];
}
int main (void)
{
push (3);
push (7);
push (137);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
printf ("%d\n", pop ());
return 0;
}
#include <stdio.h>
#define FIFO_SIZE 10
int fifo[FIFO_SIZE];
int fifo_pointer = 0;
void push (int x)
{
fifo[fifo_pointer++] = x;
}
int pop (void)
{
int result = fifo[0];
fifo[0] = fifo[1];
fifo[1] = fifo[2];
fifo[2] = fifo[3];
/* ... */
return result;
}
int main (void)
{
push (3);
push (7);
push (137);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
printf ("%d\n", pop ());
return 0;
}
#include <stdio.h>
#define FIFO_SIZE 10
int fifo[FIFO_SIZE];
int fifo_pointer = 0;
void push (int x)
{
fifo[fifo_pointer++] = x;
}
int pop (void)
{
int result = fifo[0];
for (int i = 1; i < FIFO_SIZE; i++)
fifo[i - 1] = fifo[i];
return result;
}
int main (void)
{
push (3);
push (7);
push (137);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
printf ("%d\n", pop ());
return 0;
}
#include <stdio.h>
#define FIFO_SIZE 10
int fifo[FIFO_SIZE];
int fifo_pointer = 0;
void push (int x)
{
fifo[fifo_pointer++] = x;
}
int pop (void)
{
int result = fifo[0];
for (int i = 1; i < FIFO_SIZE; i++)
fifo[i - 1] = fifo[i];
return result;
}
int main (void)
{
push (3);
push (7);
push (137);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
printf ("%d\n", pop ());
push (42);
printf ("%d\n", pop ());
return 0;
}
#include <stdio.h>
#define FIFO_SIZE 10
int fifo[FIFO_SIZE];
int fifo_pointer = 0;
void push (int x)
{
fifo[fifo_pointer++] = x;
}
int pop (void)
{
int result = fifo[0];
for (int i = 1; i < FIFO_SIZE; i++)
fifo[i - 1] = fifo[i];
fifo_pointer--;
return result;
}
int main (void)
{
push (3);
push (7);
push (137);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
printf ("%d\n", pop ());
push (42);
printf ("%d\n", pop ());
return 0;
}
#include <stdio.h>
#define FIFO_SIZE 10
int fifo[FIFO_SIZE];
int fifo_pointer = 0;
void push (int x)
{
fifo[fifo_pointer++] = x;
}
int pop (void)
{
int result = fifo[0];
for (int i = 1; i < fifo_pointer; i++)
fifo[i - 1] = fifo[i];
fifo_pointer--;
return result;
}
int main (void)
{
push (3);
push (7);
push (137);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
printf ("%d\n", pop ());
push (42);
printf ("%d\n", pop ());
return 0;
}
#include <stdio.h>
#define FIFO_SIZE 10
int fifo[FIFO_SIZE];
int fifo_write_pointer = 0;
int fifo_read_pointer = 0;
void push (int x)
{
fifo[fifo_write_pointer++] = x;
if (fifo_write_pointer >= FIFO_SIZE)
fifo_write_pointer = 0;
}
int pop (void)
{
int result = fifo[fifo_read_pointer++];
if (fifo_read_pointer >= FIFO_SIZE)
fifo_read_pointer = 0;
return result;
}
int main (void)
{
push (3);
push (7);
push (137);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
printf ("%d\n", pop ());
push (42);
printf ("%d\n", pop ());
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define FIFO_SIZE 10
int fifo[FIFO_SIZE];
int fifo_write_pointer = 0;
int fifo_read_pointer = 0;
void push (int x)
{
fifo[fifo_write_pointer++] = x;
if (fifo_write_pointer >= FIFO_SIZE)
fifo_write_pointer = 0;
if (fifo_write_pointer == fifo_read_pointer)
{
fprintf (stderr, "fifo overflow\n");
exit (1);
}
}
int pop (void)
{
if (fifo_read_pointer == fifo_write_pointer)
{
fprintf (stderr, "fifo underflow\n");
exit (1);
}
else
{
int result = fifo[fifo_read_pointer++];
if (fifo_read_pointer >= FIFO_SIZE)
fifo_read_pointer = 0;
return result;
}
}
int main (void)
{
push (3);
push (7);
push (137);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
printf ("%d\n", pop ());
push (42);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define FIFO_SIZE 10
int fifo[FIFO_SIZE];
int fifo_write_pointer = 0;
int fifo_read_pointer = 0;
void push (int x)
{
int old_fifo_write_pointer = fifo_write_pointer;
fifo_write_pointer++;
if (fifo_write_pointer >= FIFO_SIZE)
fifo_write_pointer = 0;
if (fifo_write_pointer == fifo_read_pointer)
{
fprintf (stderr, "fifo overflow\n");
exit (1);
}
else
fifo[old_fifo_write_pointer] = x;
}
int pop (void)
{
if (fifo_read_pointer == fifo_write_pointer)
{
fprintf (stderr, "fifo underflow\n");
exit (1);
}
else
{
int result = fifo[fifo_read_pointer++];
if (fifo_read_pointer >= FIFO_SIZE)
fifo_read_pointer = 0;
return result;
}
}
int main (void)
{
push (3);
push (7);
push (137);
for (int i = 0; i < 42; i++)
push (i);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
printf ("%d\n", pop ());
push (42);
printf ("%d\n", pop ());
printf ("%d\n", pop ());
return 0;
}
../common/hello-gtk.png
\ No newline at end of file
File added
% hp-20210211.pdf - Lecture Slides on Low-Level Programming
% Copyright (C) 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021 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: Objektorientierte Programmierung: virtuelle Methoden
\documentclass[10pt,t]{beamer}
\usepackage{pgslides}
\usepackage{rotating}
\usepackage{tikz}
\title{Hardwarenahe Programmierung}
\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski}
\date{11.\ Februar 2021}
\begin{document}
\maketitleframe
\nosectionnonumber{\inserttitle}
\begin{frame}
\shownosectionnonumber
\begin{itemize}
\item[\textbf{1}] \textbf{Einführung}
\hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}}
\item[\textbf{2}] \textbf{Einführung in C}
\item[\textbf{3}] \textbf{Bibliotheken}
\item[\textbf{4}] \textbf{Algorithmen}
\item[\textbf{5}] \textbf{Hardwarenahe Programmierung}
\item[\textbf{6}] \textbf{Objektorientierte Programmierung}
\begin{itemize}
\item[6.0] Dynamische Speicherverwaltung
\item[6.1] Konzepte und Ziele
\item[6.2] Beispiel: Zahlen und Buchstaben
\item[6.3] Unions
\color{medgreen}
\item[6.4] Virtuelle Methoden
\item[6.5] Beispiel: Graphische Benutzeroberfläche (GUI)
\item[6.6] Ausblick: C++
\end{itemize}
\item[\textbf{7}] \textbf{Datenstrukturen}
\vspace*{-1cm}
\end{itemize}
\end{frame}
\setcounter{section}{5}
\section{Objektorientierte Programmierung}
\addtocounter{subsection}{-1}
\subsection{Dynamische Speicherverwaltung}
\begin{frame}[fragile]
\showsection
\showsubsection
\begin{itemize}
\item
Array: feste Anzahl von Elementen desselben Typs (z.\,B.\ 3 ganze Zahlen)
\item
Dynamisches Array: variable Anzahl von Elementen desselben Typs
\end{itemize}
\bigskip
\begin{lstlisting}
char *name[] = { "Anna", "Berthold", "Caesar" };
...
name[3] = "Dieter";
\end{lstlisting}
\begin{picture}(0,0)
\color{red}
\put(0,0){\line(3,1){3.5}}
\put(0,1){\line(3,-1){3.5}}
\end{picture}
\end{frame}
\begin{frame}[fragile]
\showsection
\showsubsection
\bigskip
\begin{lstlisting}
#include <stdlib.h>
...
char **name = malloc (3 * sizeof (char *));
/* Speicherplatz für 3 Zeiger anfordern */
...
free (name);
/* Speicherplatz freigeben */
\end{lstlisting}
\end{frame}
\subsection{Konzepte und Ziele}
\begin{frame}
\showsection
\showsubsection
\begin{itemize}
\item
% Array: feste Anzahl von Elementen desselben Typs (z.\,B.\ 3 ganze Zahlen)
Array: Elemente desselben Typs (z.\,B.\ 3 ganze Zahlen)
% \item
% Dynamisches Array: variable Anzahl von Elementen desselben Typs
\item
Problem: Elemente unterschiedlichen Typs
\item
Lösung: den Typ des Elements zusätzlich speichern \textarrow\ \newterm{Objekt}
\item
Problem: Die Elemente sind unterschiedlich groß (Speicherplatz).
\item
Lösung: Im Array nicht die Objekte selbst speichern, sondern Zeiger darauf.
\end{itemize}
\begin{itemize}
\item
Funktionen, die mit dem Objekt arbeiten: \newterm{Methoden}
\begin{onlyenv}<1>
\item
Was die Funktion bewirkt,\\
hängt vom Typ des Objekts ab
\item
Realisierung über endlose \lstinline{if}-Ketten
\end{onlyenv}
\begin{onlyenv}<2>
\item
Was die Funktion bewirkt
\begin{picture}(0,0)
\color{red}
\put(-4.00,-0.05){\tikz{\draw[thick](0,0.25)--(3.75,-0.05);%
\draw[thick](-0.1,-0.05)--(3.75,0.3);}}
\end{picture}%
Welche Funktion aufgerufen wird,\\
hängt vom Typ des Objekts ab: \newterm{virtuelle Methode}
\item
Realisierung über endlose \lstinline{if}-Ketten%
\begin{picture}(0,0)
\color{red}
\put(-2.75,-0.05){\tikz{\draw[thick](0,0.25)--(2.5,-0.05);%
\draw[thick](-0.1,-0.05)--(2.5,0.3);}}
% \put(1.5,-1.1){\begin{rotate}{7}\large\bf\textarrow\
% kommt gleich
% nächste Woche
% \end{rotate}}
\end{picture}
Zeiger, die im Objekt gespeichert sind\\
(Genaugenommen: Tabelle von Zeigern)
\end{onlyenv}
\end{itemize}
\end{frame}
\begin{frame}
\showsection
\showsubsection
\begin{itemize}
\item
Problem: Elemente unterschiedlichen Typs
\item
Lösung: den Typ des Elements zusätzlich speichern \textarrow\ \newterm{Objekt}
\item
\newterm{Methoden\/} und \newterm{virtuelle Methoden}
\end{itemize}
\begin{itemize}
\item
Zeiger auf verschiedene Strukturen\\
mit einem gemeinsamen Anteil von Datenfeldern\\
\textarrow\ "`verwandte"' \newterm{Objekte}, \newterm{Klassenhierarchie} von Objekten
\item
Struktur, die \emph{nur\/} den gemeinsamen Anteil enthält\\
\textarrow\ "`Vorfahr"', \newterm{Basisklasse}, \newterm{Vererbung}
\item
% Explizite Typumwandlung eines Zeigers auf die Basisklasse\\
% in einen Zeiger auf die \newterm{abgeleitete Klasse}\\
% \textarrow\ Man kann ein Array unterschiedlicher Objekte\\
% \strut\phantom{\textarrow} in einer Schleife abarbeiten.\\
Zeiger auf die Basisklasse dürfen auf Objekte\\
der \newterm{abgeleiteten Klasse} zeigen\\
\textarrow\ \newterm{Polymorphie}
\end{itemize}
\end{frame}
\subsection{Beispiel: Zahlen und Buchstaben}
\begin{frame}[fragile]
\showsection
\showsubsection
\begin{center}
\begin{minipage}{5cm}
\begin{lstlisting}[gobble=8]
¡typedef struct
{
int type;
} t_base;¿
\end{lstlisting}
\end{minipage}\\[0.5cm]
\begin{minipage}{5cm}
\begin{lstlisting}[gobble=8]
¡typedef struct
{
int type;
int content;
} t_integer;¿
\end{lstlisting}
\end{minipage}
\begin{minipage}{5cm}
\begin{lstlisting}[gobble=8]
¡typedef struct
{
int type;
char *content;
} t_string;¿
\end{lstlisting}
\end{minipage}
\end{center}
\end{frame}
\begin{frame}[fragile]
\begin{center}
\begin{minipage}{5cm}
\begin{lstlisting}[gobble=8]
¡typedef struct
{
int type;
} t_base;¿
\end{lstlisting}
\end{minipage}\\[0.5cm]
\begin{minipage}{5cm}
\begin{lstlisting}[gobble=8]
¡typedef struct
{
int type;
int content;
} t_integer;¿
\end{lstlisting}
\end{minipage}
\begin{minipage}{5cm}
\begin{lstlisting}[gobble=8]
¡typedef struct
{
int type;
char *content;
} t_string;¿
\end{lstlisting}
\end{minipage}\\[0.7cm]
\begin{onlyenv}<1>
\begin{minipage}{8cm}
\begin{lstlisting}[gobble=10]
¡t_integer i = { 1, 42 };
t_string s = { 2, "Hello, world!" };
t_base *object[] = { (t_base *) &i, (t_base *) &s };¿
\end{lstlisting}
\end{minipage}%
\begin{picture}(0,0)
\color{red}
\put(-5.4,-0.8){\mbox{$\underbrace{\rule{1.45cm}{0pt}}_{\shortstack{\strut explizite\\Typumwandlung}}$}}
\end{picture}
\end{onlyenv}
% \begin{onlyenv}<2>
% \begin{minipage}{5cm}
% \begin{lstlisting}[gobble=10]
% ¡typedef union
% {
% t_base base;
% t_integer integer;
% t_string string;
% } t_object;¿
% \end{lstlisting}
% \end{minipage}
% \end{onlyenv}
\end{center}
\end{frame}
\subsection{Unions}
\begin{frame}[fragile]
\showsubsection
Variable teilen sich denselben Speicherplatz.
\medskip
\begin{minipage}[t]{3.7cm}
\begin{lstlisting}[gobble=6]
¡typedef union
{
int8_t i;
uint8_t u;
} num8_t;¿
\end{lstlisting}
\end{minipage}%
\begin{minipage}[t]{4.5cm}
\begin{lstlisting}[gobble=6]
¡int main (void)
{
num8_t test;
test.i = -1;
printf ("%d\n", test.u);
return 0;
}¿
\end{lstlisting}
\end{minipage}
\end{frame}
\begin{frame}[fragile]
\showsubsection
Variable teilen sich denselben Speicherplatz.
\medskip
\begin{minipage}[t]{3.7cm}
\begin{lstlisting}[gobble=6]
¡typedef union
{
char s[8];
uint64_t x;
} num_char_t;¿
\end{lstlisting}
\end{minipage}%
\begin{minipage}[t]{4.5cm}
\begin{lstlisting}[gobble=6]
¡int main (void)
{
num_char_t test = { "Hello!" };
printf ("%lx\n", test.x);
return 0;
}¿
\end{lstlisting}
\end{minipage}
\end{frame}
\begin{frame}[fragile]
\showsubsection
Variable teilen sich denselben Speicherplatz.
\medskip
\begin{minipage}[t]{3.7cm}
\begin{lstlisting}[gobble=6]
¡typedef union
{
t_base base;
t_integer integer;
t_string string;
} t_object;¿
\end{lstlisting}
\end{minipage}%
\begin{minipage}[t]{3.0cm}
\begin{lstlisting}[gobble=6]
¡typedef struct
{
int type;
} t_base;¿
\end{lstlisting}
\end{minipage}%
\begin{minipage}[t]{3.0cm}
\begin{lstlisting}[gobble=6]
¡typedef struct
{
int type;
int content;
} t_integer;¿
\end{lstlisting}
\end{minipage}%
\begin{minipage}[t]{3.0cm}
\begin{lstlisting}[gobble=6]
¡typedef struct
{
int type;
char *content;
} t_string;¿
\end{lstlisting}
\end{minipage}
\bigskip
\begin{center}
\begin{minipage}{8.5cm}
\begin{lstlisting}[gobble=8]
¡tobject *this;
if (this->base.type == T_INTEGER)
printf ("Integer: %d\n", this->integer.content);
else if (this->base.type == T_STRING)
printf ("String: \"%s\"\n", this->string.content);¿
\end{lstlisting}
\end{minipage}
\end{center}
\end{frame}
\subsection{Virtuelle Methoden}
\begin{frame}[fragile]
\showsubsection
\begin{lstlisting}
void print_object (t_object *this)
{
if (this->base.type == T_INTEGER)
printf ("Integer: %d\n", this->integer.content);
else if (this->base.type == T_STRING)
printf ("String: \"%s\"\n", this->string.content);
}
\end{lstlisting}
\begin{picture}(0,0)
\color{red}
\put(9,1.7){\shortstack[l]{if-Kette:\\\strut wird unübersichtlich}}
\put(1,-2){\mbox{\textarrow}}
\put(0,-3){\mbox{Zeiger auf Funktionen}}
\end{picture}
\begin{lstlisting}[xleftmargin=4cm]
void print_integer (t_object *this)
{
printf ("Integer: %d\n", this->integer.content);
}
void print_string (t_object *this)
{
printf ("String: \"%s\"\n", this->string.content);
}
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]
\showsubsection
Zeiger auf Funktionen
\medskip
\begin{lstlisting}
void (* print) (t_object *this);
\end{lstlisting}
\begin{picture}(0,1.2)(0,-0.9)
\color{red}
\put(0.95,0.3){\mbox{$\underbrace{\rule{1cm}{0pt}}$}}
\put(0.2,-0.7){\shortstack{das, worauf print zeigt,\\ist eine Funktion}}
\end{picture}
\begin{itemize}
\item
Objekt enthält Zeiger auf Funktion
\begin{onlyenv}<1>
\medskip
\begin{lstlisting}[gobble=10]
typedef struct
{
void (* print) (union t_object *this);
int content;
} t_integer;
\end{lstlisting}
\vspace*{-1cm}
\end{onlyenv}
\begin{onlyenv}<2->
\vspace*{-3.5cm} % Why doesn't a picture environment work here??? :-(
\begin{lstlisting}[gobble=10,xleftmargin=5.5cm]
typedef struct
{
void (* print) (union t_object *this);
int content;
} t_integer;
\end{lstlisting}
\vspace*{0.85cm}
\bigskip
\smallskip
\end{onlyenv}
\pause
\item
Konstruktor initialisiert diesen Zeiger
\begin{onlyenv}<2>
\medskip
\begin{lstlisting}[gobble=10]
t_object *new_integer (int i)
{
t_object *p = malloc (sizeof (t_integer));
p->integer.print = print_integer;
p->integer.content = i;
return p;
}
\end{lstlisting}
\vspace*{-2cm}
\end{onlyenv}
\pause
\item
Aufruf: "`automatisch"' die richtige Funktion
\begin{onlyenv}<3>
\medskip
\begin{lstlisting}[gobble=10]
for (int i = 0; object[i]; i++)
object[i]->base.print (object[i]);
\end{lstlisting}
\end{onlyenv}
\pause
\medskip
\item
in größeren Projekten:\\
Objekt enthält Zeiger auf Tabelle von Funktionen
\end{itemize}
\end{frame}
\subsection{Beispiel: Graphische Benutzeroberfläche (GUI)}
\begin{frame}[fragile]
\showsubsection
\scriptsize
\begin{lstlisting}
#include <gtk/gtk.h>
int main (int argc, char **argv)
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
GtkWidget *vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
GtkWidget *label = gtk_label_new ("Hello, world!");
gtk_container_add (GTK_CONTAINER (vbox), label);
GtkWidget *button = gtk_button_new_with_label ("Quit");
g_signal_connect (button, "clicked", G_CALLBACK (gtk_main_quit), NULL);
gtk_container_add (GTK_CONTAINER (vbox), button);
gtk_widget_show (button);
gtk_widget_show (label);
gtk_widget_show (vbox);
gtk_widget_show (window);
gtk_main ();
return 0;
}
\end{lstlisting}
\vspace*{-6cm}\strut\hfill
\includegraphics[scale=0.85]{hello-gtk.png}\\[2cm]
\begin{flushright}
\normalsize\bf Praktikumsversuch:\\
Objektorientiertes Zeichenprogramm
\end{flushright}
\end{frame}
\subsection{Ausblick: C++}
\begin{frame}[fragile]
\showsubsection
\begin{center}
\begin{minipage}{5cm}
\begin{lstlisting}[gobble=8]
¡typedef struct
{
void (* print) (union t_object *this);
} t_base;¿
\end{lstlisting}
\end{minipage}\\[0.5cm]
\begin{minipage}{5.5cm}
\begin{lstlisting}[gobble=8]
¡typedef struct
{
void (* print) (...);
int content;
} t_integer;¿
\end{lstlisting}
\end{minipage}
\begin{minipage}{5cm}
\begin{lstlisting}[gobble=8]
¡typedef struct
{
void (* print) (union t_object *this);
char *content;
} t_string;¿
\end{lstlisting}
\end{minipage}
\end{center}
\end{frame}
\begin{frame}[fragile]
\showsubsection
\begin{center}
\begin{minipage}{5cm}
\begin{lstlisting}[gobble=8]
¡struct TBase
{
virtual void print (void);
};¿
\end{lstlisting}
\end{minipage}\\[0.5cm]
\begin{minipage}{5.5cm}
\begin{lstlisting}[gobble=8]
¡struct TInteger: public TBase
{
virtual void print (void);
int content;
};¿
\end{lstlisting}
\end{minipage}
\begin{minipage}{5cm}
\begin{lstlisting}[gobble=8]
¡struct TString: public TBase
{
virtual void print (void);
char *content;
};¿
\end{lstlisting}
\end{minipage}
\end{center}
\end{frame}
\nosectionnonumber{\inserttitle}
\begin{frame}
\shownosectionnonumber
\begin{itemize}
\item[\textbf{1}] \textbf{Einführung}
\hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}}
\item[\textbf{2}] \textbf{Einführung in C}
\item[\textbf{3}] \textbf{Bibliotheken}
\item[\textbf{4}] \textbf{Algorithmen}
\item[\textbf{5}] \textbf{Hardwarenahe Programmierung}
\item[\textbf{6}] \textbf{Objektorientierte Programmierung}
\begin{itemize}
\item[6.0] Dynamische Speicherverwaltung
\item[6.1] Konzepte und Ziele
\item[6.2] Beispiel: Zahlen und Buchstaben
\item[6.3] Unions
\color{medgreen}
\item[6.4] Virtuelle Methoden
\item[6.5] Beispiel: Graphische Benutzeroberfläche (GUI)
\item[6.6] Ausblick: C++
\end{itemize}
\item[\textbf{7}] \textbf{Datenstrukturen}
\vspace*{-1cm}
\end{itemize}
\end{frame}
\begin{frame}
\shownosectionnonumber
\begin{itemize}
\item[\textbf{1}] \textbf{Einführung}
\hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}}
\item[\textbf{2}] \textbf{Einführung in C}
\item[\textbf{3}] \textbf{Bibliotheken}
\item[\textbf{4}] \textbf{Algorithmen}
\item[\textbf{5}] \textbf{Hardwarenahe Programmierung}
\item[\textbf{6}] \textbf{Objektorientierte Programmierung}
\item[\textbf{7}] \textbf{Datenstrukturen}
\begin{itemize}
\color{red}
\item[7.1] Stack und FIFO
\item[7.2] Verkettete Listen
\item[7.3] Bäume
\end{itemize}
\vspace*{-1cm}
\end{itemize}
\end{frame}
\section{Datenstrukturen}
\subsection{Stack und FIFO}
\begin{frame}[fragile]
\showsection
\showsubsection
\begin{minipage}{0.48\textwidth}
Im letzten Praktikumsversuch:
\begin{itemize}
\item
Array nur zum Teil benutzt
\item
Variable speichert genutzte Länge
\item
Elemente hinten anfügen\\
oder entfernen
\arrowitem
Stack\\
\strut
\end{itemize}
\bigskip
\begin{itemize}
\item
hinten anfügen/entfernen: $\mathcal{O}(1)$\hspace*{-1cm}
\item
vorne oder in der Mitte einfügen/entfernen: $\mathcal{O}(n)$
\end{itemize}
\end{minipage}\hfill
\begin{minipage}{0.52\textwidth}
Auch möglich:
\begin{itemize}
\item
Array nur zum Teil benutzt
\item
2 Variable speichern\\genutzte Länge (ringförmig)
\item
Elemente hinten anfügen\\
oder vorne entfernen
\arrowitem
FIFO
\end{itemize}
\bigskip
\begin{itemize}
\item
vorne oder hinten\\
anfügen oder entfernen: $\mathcal{O}(1)$
\item
in der Mitte einfügen/entfernen: $\mathcal{O}(n)$
\end{itemize}
\end{minipage}\hspace*{-1.5mm}
\end{frame}
\begin{frame}[fragile]
\showsection
\showsubsection
\bigskip
\begin{minipage}[b]{6cm}
\begin{center}
"`First In -- First Out"'
\bigskip
\begin{picture}(6,4)
\thicklines
\color{structure}
\put(0.5,0){\line(1,0){5}}
\put(3.5,0){\only<1-5>{\line(0,1){1}}}
\put(4.5,0){\only<1-4>{\line(0,1){1}}}
\put(3.5,1){\only<1-4>{\line(1,0){1}}}
\put(4.0,0.5){\only<1-4>{\makebox(0,0){\lstinline{3}}}}
\put(3.0,1.5){\only<1>{\makebox(0,0)[tl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,-0.45);}}}}
\put(3.0,1.5){\only<1>{\makebox(0,0)[b]{\lstinline{push (3)}}}}
\put(2.5,0){\only<2-6>{\line(0,1){1}}}
\put(2.5,1){\only<2-5>{\line(1,0){1}}}
\put(3.0,0.5){\only<2-5>{\makebox(0,0){\lstinline{7}}}}
\put(2.0,1.5){\only<2>{\makebox(0,0)[tl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,-0.45);}}}}
\put(2.0,1.5){\only<2>{\makebox(0,0)[b]{\lstinline{push (7)}}}}
\put(1.5,0){\only<3-6>{\line(0,1){1}}}
\put(1.5,1){\only<3-6>{\line(1,0){1}}}
\put(2.0,0.5){\only<3-6>{\makebox(0,0){\lstinline{137}}}}
\put(1.0,1.5){\only<3>{\makebox(0,0)[tl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,-0.45);}}}}
\put(1.0,1.5){\only<3>{\makebox(0,0)[b]{\lstinline{push (137)}}}}
\put(4.55,1.05){\only<4>{\makebox(0,0)[bl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,0.45);}}}}
\put(5.00,1.60){\only<4>{\makebox(0,0)[b]{\lstinline{pop ()}: 3}}}
\put(3.55,1.05){\only<5>{\makebox(0,0)[bl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,0.45);}}}}
\put(4.00,1.60){\only<5>{\makebox(0,0)[b]{\lstinline{pop ()}: 7}}}
\put(2.55,1.05){\only<6>{\makebox(0,0)[bl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,0.45);}}}}
\put(3.00,1.60){\only<6>{\makebox(0,0)[b]{\lstinline{pop ()}: 137}}}
\end{picture}
\bigskip
FIFO = Queue = Reihe
\end{center}
\end{minipage}\hfill
\begin{minipage}[b]{6cm}
\begin{center}
"`Last In -- First Out"'
\bigskip
\begin{picture}(6,4)
\thicklines
\color{structure}
\put(1.5,0){\line(1,0){3}}
\put(2.5,0){\line(0,1){1}}
\put(3.5,0){\line(0,1){1}}
\put(2.5,1){\line(1,0){1}}
\put(3.0,0.5){\makebox(0,0){\lstinline{3}}}
\put(2.0,1.5){\only<1>{\makebox(0,0)[tl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,-0.45);}}}}
\put(2.0,1.5){\only<1>{\makebox(0,0)[b]{\lstinline{push (3)}}}}
\put(2.5,1){\only<2-5>{\line(0,1){1}}}
\put(3.5,1){\only<2-5>{\line(0,1){1}}}
\put(2.5,2){\only<2-5>{\line(1,0){1}}}
\put(3.0,1.5){\only<2-5>{\makebox(0,0){\lstinline{7}}}}
\put(2.0,2.5){\only<2>{\makebox(0,0)[tl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,-0.45);}}}}
\put(2.0,2.5){\only<2>{\makebox(0,0)[b]{\lstinline{push (7)}}}}
\put(2.5,2){\only<3-4>{\line(0,1){1}}}
\put(3.5,2){\only<3-4>{\line(0,1){1}}}
\put(2.5,3){\only<3-4>{\line(1,0){1}}}
\put(3.0,2.5){\only<3-4>{\makebox(0,0){\lstinline{137}}}}
\put(2.0,3.5){\only<3>{\makebox(0,0)[tl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,-0.45);}}}}
\put(2.0,3.5){\only<3>{\makebox(0,0)[b]{\lstinline{push (137)}}}}
\put(3.55,3.05){\only<4>{\makebox(0,0)[bl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,0.45);}}}}
\put(4.00,3.60){\only<4>{\makebox(0,0)[b]{\lstinline{pop ()}: 137}}}
\put(3.55,2.05){\only<5>{\makebox(0,0)[bl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,0.45);}}}}
\put(4.00,2.60){\only<5>{\makebox(0,0)[b]{\lstinline{pop ()}: 7}}}
\put(3.55,1.05){\only<6>{\makebox(0,0)[bl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.45,0.45);}}}}
\put(4.00,1.60){\only<6>{\makebox(0,0)[b]{\lstinline{pop ()}: 3}}}
\end{picture}
\bigskip
LIFO = Stack = Stapel
\end{center}
\end{minipage}
%
% \dots
\end{frame}
\begin{frame}
\showsection
\showsubsection
\bigskip
\begin{minipage}[t]{6cm}
Array (Stack, FIFO):\\
in der Mitte einfügen
\begin{center}
\begin{picture}(6,3.8)
\thicklines
\color{structure}
\put(1.5,0){\line(1,0){3}}
\put(2.5,0){\line(0,1){3}}
\put(3.5,0){\line(0,1){3}}
\put(2.5,1){\line(1,0){1}}
\put(3.0,0.5){\makebox(0,0){\lstinline{3}}}
\put(2.5,1){\line(1,0){1}}
\put(3.0,1.5){\makebox(0,0){\lstinline{7}}}
\put(2.5,2){\line(1,0){1}}
\put(3.0,2.5){\makebox(0,0){\lstinline{137}}}
\put(2.5,3){\line(1,0){1}}
\put(1.5,1.5){\makebox(0,0)[b]{\lstinline{push (5)}}}
\put(1.5,1.45){\makebox(0,0)[tl]{\tikz{\draw[-latex, line width=1pt](0,0)--(0.95,-0.45);}}}
\put(3.55,2.5){\makebox(0,0)[bl]{\tikz{\draw[-latex, line width=1pt](0,0)..controls(0.5,0.45)..(0,0.9);}}}
\put(3.55,1.5){\makebox(0,0)[bl]{\tikz{\draw[-latex, line width=1pt](0,0)..controls(0.5,0.45)..(0,0.9);}}}
\pause
\color{red}
\put(4.1,3.0){\makebox(0,0)[l]{\textbf{1.}}}
\put(4.1,2.0){\makebox(0,0)[l]{\textbf{2.}}}
\put(1.5,1.9){\makebox(0,0)[b]{\textbf{3.}}}
\pause
\put(6.0,1.5){\makebox(0,0)[tl]{$\mathcal{O}(n)$}}
\put(5.95,1.45){\makebox(0,0)[br]{\tikz{\draw[-latex](0,0)--(-1.3,0.4);}}}
\put(5.95,1.49){\makebox(0,0)[br]{\tikz{\draw[-latex](0,0)--(-1.3,1.1);}}}
\end{picture}
\end{center}
\end{minipage}\pause\hfill
\begin{minipage}[t]{5cm}
In Array (Stack, FIFO) \dots
\begin{itemize}
\item
einfügen: $\mathcal{O}(n)$
\item
suchen: $\mathcal{O}(n)$
\item
geschickt suchen: $\mathcal{O}(\log n)$
\item
beim Einfügen sortieren:\\
$\mathcal{O}(n \log n)$ \hspace*{-1.8cm}\tikz{\draw[red](-1.8,0)--(0,0.2);\draw[red](-1.8,0.2)--(0,0);}
$\mathcal{O}(n^2)$
\end{itemize}
\end{minipage}
\end{frame}
\subsection{Verkettete Listen}
\begin{frame}
\showsection
\showsubsection
\begin{tikzpicture}
\color{structure}
\node(first) at (0,0.5) {first};
\node[shape=rectangle,draw,line width=1pt](3) at (1,2) {3};
\node[shape=rectangle,draw,line width=1pt](5) at (2,1) {5};
\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(NULL) at (7,2) {NULL};
\draw[-latex](first)--(3);
\only<1>{\draw[-latex](3)--(7);}
\only<2>{\draw[-latex](3) to[out=0] (5);}
\only<2>{\draw[-latex](5) to[in=180] (7);}
\draw[-latex](7)--(137);
\draw[-latex](137)--(NULL);
\end{tikzpicture}
\begin{itemize}
\item
Jeder Datensatz enthält einen Zeiger auf das nächste Element.
\item
Beim letzten Element zeigt der Zeiger auf \lstinline{NULL}.
\item
Eine Variable zeigt auf das erste Element.
\item
Wenn die Liste leer ist, zeigt die Variable auf \lstinline{NULL}.
\arrowitem
(einfach) \textbf{verkettete Liste}
\end{itemize}
\end{frame}
\begin{frame}
\showsection
\showsubsection
\begin{minipage}[t]{5cm}
In Array (Stack, FIFO) \dots
\begin{itemize}
\item
in der Mitte einfügen: $\mathcal{O}(n)$
\item
wahlfreier Zugriff: $\mathcal{O}(1)$
\item
suchen: $\mathcal{O}(n)$
\item
geschickt suchen: $\mathcal{O}(\log n)$
\item
beim Einfügen sortieren:\\
$\mathcal{O}(n \log n)$ \hspace*{-1.8cm}\tikz{\draw[red](-1.8,0)--(0,0.2);\draw[red](-1.8,0.2)--(0,0);}
$\mathcal{O}(n^2)$
\end{itemize}
\end{minipage}\hfill
\begin{minipage}[t]{6cm}
In (einfach) verkettete/r Liste \dots
\begin{itemize}
\item
in der Mitte einfügen: $\mathcal{O}(1)$
\item
wahlfreier Zugriff: $\mathcal{O}(n)$
\item
suchen: $\mathcal{O}(n)$
\item
geschickt \hspace*{-1.7cm}\tikz{\draw[red](-1.7,0)--(0,0.2);\draw[red](-1.7,0.2)--(0,0);}
suchen: {\color{red}$\mathcal{O}(n)$}
\item
beim Einfügen sortieren:
$\mathcal{O}(n \log n)$ \hspace*{-1.8cm}\tikz{\draw[red](-1.8,0)--(0,0.2);\draw[red](-1.8,0.2)--(0,0);}
$\mathcal{O}(n^2)$
\end{itemize}
\end{minipage}
\pause
\medskip
\begin{center}
\begin{minipage}[t]{6cm}
In (ausbalancierten) Bäumen \dots
\begin{itemize}
\item
in der Mitte einfügen: $\mathcal{O}(\log n)$
\item
wahlfreier Zugriff: $\mathcal{O}(\log n)$
\item
suchen: $\mathcal{O}(\log n)$
\item
beim Einfügen sortieren:
$\mathcal{O}(n \log n)$
\end{itemize}
\end{minipage}
\end{center}
\vspace*{-1cm}
\end{frame}
\subsection{Bäume}
\begin{frame}[fragile]
\showsection
\showsubsection
\begin{minipage}[t]{5cm}
\vspace*{-6cm}
\begin{lstlisting}[gobble=6]
¡typedef struct node
{
int content;
struct node *left, *right;
} node;¿
\end{lstlisting}
% \bigskip
\bigskip
\begin{onlyenv}<6->
\begin{itemize}
\item
Einfügen: rekursiv, $\mathcal{O}(\log n)$
\item
Suchen: rekursiv, $\mathcal{O}(\log n)$
\item
beim Einfügen sortieren:\\
rekursiv, $\mathcal{O}(n\log n)$
\begin{onlyenv}<7->
\smallskip
\item
{\color{red}
\emph{Worst Case\/}: $\mathcal{O}(n^2)$\\
vorher bereits sortiert}\\
\textarrow\ balancierte Bäume\\
\hspace*{2.15em}Anwendung: Datenbanken\hspace*{-2cm}
\end{onlyenv}
\end{itemize}
\vspace*{-1cm}
\end{onlyenv}
\end{minipage}\hfill
\begin{minipage}[t]{7cm}
\begin{center}
\begin{tikzpicture}
\color{structure}
\node(root) at (0,0) {\lstinline{node *root;}};
\begin{onlyenv}<2>
\node(3) at (-2,-3) {\lstinline{NULL}};
\node(137) at (2,-3) {\lstinline{NULL}};
\end{onlyenv}
\begin{onlyenv}<2->
\node[shape=rectangle,draw,line width=1pt](7) at (0,-1.5) {7};
\draw[-latex](root)--(7);
\draw[-latex](7)--(3);
\draw[-latex](7)--(137);
\end{onlyenv}
\begin{onlyenv}<3>
\node(3) at (-2,-3) {\lstinline{NULL}};
\end{onlyenv}
\begin{onlyenv}<3->
\node[shape=rectangle,draw,line width=1pt](137) at (2,-3) {137};
\node(137_left) at (1,-4.5) {\lstinline{NULL}};
\node(137_right) at (3,-4.5) {\lstinline{NULL}};
\draw[-latex](137)--(137_left);
\draw[-latex](137)--(137_right);
\end{onlyenv}
\begin{onlyenv}<4>
\node(5) at (-1,-4.5) {\lstinline{NULL}};
\end{onlyenv}
\begin{onlyenv}<4->
\node[shape=rectangle,draw,line width=1pt](3) at (-2,-3) {3};
\node(3_left) at (-3,-4.5) {\lstinline{NULL}};
\draw[-latex](3)--(3_left);
\draw[-latex](3)--(5);
\end{onlyenv}
\begin{onlyenv}<5->
\node[shape=rectangle,draw,line width=1pt](5) at (-1,-4.5) {5};
\node(5_left) at (-2,-6) {\lstinline{NULL}};
\node(5_right) at (0,-6) {\lstinline{NULL}};
\draw[-latex](5)--(5_left);
\draw[-latex](5)--(5_right);
\end{onlyenv}
\end{tikzpicture}
\end{center}
\end{minipage}
\end{frame}
\nosectionnonumber{\inserttitle}
\begin{frame}
\shownosectionnonumber
\begin{itemize}
\item[\textbf{1}] \textbf{Einführung}
\hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}}
\item[\textbf{2}] \textbf{Einführung in C}
\item[\textbf{3}] \textbf{Bibliotheken}
\item[\textbf{4}] \textbf{Algorithmen}
\item[\textbf{5}] \textbf{Hardwarenahe Programmierung}
\item[\textbf{6}] \textbf{Objektorientierte Programmierung}
\item[\textbf{7}] \textbf{Datenstrukturen}
\begin{itemize}
\color{medgreen}
\item[7.1] Stack und FIFO
\item[7.2] Verkettete Listen
\item[7.3] Bäume
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}
\shownosectionnonumber
\begin{itemize}
\item[\textbf{1}] \textbf{Einführung}
\hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}}
\item[\textbf{2}] \textbf{Einführung in C}
\item[\textbf{3}] \textbf{Bibliotheken}
\item[\textbf{4}] \textbf{Algorithmen}
\item[\textbf{5}] \textbf{Hardwarenahe Programmierung}
\item[\textbf{6}] \textbf{Objektorientierte Programmierung}
\item[\textbf{7}] \textbf{Datenstrukturen}
\begin{itemize}
\item[7.1] Stack und FIFO
\item[7.2] Verkettete Listen
\item[7.3] Bäume
\end{itemize}
\end{itemize}
\begin{flushright}
\large\bf\em\color{medgreen}Vielen Dank für Ihre Aufmerksamkeit\\
und viel Erfolg bei den Prüfungen!
\end{flushright}
\end{frame}
\end{document}
File added
% hp-musterloesung-20210211.pdf - Solutions to the Exercises on Low-Level Programming
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021 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: Stack-Operationen, einfach und doppelt verkettete Listen, ternärer Baum
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{tikz}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 11.\ Februar 2021}
\exercise{Stack-Operationen}
Das folgende Programm (\gitfile{hp}{2020ws/20210211}{aufgabe-1.c})
implementiert einen Stapelspeicher (Stack).
Dies ist ein Array, das nur bis zu einer variablen Obergrenze (Stack-Pointer)
tatsächlich genutzt wird.
An dieser Obergrenze kann man Elemente hinzufügen (push).
In dieser Aufgabe sollen zusätzlich Elemente
in der Mitte eingefügt werden (insert).
Die dafür bereits existierenden Funktionen \lstinline{insert()}
und \lstinline{insert_sorted()} sind jedoch fehlerhaft.
\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;
}
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
Korrigieren 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
Korrigieren 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 die Zahl
\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}
\goodbreak
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{Korrigieren 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{hp}{2020ws/20210211}{loesung-1.c})
\item
\textbf{Korrigieren 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{hp}{2020ws/20210211}{loesung-1b-1.c})
oder die Schleife von oben nach unten durchlaufen
(siehe \gitfile{hp}{2020ws/20210211}{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{hp}{2020ws/20210211}{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
(siehe \gitfile{hp}{2020ws/20210211}{loesung-1c.c}).
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{hp}{2020ws/20210211}{loesung-1d.c}) --
wie in der Funktion \lstinline{push_sorted()}
im Beispiel-Programm \gitfile{hp}{2020ws/20210211}{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{Einfach und doppelt verkettete Listen}
Das Beispiel-Programm \gitfile{hp}{2020ws/20210211}{aufgabe-2.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}
\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{hp}{2020ws/20210211}{loesung-2a.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{hp}{2020ws/20210211}{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
Man benötigt also
\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{hp}{2020ws/20210211}{loesung-2b.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}
\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://de.wikipedia.org/wiki/2-3-4-Baum}.)
\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}{2020ws/20210211}{hp-20210211.pdf}),
Seite 42.
\points{3}
%
% Lösung:
%
% 7 137
% / |
% 3 5 12 42
% / \
% 1 2 6
%
% (NULL-Zeiger sind hier nicht dargestellt,
% gehören aber dazu.)
%
\goodbreak
\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}
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{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}{2020ws/20210211}{hp-20190121.pdf}),
Seite 21.}
%
% Lösung:
%
% 7 137
% / |
% 3 5 12 42
% / \
% 1 2 6
%
% (NULL-Zeiger sind hier nicht dargestellt,
% gehören aber dazu.)
%
\begin{center}
\newcommand{\x}{~\makebox(0,0){\raisebox{0.7em}{\rule{1pt}{1.4em}}}~}
\begin{tikzpicture}
\color{blendedblue}
\node(root) at (0,0) {\lstinline{node *root;}};
\node[shape=rectangle,draw,line width=1pt](7-137) at (0,-1.5) {7\x 137};
\draw[-latex](root)--(7-137);
\node[shape=rectangle,draw,line width=1pt](3-5) at (-2,-3) {3\x 5};
\draw[-latex](7-137)--(3-5);
\node[shape=rectangle,draw,line width=1pt](12-42) at (0,-3) {12\x 42};
\draw[-latex](7-137)--(12-42);
\node[shape=rectangle,draw,line width=1pt](1-2) at (-4,-4.5) {1\x 2};
\draw[-latex](3-5)--(1-2);
\node[shape=rectangle,draw,line width=1pt](6) at (0,-4.5) {6};
\draw[-latex](3-5)--(6);
\end{tikzpicture}
\end{center}
Bemerkungen:
\begin{itemize}
\item
Zeiger mit dem Wert \lstinline{NULL} sind nicht dargestellt:
\lstinline{right}-Zeiger von 7/137,
\lstinline{middle}-Zeiger von 3/5,
sämtliche Zeiger von 1/2, 12/42 und 6.
\item
Beim Einfügen der 12 wird die sich bereits vorher in diesem
\lstinline{node} befindliche 42 zu \lstinline{content_right},
und die 12 wird das neue \lstinline{content_left}.
\item
Dieser Baum hat sehr einfache Regeln und ist daher \emph{nicht\/}
balanciert. Insbesondere unsere Regel, daß einmal angelegte Knoten
nicht mehr verändert werden dürfen, steht dem im Wege.
Ein einfaches Beispiel für einen \emph{balancierten\/} ternären
Baum ist der 2-3-Baum -- siehe z.\,B.\ \url{https://en.wikipedia.org/wiki/2-3_tree}.
\end{itemize}
\goodbreak
\item
\textbf{Dasselbe, aber in der Reihenfolge
2, 7, 42, 12, 1, 137, 5, 6, 3.}
%
% Lösung:
%
% 2 7
% / | \
% 1 5 6 12 42
% / \
% 3 137
%
% (NULL-Zeiger sind hier wieder nicht dargestellt,
% gehören aber dazu.)
%
\begin{center}
\newcommand{\x}{~\makebox(0,0){\raisebox{0.7em}{\rule{1pt}{1.4em}}}~}
\begin{tikzpicture}
\color{blendedblue}
\node(root) at (0,0) {\lstinline{node *root;}};
\node[shape=rectangle,draw,line width=1pt](2-7) at (0,-1.5) {2\x 7};
\draw[-latex](root)--(7-137);
\node[shape=rectangle,draw,line width=1pt](1) at (-2,-3) {1};
\draw[-latex](2-7)--(1);
\node[shape=rectangle,draw,line width=1pt](5-6) at (0,-3) {5\x 6};
\draw[-latex](2-7)--(5-6);
\node[shape=rectangle,draw,line width=1pt](3) at (-2,-4.5) {3};
\draw[-latex](5-6)--(3);
\node[shape=rectangle,draw,line width=1pt](12-42) at (2,-3) {12\x 42};
\draw[-latex](2-7)--(12-42);
\node[shape=rectangle,draw,line width=1pt](137) at (4,-4.5) {137};
\draw[-latex](12-42)--(137);
\end{tikzpicture}
\end{center}
Bemerkungen:
\begin{itemize}
\item
Wieder sind Zeiger mit dem Wert \lstinline{NULL} nicht dargestellt:
\lstinline{middle}- und \lstinline{right}-Zeiger von 5/6,
\lstinline{left}- und \lstinline{middle}-Zeiger von 12/42,
sämtliche Zeiger von 1, 3 und 137.
\item
Beim Einfügen der 12 wird wieder die sich bereits vorher in diesem
\lstinline{node} befindliche 42 zu \lstinline{content_right},
und die 12 wird das neue \lstinline{content_left}.
\end{itemize}
\item
\textbf{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.}
Die entscheidende Idee ist \textbf{Rekursion}.
Eine Funktion, die den gesamten Baum ausgibt,
müßte einmalig für den Zeiger \lstinline{root} aufgerufen werden
und folgendes tun:
\begin{enumerate}[\quad 1.]
\item
falls der übergebene Zeiger den Wert \lstinline{NULL} hat,
nichts ausgeben, sondern die Funktion direkt beenden,
\item
sich selbst für den \lstinline{left}-Zeiger aufrufen,
\item
den Wert von \lstinline{content_left} ausgeben,
\item
sich selbst für den \lstinline{middle}-Zeiger aufrufen,
\item
sofern vorhanden (also ungleich \lstinline{-1}),
den Wert von \lstinline{content_right} ausgeben,
\item
sich selbst für den \lstinline{right}-Zeiger aufrufen.
\end{enumerate}
Als C-Fragment:
\begin{lstlisting}[gobble=8]
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);
}
}
\end{lstlisting}
Die Datei \gitfile{hp}{2020ws/20210211}{loesung-3c.c} erweitert dieses Fragment
zu einem vollständigen C-Programm zum Erstellen und sortierten Ausgeben
eines ternären Baums mit den Zahlenwerten von Aufgabenteil (a).
\end{enumerate}
\end{document}
File added
% hp-uebung-20210204.pdf - Exercises on Low-Level Programming
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021 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: Stack-Operationen, einfach und doppelt verkettete Listen, ternärer Baum
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{tikz}
\begin{document}
% \thispagestyle{empty}
\section*{Hardwarenahe Programmierung\\
Übungsaufgaben -- 11.\ Februar 2021}
% Diese Übung enthält Punkteangaben wie in einer Klausur.
% Um zu "`bestehen"', müssen Sie innerhalb von 100 Minuten
% unter Verwendung ausschließlich zugelassener Hilfsmittel
% 17 Punkte (von insgesamt \totalpoints) erreichen.
\exercise{Stack-Operationen}
Das folgende Programm (\gitfile{hp}{2020ws/20210211}{aufgabe-1.c})
implementiert einen Stapelspeicher (Stack).
Dies ist ein Array, das nur bis zu einer variablen Obergrenze (Stack-Pointer)
tatsächlich genutzt wird.
An dieser Obergrenze kann man Elemente hinzufügen (push).
In dieser Aufgabe sollen zusätzlich Elemente
in der Mitte eingefügt werden (insert).
Die dafür bereits existierenden Funktionen \lstinline{insert()}
und \lstinline{insert_sorted()} sind jedoch fehlerhaft.
\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;
}
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
Korrigieren 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
Korrigieren 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 die Zahl
\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}
\goodbreak
\exercise{Einfach und doppelt verkettete Listen}
Das Beispiel-Programm \gitfile{hp}{2020ws/20210211}{aufgabe-2.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}
\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://de.wikipedia.org/wiki/2-3-4-Baum}.)
\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}{2020ws/20210211}{hp-20210211.pdf}),
Seite 42.
% \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}
\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}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment