Skip to content
Snippets Groups Projects
Commit 12573ea0 authored by Tobias Koelling's avatar Tobias Koelling
Browse files

refactor merge sort

parent 778d8d5a
No related branches found
No related tags found
1 merge request!24complexity lecture
Pipeline #66453 passed
...@@ -157,31 +157,31 @@ bubble_sort(test_values) ...@@ -157,31 +157,31 @@ bubble_sort(test_values)
:::{.fragment fragment-index=1} :::{.fragment fragment-index=1}
1. Array which has $n$ entries 1. Array with $n$ elements
::: :::
:::{.fragment fragment-index=2} :::{.fragment fragment-index=2}
2. Iteratively divide elements into groups 2. Split array in two groups
::: :::
:::{.fragment fragment-index=3} :::{.fragment fragment-index=3}
3. Compare and sort elements of two neighboring groups 3. Sort each group (using Merge Sort, recursively)
::: :::
:::{.fragment fragment-index=4} :::{.fragment fragment-index=4}
4. Save sorted elements into group containing both 4. Merge groups, keep order
::: :::
:::{.fragment fragment-index=5} :::{.fragment fragment-index=5}
5. Keep repeating step 3 and 4 until there is only one group with the full array 5. Recurse until done
::: :::
...@@ -192,29 +192,17 @@ bubble_sort(test_values) ...@@ -192,29 +192,17 @@ bubble_sort(test_values)
```{python} ```{python}
#| echo: true #| echo: true
def Merge_Join(values, idx_left, idx_split, idx_right): def merge_join(left, right):
left_temp = values[idx_left:idx_split+1] i = j = 0
right_temp = values[idx_split+1:idx_right+1] while i < len(left) and j < len(right):
if left[i] < right[j]:
idx_temp_left = 0 yield left[i]
idx_temp_right = 0 i += 1
idx_overall = idx_left
while (idx_temp_left < idx_split-idx_left+1) and (idx_temp_right < idx_right-idx_split):
value_left = left_temp[idx_temp_left]
value_right = right_temp[idx_temp_right]
if (value_left <= value_right):
values[idx_overall] = value_left
idx_temp_left += 1
else: else:
values[idx_overall] = value_right yield right[j]
idx_temp_right += 1 j += 1
idx_overall += 1 yield from left[i:]
yield from right[j:]
if (idx_temp_left < idx_split-idx_left+1):
values[idx_overall:idx_right+1] = left_temp[idx_temp_left:]
elif (idx_temp_right < idx_right-idx_split):
values[idx_overall:idx_right+1] = right_temp[idx_temp_right:]
print(values)
``` ```
::: :::
...@@ -224,17 +212,72 @@ def Merge_Join(values, idx_left, idx_split, idx_right): ...@@ -224,17 +212,72 @@ def Merge_Join(values, idx_left, idx_split, idx_right):
```{python} ```{python}
#| echo: true #| echo: true
def Merge_Sort(values, idx_left, idx_right): def merge_sort(values):
if (idx_left < idx_right): if len(values) < 2: return values
idx_split = (idx_left+idx_right) // 2 split = len(values) // 2
Merge_Sort(values, idx_left, idx_split) res = list(merge_join(merge_sort(values[:split]),
Merge_Sort(values, idx_split+1, idx_right) merge_sort(values[split:])))
Merge_Join(values, idx_left, idx_split, idx_right) print(res)
return res
testvec = [6, 0, 3, 1, 5, 7, 4, 2] testvec = [6, 0, 3, 1, 5, 7, 4, 2]
Merge_Sort(testvec, 0, len(testvec)-1) merge_sort(testvec);
``` ```
## Bubble vs Merge
```{python}
import time
import matplotlib.pylab as plt
import builtins
def get_time(f):
global print
oldprint = print
print = lambda x: None
start = time.perf_counter()
f()
end = time.perf_counter()
print = oldprint
return end - start
def get_times(f, args, n=1):
if n == 1:
return [get_time(lambda: f(a)) for a in args]
else:
return [min(*t) for t in zip(*[[get_time(lambda: f(a)) for a in args] for _ in range(n)])]
```
```{python}
import numpy as np
values = np.random.randint(0, 100000, 10000)
```
```{python}
x = list(range(0, 200, 5))
y1 = get_times(lambda n: bubble_sort(values[:n].tolist()), x, 3)
y2 = get_times(lambda n: merge_sort(values[:n].tolist()), x, 3)
plt.plot(x, y1, label="bubble", ls='--')
plt.plot(x, y2, label="merge")
plt.xlabel("Number of elements n", fontsize=14)
plt.ylabel("Time to compute / s", fontsize=14)
plt.legend()
None
```
## There are more
You may want to study e.g.:
* Heapsort
* Quicksort
* Countingsort
* Bogosort
:::{.smaller}
For an overview, [check Wikipedia](https://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms)
:::
# an example # an example
*(Fibonacci)* *(Fibonacci)*
...@@ -297,20 +340,6 @@ fib2(30) ...@@ -297,20 +340,6 @@ fib2(30)
## Performance Overview ## Performance Overview
```{python} ```{python}
import time
import matplotlib.pylab as plt
def get_time(f):
start = time.perf_counter()
f()
end = time.perf_counter()
return end - start
def get_times(f, args, n=1):
if n == 1:
return [get_time(lambda: f(a)) for a in args]
else:
return [min(*t) for t in zip(*[[get_time(lambda: f(a)) for a in args] for _ in range(n)])]
x1 = list(range(30)) x1 = list(range(30))
x2 = list(range(60)) x2 = list(range(60))
y1 = get_times(fib1, x1) y1 = get_times(fib1, x1)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment