TheAlgorithms-Python
165 строк · 5.1 Кб
1"""
2This is an implementation of odd-even transposition sort.
3
4It works by performing a series of parallel swaps between odd and even pairs of
5variables in the list.
6
7This implementation represents each variable in the list with a process and
8each process communicates with its neighboring processes in the list to perform
9comparisons.
10They are synchronized with locks and message passing but other forms of
11synchronization could be used.
12"""
13
14from multiprocessing import Lock, Pipe, Process
15
16# lock used to ensure that two processes do not access a pipe at the same time
17# NOTE This breaks testing on build runner. May work better locally
18# process_lock = Lock()
19
20"""
21The function run by the processes that sorts the list
22
23position = the position in the list the process represents, used to know which
24neighbor we pass our value to
25value = the initial value at list[position]
26LSend, RSend = the pipes we use to send to our left and right neighbors
27LRcv, RRcv = the pipes we use to receive from our left and right neighbors
28resultPipe = the pipe used to send results back to main
29"""
30
31
32def oe_process(position, value, l_send, r_send, lr_cv, rr_cv, result_pipe):
33process_lock = Lock()
34
35# we perform n swaps since after n swaps we know we are sorted
36# we *could* stop early if we are sorted already, but it takes as long to
37# find out we are sorted as it does to sort the list with this algorithm
38for i in range(10):
39if (i + position) % 2 == 0 and r_send is not None:
40# send your value to your right neighbor
41process_lock.acquire()
42r_send[1].send(value)
43process_lock.release()
44
45# receive your right neighbor's value
46process_lock.acquire()
47temp = rr_cv[0].recv()
48process_lock.release()
49
50# take the lower value since you are on the left
51value = min(value, temp)
52elif (i + position) % 2 != 0 and l_send is not None:
53# send your value to your left neighbor
54process_lock.acquire()
55l_send[1].send(value)
56process_lock.release()
57
58# receive your left neighbor's value
59process_lock.acquire()
60temp = lr_cv[0].recv()
61process_lock.release()
62
63# take the higher value since you are on the right
64value = max(value, temp)
65# after all swaps are performed, send the values back to main
66result_pipe[1].send(value)
67
68
69"""
70the function which creates the processes that perform the parallel swaps
71
72arr = the list to be sorted
73"""
74
75
76def odd_even_transposition(arr):
77"""
78>>> odd_even_transposition(list(range(10)[::-1])) == sorted(list(range(10)[::-1]))
79True
80>>> odd_even_transposition(["a", "x", "c"]) == sorted(["x", "a", "c"])
81True
82>>> odd_even_transposition([1.9, 42.0, 2.8]) == sorted([1.9, 42.0, 2.8])
83True
84>>> odd_even_transposition([False, True, False]) == sorted([False, False, True])
85True
86>>> odd_even_transposition([1, 32.0, 9]) == sorted([False, False, True])
87False
88>>> odd_even_transposition([1, 32.0, 9]) == sorted([1.0, 32, 9.0])
89True
90>>> unsorted_list = [-442, -98, -554, 266, -491, 985, -53, -529, 82, -429]
91>>> odd_even_transposition(unsorted_list) == sorted(unsorted_list)
92True
93>>> unsorted_list = [-442, -98, -554, 266, -491, 985, -53, -529, 82, -429]
94>>> odd_even_transposition(unsorted_list) == sorted(unsorted_list + [1])
95False
96"""
97process_array_ = []
98result_pipe = []
99# initialize the list of pipes where the values will be retrieved
100for _ in arr:
101result_pipe.append(Pipe())
102# creates the processes
103# the first and last process only have one neighbor so they are made outside
104# of the loop
105temp_rs = Pipe()
106temp_rr = Pipe()
107process_array_.append(
108Process(
109target=oe_process,
110args=(0, arr[0], None, temp_rs, None, temp_rr, result_pipe[0]),
111)
112)
113temp_lr = temp_rs
114temp_ls = temp_rr
115
116for i in range(1, len(arr) - 1):
117temp_rs = Pipe()
118temp_rr = Pipe()
119process_array_.append(
120Process(
121target=oe_process,
122args=(i, arr[i], temp_ls, temp_rs, temp_lr, temp_rr, result_pipe[i]),
123)
124)
125temp_lr = temp_rs
126temp_ls = temp_rr
127
128process_array_.append(
129Process(
130target=oe_process,
131args=(
132len(arr) - 1,
133arr[len(arr) - 1],
134temp_ls,
135None,
136temp_lr,
137None,
138result_pipe[len(arr) - 1],
139),
140)
141)
142
143# start the processes
144for p in process_array_:
145p.start()
146
147# wait for the processes to end and write their values to the list
148for p in range(len(result_pipe)):
149arr[p] = result_pipe[p][0].recv()
150process_array_[p].join()
151return arr
152
153
154# creates a reverse sorted list and sorts it
155def main():
156arr = list(range(10, 0, -1))
157print("Initial List")
158print(*arr)
159arr = odd_even_transposition(arr)
160print("Sorted List\n")
161print(*arr)
162
163
164if __name__ == "__main__":
165main()
166