From ecbf274be6c7a6716662ccbc1acf0e23389fd231 Mon Sep 17 00:00:00 2001 From: raj_mathe Date: Mon, 25 Oct 2021 12:33:57 +0200 Subject: [PATCH] =?UTF-8?q?master=20>=20master:=20code=20-=20refactoring?= =?UTF-8?q?=20+=20counting=20f=C3=BCr=20maxsubsum=20=C3=BCberarbeitet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/algorithms/search/exports.py | 2 +- code/algorithms/search/ith_smallest.py | 32 +++++ code/algorithms/search/ith_smallest_dc.py | 65 ---------- code/algorithms/sum/exports.py | 2 +- code/algorithms/sum/maxsubsum.py | 124 ++++++++++++++++-- code/algorithms/sum/maxsubsum_dc.py | 145 ---------------------- 6 files changed, 146 insertions(+), 224 deletions(-) delete mode 100644 code/algorithms/search/ith_smallest_dc.py delete mode 100644 code/algorithms/sum/maxsubsum_dc.py diff --git a/code/algorithms/search/exports.py b/code/algorithms/search/exports.py index f7d5385..0acd389 100644 --- a/code/algorithms/search/exports.py +++ b/code/algorithms/search/exports.py @@ -11,4 +11,4 @@ from code.algorithms.search.interpol import InterpolationSearch; from code.algorithms.search.jump import JumpSearchLinear; from code.algorithms.search.jump import JumpSearchExponentiell; from code.algorithms.search.ith_smallest import FindIthSmallest; -from code.algorithms.search.ith_smallest_dc import FindIthSmallestDC; +from code.algorithms.search.ith_smallest import FindIthSmallestDC; diff --git a/code/algorithms/search/ith_smallest.py b/code/algorithms/search/ith_smallest.py index a3e46af..5126fd0 100644 --- a/code/algorithms/search/ith_smallest.py +++ b/code/algorithms/search/ith_smallest.py @@ -63,3 +63,35 @@ def FindIthSmallest(L: List[int], i: int) -> int: logDebug('Entfernte Minimum: {value}.'.format(value = minValue)); i = i - 1; return FindIthSmallest(L=L[:index] + L[(index+1):], i=i); + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ALGORITHM jump search (D & C) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@algorithmInfos(name='Auswahlproblem (i. kleinstes Element, D & C)', outputnames='value', checks=True, metrics=True, preChecks=preChecks, postChecks=postChecks) +def FindIthSmallestDC(L: List[int], i: int) -> int: + ''' + Inputs: L = Liste von Zahlen, i = Ordinalzahl + + Annahmen: + + - L enthält keine Duplikate. + - L enthält mindestens i Elemente. + + Outputs: Wert des i. kleinste Element in L. + Beachte 1.kleinstes <==> Minimum. + ''' + AddToCounter(); + p = L[len(L)-1]; # NOTE: Pivotelement kann beliebig gewählt werden + Ll = [ x for x in L if x < p ]; + Lr = [ x for x in L if x > p ]; + if len(Ll) == i - 1: + logDebug('Es gibt i-1 Elemente vor p={p}. ==> i. kleinste Element = p'.format(p=p)); + return p; + elif len(Ll) >= i: + logDebug('Es gibt >= i Elemente vor p={p}. ==> Suche in linker Hälfte!'.format(p=p)); + return FindIthSmallestDC(L=Ll, i=i); + else: + i = i - (len(Ll) + 1) + logDebug('Es gibt < i-1 Elemente vor p={p}. ==> Suche in rechter Hälfte!'.format(p=p)); + return FindIthSmallestDC(L=Lr, i=i); diff --git a/code/algorithms/search/ith_smallest_dc.py b/code/algorithms/search/ith_smallest_dc.py deleted file mode 100644 index a7ed6d1..0000000 --- a/code/algorithms/search/ith_smallest_dc.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# IMPORTS -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -from local.maths import *; -from local.typing import *; - -from code.core.log import *; -from code.algorithms.search.sequential import SequentialSearch; -from code.algorithms.methods import *; - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# GLOBAL VARIABLES/CONSTANTS -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -# - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# CHECKS -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def preChecks(L: List[int], i: int, **_): - assert 1 <= i and i <= len(L), 'Der Wert von i muss zw. {lb} und {ub} liegen.'.format(lb = 1, ub = len(L)); - assert sorted(L) == sorted(list(set(L))), 'Ungültiger Input: L darf keine Duplikate enthalten!'; - return; - -def postChecks(L: List[int], i: int, value: int, **_): - L_ = sorted(L); - assert L_[i-1] == value, 'Der Algorithmus hat versagt.'; - return; - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# ALGORITHM jump search -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -@algorithmInfos(name='Auswahlproblem (i. kleinstes Element, D & C)', outputnames='value', checks=True, metrics=True, preChecks=preChecks, postChecks=postChecks) -def FindIthSmallestDC(L: List[int], i: int) -> int: - ''' - Inputs: L = Liste von Zahlen, i = Ordinalzahl - - Annahmen: - - - L enthält keine Duplikate. - - L enthält mindestens i Elemente. - - Outputs: Wert des i. kleinste Element in L. - Beachte 1.kleinstes <==> Minimum. - ''' - AddToCounter(); - p = L[len(L)-1]; # NOTE: Pivotelement kann beliebig gewählt werden - Ll = [ x for x in L if x < p ]; - Lr = [ x for x in L if x > p ]; - if len(Ll) == i - 1: - logDebug('Es gibt genau i-1 Elemente vorm Pivotelment, p. Also ist p das i. kleinste Element.'); - return p; - elif len(Ll) >= i: - logDebug('Es gibt mindestens i Elemente vorm Pivotelement, p. Suche wird in linker Hälfte fortgesetzt.'); - return FindIthSmallestDC(L=Ll, i=i); - else: - i = i - (len(Ll) + 1) - logDebug('Es gibt weniger als i-1 Elemente vorm Pivotelement, p. Suche wird in rechte Hälfte nach {i}. kleinstem Element fortgesetzt.'.format(i=i)); - return FindIthSmallestDC(L=Lr, i=i); diff --git a/code/algorithms/sum/exports.py b/code/algorithms/sum/exports.py index 008022d..414d067 100644 --- a/code/algorithms/sum/exports.py +++ b/code/algorithms/sum/exports.py @@ -6,4 +6,4 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from code.algorithms.sum.maxsubsum import MaxSubSum; -from code.algorithms.sum.maxsubsum_dc import MaxSubSumDC; +from code.algorithms.sum.maxsubsum import MaxSubSumDC; diff --git a/code/algorithms/sum/maxsubsum.py b/code/algorithms/sum/maxsubsum.py index 4ee36e5..9b9d480 100644 --- a/code/algorithms/sum/maxsubsum.py +++ b/code/algorithms/sum/maxsubsum.py @@ -43,17 +43,117 @@ def MaxSubSum(L: List[float]) -> Tuple[float, int, int]: ''' maxSum: float = 0; u: int = 0; - v: int = 0; + v: int = -1; for i in range(len(L)): - for j in range(i+1, len(L)): - thisSum = 0; - # NOTE: Schleibe über Indexes von von i bis j - for k in range(i, j+1): - AddToCounter(); - thisSum += L[k] - if thisSum > maxSum: - logDebug('max Teilsumme aktualisiert: Summe L[i] von i={i} bis {j} = {value}'.format( - i = i, j = j, value = thisSum - )); - maxSum, u, v = thisSum, i, j; + ## Bestimme maximale Teilsumme der linken Rände der Liste ab Index i: + maxSum_, _, k = lRandSum(L[i:]); + if maxSum_ > maxSum: + k += i; # NOTE: muss wegen Offset kompensieren + maxSum, u, v = maxSum_, i, k; + logDebug('max Teilsumme aktualisiert: Summe L[i] von i={u} .. {v} = {value}'.format(u = u, v = v, value = maxSum)); + return maxSum, u, v; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ALGORITHM max sub sum (D & C) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@algorithmInfos(name='MaxSubSum (Maximale Teilsumme mit D & C)', outputnames=('maxSum', 'index_from', 'index_to'), checks=True, metrics=True, preChecks=preChecks, postChecks=postChecks) +def MaxSubSumDC(L: List[float]) -> Tuple[float, int, int]: + ''' + Inputs: L = Liste von Zahlen + Outputs: + - maxSum = Wert der maximalen Summe einer Teilliste aufeinanderfolgender Elemente + - u, v = Indexes so dass die Teilliste [L[u], L[u+1], ..., L[v]] die maximale Summe aufweist + ''' + maxSum = 0; + u = 0; + v = -1; + if len(L) == 1: + ## wenn Liste aus 1 Element besteht, nicht teilen: + if L[0] > maxSum: + v = 0; + maxSum = L[0]; + else: + u = math.ceil(len(L)/2); + Ll = L[:u]; + Lr = L[u:]; + ## berechnet maximale Teilsumme der linken Hälfte: + maxSum1, u1, v1 = MaxSubSumDC(L=Ll); + ## berechnet maximale Teilsumme der rechten Hälfte: + maxSum2, u2, v2 = MaxSubSumDC(L=Lr); + u2, v2 = u2 + len(Ll), v2 + len(Ll); # offsets kompensieren + ## berechnet maximale Teilsumme mit Überschneidung zw. den Hälften: + maxSum3, u3, v3 = lrRandSum(Ll=Ll, Lr=Lr); + ## bestimme Maximum der 3 Möglichkeiten: + maxSum = max(maxSum1, maxSum2, maxSum3); + if maxSum == maxSum1: + maxSum, u, v = maxSum1, u1, v1; + logDebug('max Teilsumme kommt in linker Partition vor: Summe L[i] von i={i} .. {j} = {value}'.format(L = L, i = u, j = v, value = maxSum)); + elif maxSum == maxSum3: + maxSum, u, v = maxSum3, u3, v3; + logDebug('max Teilsumme kommt in Überschneidung vor: Summe L[i] von i={i} .. {j} = {value}'.format(L = L, i = u, j = v, value = maxSum)); + else: # elif maxSum == maxSum2: + maxSum, u, v = maxSum2, u2, v2; + logDebug('max Teilsumme kommt in rechter Partition vor: Summe L[i] von i={i} .. {j} = {value}'.format(L = L, i = u, j = v, value = maxSum)); + return maxSum, u, v; + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# AUXILIARY METHODS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def lrRandSum(Ll: List[float], Lr: List[float]) -> Tuple[float, int, int]: + ''' + Bestimmt maximale Teilsumme einer Teiliste einer Liste, + wobei die Liste in zwei Intervalle partitioniert ist + und die Teilliste beide überschneidet. + + Inputs: Ll, Lr = eine Partition einer Liste von Zahlen in zwei Intervalle + Outputs: maxSum, u=0, v + ''' + maxSumL, u, _ = rRandSum(L=Ll); + maxSumR, _, v = lRandSum(L=Lr); + maxSum = maxSumL + maxSumR; + v += len(Ll) # offsets kompensieren + return maxSum, u, v; + +def lRandSum(L: List[float]) -> Tuple[float, int, int]: + ''' + Bestimmt maximale Teilsumme aller nicht leeren linken Segmente einer Liste. + + Inputs: L = Liste von Zahlen + Outputs: maxSum, u(=0), v + ''' + n = len(L); + ## berechne kumulative Summen (vorwärts) + AddToCounter(n); + total = L[0]; + maxSum = total; + u = 0; + v = 0; + for i in range(1, n): + total += L[i]; + if total > maxSum: + v = i; + maxSum = total; + return maxSum, 0, v; + +def rRandSum(L: List[float]) -> Tuple[float, int, int]: + ''' + Bestimmt maximale Teilsumme aller nicht leeren rechten Segmente einer Liste. + + Inputs: L = Liste von Zahlen + Outputs: maxSum, u, v(=len(L)-1) + ''' + n = len(L); + ## berechne kumulative Summen (rückwärts) + AddToCounter(n); + total = L[n-1]; + maxSum = total; + u = n-1; + v = n-1; + for i in range(0, n-1)[::-1]: + total += L[i]; + if total > maxSum: + u = i; + maxSum = total; return maxSum, u, v; diff --git a/code/algorithms/sum/maxsubsum_dc.py b/code/algorithms/sum/maxsubsum_dc.py deleted file mode 100644 index d68a0cf..0000000 --- a/code/algorithms/sum/maxsubsum_dc.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# IMPORTS -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -from local.maths import *; -from local.typing import *; - -from code.core.log import *; -from code.algorithms.methods import *; - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# GLOBAL VARIABLES/CONSTANTS -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -# - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# CHECKS -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def preChecks(L: List[int], **_): - assert len(L) > 0, 'Liste darf nicht leer sein.'; - return; - -def postChecks(L: List[int], **_): - # TODO - return; - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# ALGORITHM max sub sum -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -@algorithmInfos(name='MaxSubSum (Maximale Teilsumme mit D & C)', outputnames=('maxSum', 'index_from', 'index_to'), checks=True, metrics=True, preChecks=preChecks, postChecks=postChecks) -def MaxSubSumDC(L: List[float]) -> Tuple[float, int, int]: - ''' - Inputs: L = Liste von Zahlen - Outputs: - - maxSum = Wert der maximalen Summe einer Teilliste aufeinanderfolgender Elemente - - u, v = Indexes so dass die Teilliste [L[u], L[u+1], ..., L[v]] die maximale Summe aufweist - ''' - maxSum = 0; - u = 0; - v = -1; - if len(L) == 1: - ## wenn Liste aus 1 Element besteht, nicht teilen: - if L[0] > maxSum: - v = 0; - maxSum = L[0]; - else: - u = math.ceil(len(L)/2); - Ll = L[:u]; - Lr = L[u:]; - ## berechnet maximale Teilsumme der linken Hälfte: - maxSum1, u1, v1 = MaxSubSumDC(L=Ll); - ## berechnet maximale Teilsumme der rechten Hälfte: - maxSum2, u2, v2 = MaxSubSumDC(L=Lr); - u2, v2 = u2 + len(Ll), v2 + len(Ll); # offsets kompensieren - ## berechnet maximale Teilsumme mit Überschneidung zw. den Hälften: - maxSum3, u3, v3 = lrRandSum(Ll=Ll, Lr=Lr); - ## bestimme Maximum der 3 Möglichkeiten: - maxSum = max(maxSum1, maxSum2, maxSum3); - if maxSum == maxSum1: - maxSum, u, v = maxSum1, u1, v1; - logDebug('max Teilsumme kommt in linker Partition vor: Summe L[i] von i={i} bis {j} = {value}'.format(L = L, i = u, j = v, value = maxSum)); - elif maxSum == maxSum3: - maxSum, u, v = maxSum3, u3, v3; - logDebug('max Teilsumme kommt in Überschneidung vor: Summe L[i] von i={i} bis {j} = {value}'.format(L = L, i = u, j = v, value = maxSum)); - else: # elif maxSum == maxSum2: - maxSum, u, v = maxSum2, u2, v2; - logDebug('max Teilsumme kommt in rechter Partition vor: Summe L[i] von i={i} bis {j} = {value}'.format(L = L, i = u, j = v, value = maxSum)); - return maxSum, u, v; - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# AUXILIARY METHODS -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def lrRandSum(Ll: List[float], Lr: List[float]) -> Tuple[float, int, int]: - ''' - Bestimmt maximale Teilsumme einer Teiliste einer Liste, - wobei die Liste in zwei Intervalle partitioniert ist - und die Teilliste beide überschneidet. - - Inputs: Ll, Lr = eine Partition einer Liste von Zahlen in zwei Intervalle - Outputs: maxSum, u=0, v - ''' - maxSumL, u, _ = rRandSum(L=Ll); - maxSumR, _, v = lRandSum(L=Lr); - maxSum = maxSumL + maxSumR; - v += len(Ll) # offsets kompensieren - return maxSum, u, v; - -def lRandSum(L: List[float]) -> Tuple[float, int, int]: - ''' - Bestimmt maximale Teilsumme aller nicht leeren linken Segmente einer Liste. - - Inputs: L = Liste von Zahlen - Outputs: maxSum, u(=0), v - ''' - n = len(L); - ## berechne kumulative Summen (vorwärts) - AddToCounter(n); - total = L[0]; - M = [total]; - for i in range(1, n): - total += L[i]; - M.append(total); - ## berechne maximum - AddToCounter(n); - maxSum = M[0]; - u = 0; - v = 0; - for i in range(1, n): - if M[i] > maxSum: - v = i; - maxSum = M[i]; - return maxSum, 0, v; - -def rRandSum(L: List[float]) -> Tuple[float, int, int]: - ''' - Bestimmt maximale Teilsumme aller nicht leeren rechten Segmente einer Liste. - - Inputs: L = Liste von Zahlen - Outputs: maxSum, u, v(=len(L)-1) - ''' - n = len(L); - ## berechne kumulative Summen (rückwärts) - AddToCounter(n); - total = L[n-1]; - M = [total]; - for i in range(0, n-1)[::-1]: - total += L[i]; - M.insert(0, total); - ## berechne maximum - AddToCounter(n); - maxSum = M[n-1]; - u = n-1; - v = n-1; - for i in range(0, n-1)[::-1]: - if M[i] > maxSum: - u = i; - maxSum = M[i]; - return maxSum, u, v;