-
Notifications
You must be signed in to change notification settings - Fork 0
/
zad1.py
120 lines (99 loc) · 3.61 KB
/
zad1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
""" O(n * log(n)) - sortowanie Quick Sortem"""
from zad1testy import runtests
def quick_sort(arr, *, fn=lambda x: x):
_quick_sort(arr, 0, len(arr) - 1, fn)
def _quick_sort(arr, left_idx, right_idx, fn):
while left_idx < right_idx:
pivot_position = _partition(arr, left_idx, right_idx, fn)
if pivot_position - left_idx < right_idx - pivot_position:
_quick_sort(arr, left_idx, pivot_position - 1, fn)
left_idx = pivot_position + 1
else:
_quick_sort(arr, pivot_position + 1, right_idx, fn)
right_idx = pivot_position - 1
def _partition(arr, left_idx, right_idx, fn):
pivot = fn(arr[right_idx])
# Partition an array into 2 subarrays of elements lower than
# pivot and of elements greater than a pivot
i = left_idx
for j in range(left_idx, right_idx):
if fn(arr[j]) < pivot:
_swap(arr, i, j)
i += 1
# Place a pivot element on its destination index
_swap(arr, i, right_idx)
return i # Return a pivot position after the last swap
def _swap(arr, i, j):
arr[i], arr[j] = arr[j], arr[i]
def dominance_helper(P, fn1, fn2):
n = len(P)
# Sort points by the specified coordinate coordinate
quick_sort(P, fn=fn1)
# Create an array of tuples sorted by the second coordinate
# of points which will store also an index to the P array
A = [(fn2(P[i]), i) for i in range(n)]
quick_sort(A, fn=lambda p: p[0])
# Create an array of numbers which will indicate on which
# positions should be points from the P array stored when
# sorted by the second coordinate specified. If there are
# points with the same first coordinate, we will store the
# same number for them
order = [-1] * n
k = 0
order[A[0][1]] = k
for i in range(1, n):
if A[i][0] != A[i - 1][0]:
k += 1
order[A[i][1]] = k
# Create a set of points which dominate all the remaining
# points by the first coordinate specified and aren't dominated
# by any of rejected points
start = float('inf')
B = []
for i in range(n):
if order[i] < start:
B.append(P[i])
start = order[i]
return B
def intersection(A, B):
C = []
# Sort points in both arrays by their both coordinates
# in the same order
quick_sort(A)
quick_sort(B)
# Merge A and B arrays into one array which will contain
# all elements which are in both A and B array
i = j = 0
while i < len(A) and j < len(B):
if A[i][0] < B[j][0] or (A[i][0] == B[j][0] and A[i][1] < B[j][1]):
i += 1
elif A[i][0] > B[j][0] or (A[i][0] == B[j][0] and A[i][1] > B[j][1]):
j += 1
else: # If points have both coordinates the same
C.append(A[i])
i += 1
j += 1
return C
def dominance(P):
n = len(P)
# Sort points in order to easily restore indices later
temp = [(P[i], i) for i in range(n)]
quick_sort(temp, fn=lambda p: p[0])
# Get an array of points which dominate all other points by x coordinate
A = dominance_helper(P, lambda p: p[0], lambda p: p[1])
# Get an array of points which dominate all other points by y coordinate
B = dominance_helper(P, lambda p: p[1], lambda p: p[0])
# Create an intersection of both arrays of points
C = intersection(A, B)
# Map resulting points to their indices in an initial array
m = len(C)
D = []
i = j = 0
while i < n and j < m:
if temp[i][0] == C[j]:
D.append(temp[i][1])
j += 1
i += 1
quick_sort(D)
return D
runtests(dominance)