Skip to content

Commit

Permalink
chap12: merge sort
Browse files Browse the repository at this point in the history
  • Loading branch information
AliNisarAhmed committed Aug 15, 2023
1 parent f8122bb commit a01833b
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 0 deletions.
31 changes: 31 additions & 0 deletions python/python-algo-ds/chap12/merge_sort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
def merge_sort(S):
"""Sort (in-place) elements of Python list S using merge-sort"""
n = len(S)
if n < 2:
return

mid = n // 2
S1 = S[0:mid]
S2 = S[mid:n]

merge_sort(S1)
merge_sort(S2)

merge(S1, S2, S)


def merge(S1, S2, S):
i = j = 0
while i + j < len(S):
if j == len(S2) or (i < len(S1) and S1[i] < S2[j]):
S[i + j] = S1[i]
i += 1
else:
S[i + j] = S2[j]
j += 1


if __name__ == "__main__":
l = [4, 5, 6, 34, 2, 7, 8, 9, 0]
merge_sort(l)
print(l)
42 changes: 42 additions & 0 deletions python/python-algo-ds/chap12/merge_sort_lq.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from ..chap7 import LinkedQueue


def merge(S1: LinkedQueue, S2: LinkedQueue, S: LinkedQueue):
while not S1.is_empty() and not S2.is_empty():
if S1.first() < S2.first():
S.enqueue(S1.dequeue())
else:
S.enqueue(S2.dequeue())

while not S1.is_empty():
S.enqueue(S1.dequeue())

while not S2.is_empty():
S.enqueue(S2.dequeue())


def merge_sort(S: LinkedQueue):
n = len(S)
if n < 2:
return

S1 = LinkedQueue()
S2 = LinkedQueue()

while len(S1) < n // 2:
S1.enqueue(S.dequeue())

while not S.is_empty():
S2.enqueue(S.dequeue())

merge_sort(S1)
merge_sort(S2)

merge(S1, S2, S)


if __name__ == "__main__":
l1 = LinkedQueue()
l2 = LinkedQueue()

l1.enqueue(1)
64 changes: 64 additions & 0 deletions python/python-algo-ds/chap12/merge_sort_non_recursive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""
The main idea is to perform merge-sort bottom-up, performing the merges level
by level going up the merge-sort tree.
Given an input array of elements, we begin by merging every
successive pair of elements into sorted runs of length two.
We merge these runs into runs of length four, merge these new runs into runs of
length eight, and so on, until the array is sorted.
To keep the space usage reasonable, we deploy a second array that stores the
merged runs (swapping input and output arrays after each iteration).
"""

import math


def merge(src, result, start, inc):
"""Merge src[start:start+inc] and src[start+inc:start+2*inc] into result"""
# boundary for run 1
end1 = start + inc
# boundary for run 2
end2 = min(start + 2*inc, len(src))

# index into run 1, run 2, result
x, y, z = start, start + inc, start

while x < end1 and y < end2:
if src[x] < src[y]:
# copy from run 1 and increment
result[z] = src[x]
x += 1
else:
# copy from run 2 and increment
result[z] = src[y]
y += 1
# increment z to reflect new result
z += 1

if x < end1:
# copy remainder of run 1 to output
result[z:end2] = src[x:end1]
elif y < end2:
# copy remainder of run 2 to output
result[z:end2] = src[y:end2]


def merge_sort(S):
n = len(S)
logn = math.ceil(math.log(n, 2))
# make temp storage for dest
src, dest = S, [None] * n

# pass i creates all runs of length 2i
for i in (2**k for k in range(logn)):
# each pass merges two length i runs
for j in range(0, n, 2*i):
merge(src, dest, j, i)
# reverse roles of list
src, dest = dest, src

if S is not src:
# additional copy to get results to S
S[0:n] = src[0:n]

0 comments on commit a01833b

Please sign in to comment.