Prev - #39 Collatz Sequence | Table of Contents | Next - #41 ROT 13 Encryption
mergeTwoLists([1, 3, 6], [5, 7, 8, 9]) → [1, 3, 5, 6, 7, 8, 9]
One of the most efficient sorting algorithms is the merge sort algorithm. Merge sort has two phases: the dividing phase and the merge phase. We won’t dive into this advanced algorithm in this book. However, we can write code for the second half: merging two pre-sorted lists of integers into a single sorted list.
Exercise Description
Write a mergeTwoLists()
function with
two parameters list1
and list2
.
The lists of numbers passed for these parameters are already in sorted order
from smallest to largest number. The function returns a single sorted list of
all numbers from these two lists.
You could write this function in one line of code by using
Python’s sorted()
function:
return sorted(list1 + list2)
But this would defeat the purpose of the exercise, so don’t use
the sorted()
function or sort()
method as part of your solution.
These Python assert
statements stop
the program if their condition is False
. Copy them
to the bottom of your solution program. Your solution is correct if the following
assert
statements’ conditions are all True:
assert mergeTwoLists([1, 3, 6], [5, 7, 8, 9]) == [1, 3, 5, 6, 7, 8, 9]
assert mergeTwoLists([1, 2, 3], [4, 5]) == [1, 2, 3, 4, 5]
assert mergeTwoLists([4, 5], [1, 2, 3]) == [1, 2, 3, 4, 5]
assert mergeTwoLists([2, 2, 2], [2, 2, 2]) == [2, 2, 2, 2, 2, 2]
assert mergeTwoLists([1, 2, 3], []) == [1, 2, 3]
assert mergeTwoLists([], [1, 2, 3]) == [1, 2, 3]
Try to write a solution based on the information in this description. If you still have trouble solving this exercise, read the Solution Design and Special Cases and Gotchas sections for additional hints.
Prerequisite concepts: lists, while
loops, Boolean operators, append()
, for loops, range()
with two
arguments, len()
Solution Design
The lists of integers, already in sorted order, are passed to the
function as parameters list1
and list2. The algorithm begins with two variables, i1 and i2
, which both begin at
index 0
of their respective lists. We also create a
blank list in a variable named result
which stores
the merged results of the two lists.
Inside of a while
loop, the code does
the following:
·
Look at the numbers that i1
and i2 point to.
·
Append the smaller of the two numbers to result
.
·
If i1
’s number was appended, increment
i1
to point to the next number in list1. Otherwise, increment i2
to point to the next number in list2
.
·
Repeat until either i1
or i2 has gone past the end of their list.
For example, Figure 40-1 shows the first three iterations of the
loop when merging lists [1, 3, 6]
and [5, 7, 8, 9].
Figure 40-1: The first three iterations of the loop that merges two lists.
Think of this code as like an asymmetrical zipper: the i1 and i2
variables keep moving
right along their respective lists, appending their values to result. When
either i1
or i2
reaches
the end of their list, the rest of the other list is appended to result. This result
list
contains all of the numbers in list1
and list2 in sorted order, so the function returns it.
Special Cases and Gotchas
Keep in mind that while the list1
and list2 parameters must be sorted lists, they aren’t
required to be the same length.
If either of these list arguments to mergeTwoLists()
isn’t sorted, the function will return a merged list that is also not in sorted
order. For this exercise, however, we’ll assume that mergeTwoLists()
is always called with valid arguments.
Now try to write a solution based on the information in the previous sections. If you still have trouble solving this exercise, read the Solution Template section for additional hints.
Solution Template
Try to first write a solution from scratch. But if you have difficulty, you can use the following partial program as a starting place. Copy the following code from https://invpy.com/mergetwolists-template.py and paste it into your code editor. Replace the underscores with code to make a working program:
def mergeTwoLists(list1, list2):
# Create an empty list to hold the final sorted results:
result = ____
# Start i1 and i2 at index 0, the start of list1 and list2:
i1 = ____
i2 = ____
# Keeping moving up i1 and i2 until one reaches the end of its list:
while i1 < len(____) and ____ < len(list2):
# Add the smaller of the two current items to the result:
if list1[____] < list2[____]:
# Add list1's current item to the result:
result.append(____[i1])
# Increment i1:
i1 += ____
else:
# Add list2's current item to the result:
result.append(____[i2])
# Increment i2:
i2 += ____
# If i1 is not at the end of list1, add the remaining items from list1:
if i1 < len(____):
for j in range(i1, len(list1)):
result.append(____[j])
# If i2 is not at the end of list2, add the remaining items from list2:
if i2 < len(____):
for j in range(i2, len(list2)):
result.append(____[j])
# Return the merged, sorted list:
return result
The complete solution for this exercise is given in Appendix A and https://invpy.com/mergetwolists.py. You can view each step of this program as it runs under a debugger at https://invpy.com/mergetwolists-debug/.
Further Reading
Merge sort uses this “merge two sorted lists into a single sorted list” behavior as a step in its algorithm. You can learn more about merge sort and other recursive algorithms from my book, “The Recursive Book of Recursion.” The full book is freely available under a Creative Commons license at https://inventwithpython.com/recursion/.
Prev - #39 Collatz Sequence | Table of Contents | Next - #41 ROT 13 Encryption