Initial commit with cleaned history

This commit is contained in:
2024-09-01 18:09:25 +02:00
commit 208004e9d0
273 changed files with 234697 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
// g++ -std=c++14 -Wall -Wextra -Werror -pedantic ./w4/binarysearch.cpp -o ./bin/binarysearch
#include <iostream>
#include <vector>
int binarySearch(int query, std::vector<int> &elems)
{
unsigned low = 0;
unsigned high = elems.size() - 1;
unsigned index = (low + high) / 2;
while (low < high)
{
if (query == elems[index])
{
return elems[index];
}
if (query < elems[index])
{
high = index - 1;
}
else
{
low = index + 1;
}
index = (low + high) / 2;
}
return elems[index];
}
int main()
{
std::vector<int> searchtest = {1, 4, 6, 12, 19, 22, 34, 36, 100};
std::cout << "Binärsuche: " << binarySearch(36, searchtest) << std::endl;
std::cout << "Binärsuche: " << binarySearch(1000, searchtest) << std::endl;
std::cout << "Binärsuche: " << binarySearch(0, searchtest) << std::endl;
std::cout << "Binärsuche: " << binarySearch(5, searchtest) << std::endl;
}
+53
View File
@@ -0,0 +1,53 @@
// g++ -std=c++14 -Wall -Wextra -Werror -pedantic ./w4/bubblesort.cpp -o ./bin/bubblesort
#include <iostream>
#include <vector>
void bubbleSort(std::vector<int>& arr, bool ascending) {
int n = arr.size();
for (int i = 0; i < n - 1; ++i) {
bool swapped = false;
for (int j = 0; j < n - i - 1; ++j) {
if ((arr[j] > arr[j + 1] && ascending) || (arr[j] < arr[j + 1] && !ascending)) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (!swapped) {
break;
}
}
}
int main() {
int arr[] = {30, 10, 25, 100, 5, 16};
int n = sizeof(arr) / sizeof(arr[0]);
std::vector<int> numbers(arr, arr + n);
bool ascending = true;
// Ascending sort
bubbleSort(numbers, ascending);
std::cout << "Sorted list (ascending): ";
for (unsigned i = 0; i < numbers.size(); ++i) {
std::cout << numbers[i] << " ";
}
std::cout << std::endl;
// Descending sort
ascending = false;
bubbleSort(numbers, ascending);
std::cout << "Sorted list (descending): ";
for (unsigned i = 0; i < numbers.size(); ++i) {
std::cout << numbers[i] << " ";
}
std::cout << std::endl;
return 0;
}
+31
View File
@@ -0,0 +1,31 @@
# 1. Gierige Algorithmen
## a)
Gegeben:
Eine Liste L von n Dateien. Jede Datei i hat eine Größe s_i und eine Zugriffswahrscheinlichkeit p_i. Da die Wahrscheinlichkeit für alle Dateien gleich ist, ist p_i = 1/n für alle i.
Ein Bandspeicher.
Gesucht:
Eine optimale Reihenfolge der Dateien auf dem Band, um die erwartete Zugriffszeit zu minimieren. Die Zugriffszeit auf eine Datei i ist gleich der Summe der Größen aller Dateien, die vor i auf dem Band stehen.
## b)
Eine einfache gierige Strategie zur Lösung dieses Problems wäre, die Dateien in aufsteigender Reihenfolge ihrer Größe auf das Band zu schreiben. Der gierige Algorithmus sortiert die Dateien nach ihrer Größe und schreibt sie in dieser Reihenfolge auf das Band.
1. Eingabe: Liste L von Dateien mit Größen s_i
2. Sortiere L in aufsteigender Reihenfolge nach s_i
3. Schreibe die Dateien in der sortierten Reihenfolge auf das Band
## c)
Angenommen, wir haben eine optimale Reihenfolge O und die gierige Reihenfolge G, und O unterscheidet sich von G. Wir können immer zwei benachbarte Dateien in O finden, die in umgekehrter Reihenfolge im Vergleich zu G angeordnet sind, d.h. eine größere Datei steht vor einer kleineren.
Wir nehmen diese beiden Dateien und tauschen sie. Dieser Tausch führt zu einer Reduzierung oder zumindest zu keiner Änderung der gesamten Zugriffszeit, da jede Zugriffsoperation auf die größere Datei jetzt weniger kostet. Dieser Tausch verletzt nicht die Ordnung der restlichen Dateien.
Indem wir dieses Verfahren wiederholen, können wir die Reihenfolge O allmählich in die Reihenfolge G umwandeln, ohne dass die Gesamtzugriffszeit steigt. Daher muss G mindestens genauso gut sein wie jede andere Reihenfolge, einschließlich O. Daher ist G optimal.
## d)
d4,d1,d3,d6,d2,d5
+52
View File
@@ -0,0 +1,52 @@
/* Informatik B - Sommersemester 2023
Vorlesung am 12.05.2023
Katharina Klost
Hilfsfunktionen zum Sortieren, nur zusammen mit der sorting.cpp zu compilieren
*/
#include <iostream>
#include <vector>
#include "hilfsfunktionen.hpp"
namespace hf{
void gebe_aus(std::vector<int>& vec, unsigned start, unsigned end){
if(end>vec.size()){
std::cout << vec.size() << " " << end << std::endl;
return;
}
std::cout << vec[start];
for(unsigned k=start+1; k<end; k++){
std::cout << ", " << vec[k];
}
std::cout << std::endl;
}
void swap(std::vector<int>& elems, unsigned i, unsigned j){
if (i>=elems.size() || j >= elems.size()){
return;
}
int tmp = elems[i];
elems[i] = elems[j];
elems[j] = tmp;
}
unsigned minimumIndex(std::vector<int>& elems, unsigned start, unsigned end){
unsigned min = start;
for(unsigned i = start; i<end; i++){
if(elems[i] < elems[min]){
min = i;
}
}
return min;
}
std::vector<int> copy(std::vector<int>& elems, unsigned start, unsigned end){
std::vector<int> returnVec;
for(unsigned i= start; i<end; i++){
returnVec.push_back(elems[i]);
}
return returnVec;
}
}
+57
View File
@@ -0,0 +1,57 @@
/* Informatik B - Sommersemester 2023
Vorlesung am 12.05.2023
Katharina Klost
Headerdatei zu den Hilfsfunktionen zum Sortieren
*/
#include <vector>
// #include "telefonbuch.hpp"
namespace hf{
/*
Voraussetzung: 0 <= start <= end < vec.elems()
Ergebnis: Keins
Effekt: Gibt die Elemente des Vektors im Intervall [start,end) aus
*/
void gebe_aus(std::vector<int>& elems, unsigned start, unsigned end);
/*
Voraussetzung: 0<=start<=end < vec.elems()
Ergebnis: Ein vector, mit alle Elemente im Intervall [start, end)
Effekt: Keiner
*/
std::vector<int> copy(std::vector<int>& elems, unsigned start, unsigned end);
/*
Voraussetzung: 0 <= i,j <= elems.size()
Ergebnis: Keins
Effekt: Tauscht die Einträge and Position i und j
*/
void swap(std::vector<int>& elems, unsigned i, unsigned j);
/*
Voraussetzung: Es gilt 0 <= start <= end < elems.size()
Effekt: Keiner
Ergebni: Index des kleinesten Elements zwischen start und end
*/
unsigned minimumIndex(std::vector<int>& elems, unsigned start, unsigned end);
/*
Voraussetzung: left < right
Ergebnis: Eine Zufallszahl zwischen left(inklusive) und right (exklusive)
Effekt: Keiner
*/
int zufall(int left, int right);
std::vector<int> sortiertes_array(unsigned size, bool aufsteigend);
std::vector<int> zufalls_array(unsigned size);
void test();
}
+39
View File
@@ -0,0 +1,39 @@
/*
g++ -std=c++14 -Wall -Wextra -Werror -pedantic ./w4/hilfsfunktionen.cpp ./w4/insertionsort.cpp -o ./bin/insertionsort
Insertion Sort funktioniert, indem es durch das Array läuft und jedes Element nach links verschiebt,
bis es das erste Element findet, das kleiner ist. Dieser Prozess wird für jedes Element im Array wiederholt,
bis das gesamte Array sortiert ist. Im Hauptprogramm (main) wird der Insertion Sort Algorithmus auf ein Testarray angewendet
und das Array vor und nach der Sortierung ausgegeben.
*/
#include <vector>
#include "hilfsfunktionen.hpp"
void insertionSort(std::vector<int>& elems){
// Der Schlüssel ist das Element, das wir gerade sortieren
int key=elems[0];
unsigned shiftindex;
// Beginne mit dem zweiten Element (Index 1)
for(unsigned i = 1; i<elems.size();i++){
// Aktualisiere den Schlüssel auf das aktuelle Element
key=elems[i];
// Verschiebe jedes Element, das größer als der Schlüssel ist, um eine Position nach rechts
for(shiftindex=i; shiftindex>0&&elems[shiftindex-1]>=key;shiftindex--){
elems[shiftindex] = elems[shiftindex-1];
}
// Füge den Schlüssel an der richtigen Position ein
elems[shiftindex] = key;
}
}
int main(){
std::vector<int> test = {1,4,2,67,3,76,13,8,10,22,6,9,5,11,32,0};
hf::gebe_aus(test, 0, test.size());
insertionSort(test);
hf::gebe_aus(test, 0, test.size());
}
+58
View File
@@ -0,0 +1,58 @@
/*
g++ -std=c++14 -Wall -Wextra -Werror -pedantic ./w4/hilfsfunktionen.cpp ./w4/mergesort.cpp -o ./bin/mergesort
Dieser Algorithmus verwendet den Divide-and-Conquer-Ansatz, um das Array zu sortieren. Zuerst wird das Array in zwei Hälften geteilt.
Diese Hälften werden dann rekursiv sortiert (mit mergeSortHelp). Danach werden die beiden sortierten Hälften mit der merge Funktion
zusammengeführt. Dieser Prozess wird fortgesetzt, bis das gesamte Array sortiert ist. Im Hauptprogramm (main) wird der Merge Sort
Algorithmus auf ein Testarray angewendet und das Array vor und nach der Sortierung ausgegeben.
*/
#include <vector>
#include "hilfsfunktionen.hpp"
void merge(std::vector<int>& elems, unsigned begin, unsigned mid, unsigned end){
// Kopiere die erste und zweite Hälfte des zu sortierenden Bereichs in neue Vektoren
std::vector<int> firstHalf = hf::copy(elems, begin, mid);
std::vector<int> secondHalf = hf::copy(elems, mid, end);
// Initialisiere Zähler für die beiden Hälften
unsigned i = 0;
unsigned j = 0;
// Iteriere durch den zu sortierenden Bereich
while(begin + i + j < end){
// Wenn alle Elemente aus der zweiten Hälfte kopiert wurden oder das aktuelle Element der ersten Hälfte kleiner ist als das der zweiten Hälfte
if ( j >= secondHalf.size() || ((i<firstHalf.size()) && (firstHalf[i]<secondHalf[j]))){
// Kopiere das aktuelle Element der ersten Hälfte in den ursprünglichen Vektor
elems[begin+i+j] = firstHalf[i];
i++;
}else{
// Kopiere das aktuelle Element der zweiten Hälfte in den ursprünglichen Vektor
elems[begin+i+j] = secondHalf[j];
j++;
}
}
}
void mergeSortHelp(std::vector<int>& elems, unsigned start, unsigned end){
if(start==end||start==end-1){
return;
}
unsigned mid = (start+end)/2;
mergeSortHelp(elems, start, mid);
mergeSortHelp(elems, mid, end);
merge(elems, start, mid, end);
}
void mergeSort(std::vector<int>& elems){
mergeSortHelp(elems, 0, elems.size());
}
int main(){
std::vector<int> test = {1,4,2,67,3,76,13,8,10,22,6,9,5,11,32,0};
hf::gebe_aus(test, 0, test.size());
mergeSort(test);
hf::gebe_aus(test, 0, test.size());
}
+68
View File
@@ -0,0 +1,68 @@
// g++ -std=c++14 -Wall -Wextra -Werror -pedantic ./w4/rucksack2.cpp -o ./bin/rucksack2
#include <iostream>
#include <vector>
struct Gegenstand {
int gewicht;
int wert;
Gegenstand(int g, int w) : gewicht(g), wert(w) {}
};
int rucksackWert(const std::vector<Gegenstand>& gegenstaende, int kapazitaet, int index) {
if (index < 0 || kapazitaet == 0) {
return 0;
}
if (gegenstaende[index].gewicht > kapazitaet) {
return rucksackWert(gegenstaende, kapazitaet, index - 1);
} else {
int wert1 = rucksackWert(gegenstaende, kapazitaet, index - 1);
int wert2 = gegenstaende[index].wert + rucksackWert(gegenstaende, kapazitaet - gegenstaende[index].gewicht, index - 1);
return (wert1 > wert2) ? wert1 : wert2;
}
}
std::vector<Gegenstand> rucksackGegenstaende(const std::vector<Gegenstand>& gegenstaende, int kapazitaet, int index) {
if (index < 0 || kapazitaet == 0) {
return std::vector<Gegenstand>();
}
if (gegenstaende[index].gewicht > kapazitaet) {
return rucksackGegenstaende(gegenstaende, kapazitaet, index - 1);
} else {
int wert1 = rucksackWert(gegenstaende, kapazitaet, index - 1);
int wert2 = gegenstaende[index].wert + rucksackWert(gegenstaende, kapazitaet - gegenstaende[index].gewicht, index - 1);
if (wert1 > wert2) {
return rucksackGegenstaende(gegenstaende, kapazitaet, index - 1);
} else {
std::vector<Gegenstand> ausgewaehlteGegenstaende = rucksackGegenstaende(gegenstaende, kapazitaet - gegenstaende[index].gewicht, index - 1);
ausgewaehlteGegenstaende.push_back(gegenstaende[index]);
return ausgewaehlteGegenstaende;
}
}
}
int main() {
std::vector<Gegenstand> gegenstaende;
gegenstaende.push_back(Gegenstand(2, 10));
gegenstaende.push_back(Gegenstand(3, 15));
gegenstaende.push_back(Gegenstand(5, 20));
gegenstaende.push_back(Gegenstand(7, 25));
int kapazitaet = 10;
int optimalerWert = rucksackWert(gegenstaende, kapazitaet, gegenstaende.size() - 1);
std::cout << "Optimaler Wert: " << optimalerWert << std::endl;
std::vector<Gegenstand> optimaleGegenstaende = rucksackGegenstaende(gegenstaende, kapazitaet, gegenstaende.size() - 1);
std::cout << "Optimale Gegenstände: ";
for (const auto& gegenstand : optimaleGegenstaende) {
std::cout << "(" << gegenstand.gewicht << ", " << gegenstand.wert << ") ";
}
std::cout << std::endl;
return 0;
}
+25
View File
@@ -0,0 +1,25 @@
/*
g++ -std=c++14 -Wall -Wextra -Werror -pedantic ./w4/hilfsfunktionen.cpp ./w4/selectionsort.cpp -o ./bin/selectionsort
Dieser Algorithmus durchläuft das Array und findet das kleinste Element, dann tauscht es dieses Element mit dem ersten Element des Arrays.
Danach durchläuft es den restlichen Teil des Arrays, findet das kleinste Element und tauscht es mit dem zweiten Element des Arrays.
Dieser Prozess wird so lange wiederholt, bis das gesamte Array sortiert ist. Im Hauptprogramm (main) wird der Selection Sort Algorithmus auf
ein Testarray angewendet und das Array vor und nach der Sortierung ausgegeben.
*/
#include <vector>
#include "hilfsfunktionen.hpp"
void selectionSort(std::vector<int>& elems){
for(unsigned i = 0; i < elems.size();i++){
hf::swap(elems, i, hf::minimumIndex(elems, i, elems.size()));
}
}
int main(){
std::vector<int> test = {1,4,2,67,3,76,13,8,10,22,6,9,5,11,32,0};
hf::gebe_aus(test, 0, test.size());
selectionSort(test);
hf::gebe_aus(test, 0, test.size());
}
+41
View File
@@ -0,0 +1,41 @@
# 3. Sortieralgorithmen
## a)
Bubblesort ist ein einfacher Sortieralgorithmus, der wiederholt **benachbarte Elemente in einer Liste vergleicht** und sie bei Bedarf vertauscht, bis die gesamte Liste sortiert ist. Der Algorithmus erhält seinen Namen aufgrund der Art und Weise, wie die **größten (oder kleinsten) Elemente "nach oben blubbern"**, ähnlich wie Blasen in einem aufsteigenden Strom.
Der Ablauf des Bubblesort-Algorithmus kann wie folgt beschrieben werden:
1. Beginne mit einer ungeordneten Liste von Elementen.
2. Vergleiche jeweils benachbarte Elemente der Liste. Wenn das linke Element größer (oder kleiner, abhängig von der Sortierreihenfolge) ist als das rechte Element, vertausche sie.
3. Wiederhole diesen Schritt für jedes Paar benachbarter Elemente in der Liste, bis das größte (oder kleinste) Element an die letzte Position der Liste "blubbert".
4. Reduziere die Größe des zu sortierenden Bereichs um 1 und wiederhole Schritt 2 und 3, bis die Liste vollständig sortiert ist.
Der Bubblesort-Algorithmus hat eine Zeitkomplexität von $O(n^2)$, was bedeutet, dass die Anzahl der Vergleiche und Vertauschungen quadratisch mit der Größe der Liste wächst. Es ist daher nicht effizient für große Listen.
Quellen:
- GeeksforGeeks. "Bubble Sort." https://www.geeksforgeeks.org/bubble-sort/
- Wikipedia. "Bubble sort." https://en.wikipedia.org/wiki/Bubble_sort
## c)
Bogosort, auch bekannt als "Monkey Sort" oder "Random Sort", ist ein extrem **ineffizienter Sortieralgorithmus**, der auf dem **Zufall** basiert. Der Algorithmus folgt einem einfachen Prinzip: Überprüfe, ob die gegebene Liste sortiert ist. Wenn nicht, mische die Elemente zufällig und überprüfe erneut. Dieser Vorgang wird so lange wiederholt, bis die Liste tatsächlich sortiert ist.
1. Der Ablauf des Bogosort-Algorithmus kann wie folgt beschrieben werden:
2. Überprüfe, ob die Liste sortiert ist. Wenn ja, beende den Algorithmus.
3. Falls die Liste nicht sortiert ist, mische die Elemente zufällig.
4. Überprüfe erneut, ob die Liste sortiert ist. Wenn nicht, gehe zu Schritt 2.
Der Bogosort-Algorithmus hat keine feste Zeitkomplexität. In der schlechtesten Fallannahme kann es jedoch eine unendliche Anzahl von Mischungen erfordern, um eine sortierte Liste zu erhalten. Das bedeutet, dass die Laufzeit des Algorithmus im schlimmsten Fall unbegrenzt ist.
Aufgrund dieser extremen Ineffizienz wird der Bogosort-Algorithmus nicht für die praktische Sortierung verwendet.
Quellen:
- GeeksforGeeks. "Bogosort." https://www.geeksforgeeks.org/bogosort-permutation-sort/
- Wikipedia. "Bogosort." https://de.wikipedia.org/wiki/Bogosort
Warum sollte man den Algorithmus nicht mit langen Listen testen?
Da der Bogosort-Algorithmus zufällige Mischungen verwendet, um die Sortierung zu erreichen, kann die Laufzeit des Algorithmus sehr lange dauern. Mit zunehmender Größe der Liste steigt die Anzahl der möglichen Permutationen exponentiell an. Das bedeutet, dass die Wahrscheinlichkeit, dass der Algorithmus eine sortierte Liste findet, mit zunehmender Listenlänge sehr gering wird. Für längere Listen ist der Algorithmus praktisch nutzlos und unpraktikabel. Es ist viel effizienter, andere Sortieralgorithmen zu verwenden, die eine bessere Leistungsgarantie bieten.