CS5001 / CS5003:
Intensive Foundations of Computer Science
Today's topics:
lst = [12, 4, 9, 18, 53, 82, 15, 99, 98, 14, 11]
lst = [12, 4, 9, 18, 53, 82, 15, 99, 98, 14, 11]
def linear_search(lst, value_to_find):
"""
Perform a linear search to find a value in the list
:param lst: a list
:param value_to_find: the value we want to find
:return: the index of the found element, or -1 if the element does not
exist in the list
>>> linear_search([12, 4, 9, 18, 53, 82, 15, 99, 98, 14, 11], 15)
6
>>> linear_search([12, 4, 9, 18, 53, 82, 15, 99, 98, 14, 11], 42)
-1
"""
for i, value in enumerate(lst):
if value == value_to_find:
return i
return -1
s.find()
), but let's think about how we might do this.s = "The cat in the hat"
find_str(s, "cat")
s.find()
), but let's think about how we might do this.s = "The cat in the hat"
find_str(s, "cat")
def find_str(s, str_to_find):
"""
Returns the index of the first occurrence of str_to_find in s, and -1 if
the string is not contained in s
:param s: a string
:param str_to_find: the string to search for
:return: the index of the first occurrence of str_to_find in s,
-1 if not found
>>> find_str("the cat in the hat", "cat")
4
>>> find_str("aaaaab", "aab")
3
"""
for i in range(len(s) - len(str_to_find) + 1):
found = True
for c, c_to_find in zip(s[i:], str_to_find):
if c != c_to_find:
found = False
break
if found:
return i
def binary_search(sorted_list, value_to_find):
"""
Performs a binary search on sorted_list for value_to_find
:param sorted_list: a sorted list, smallest to largest
:param value_to_find: the value we are looking for
:return: the index of value_to_find, or -1 if not found
"""
low = 0 # the low index
high = len(sorted_list) - 1 # the high index
while low <= high:
mid = (low + high) // 2 # the middle value
if sorted_list[mid] < value_to_find:
low = mid + 1
elif sorted_list[mid] > value_to_find:
high = mid - 1
else: # found!
return mid
return -1
where n is the number of elements, and k is the number of times we have to divide.
Insertion Sort
Selection Sort
Merge Sort
Quicksort
Insertion sort: orders a list of values by repetitively inserting a particular value into a sorted subset of the list
More specifically:
– consider the first item to be a sorted sublist of length 1
– insert second item into sorted sublist, shifting first item if needed
– insert third item into sorted sublist, shifting items 1-2 as needed
– ...
– repeat until all values have been inserted into their proper positions
Algorithm:
Algorithm:
Algorithm:
Algorithm:
Algorithm:
Algorithm:
Algorithm:
Algorithm:
Algorithm:
Best case? The list is already sorted -- nothing to do!
Worst case? The list is completely reversed -- we have to shift the entire list each time!
The best case is said to be "linear" in that we only have to go through the list once (we have to look at n elements).
The worst case is called n2, because we have to look through (and move) all the remaining elements each time.
Insertion sort code:
def insertion_sort(lst):
for i in range(1,len(lst)):
temp = lst[i]
j = i
while j >= 1 and lst[j - 1] > temp:
lst[j] = lst[j - 1]
j -= 1
lst[j] = temp
Insertion sort is an easy sort to code, and it is decently fast for small lists.
def selection_sort(lst):
for i in range(len(lst)):
min_index = i
for j in range(i + 1, len(lst)):
if lst[j] < lst[min_index]:
min_index = j
lst[i], lst[min_index] = lst[min_index], list[i]
def merge(lst1, lst2):
""" Merge two already sorted lists and return the new, sorted list"""
new_list = []
len1 = len(lst1)
len2 = len(lst2)
p1 = 0
p2 = 0
while p1 < len1 and p2 < len2:
if lst1[p1] <= lst2[p2]:
new_list.append(lst1[p1])
p1 += 1
else:
new_list.append(lst2[p2])
p2 += 1
new_list = new_list + lst1[p1:] + lst2[p2:]
return new_list
def merge_sort(lst):
""" Use merge sort to sort lst in place"""
n = len(lst)
if n <= 1:
return lst # list with 0 or 1 elements is already sorted
sublist1 = lst[:n // 2]
sublist2 = lst[n // 2:]
sublist1 = merge_sort(sublist1)
sublist2 = merge_sort(sublist2)
return merge(sublist1, sublist2)
Partition into two new lists -- less than the pivot on the left, and greater than the pivot on the right.
Even if all elements go into one list, that was just a poor partition.
Keep partitioning the sub-lists
Keep partitioning the sub-lists
Keep partitioning the sub-lists
The quicksort functions:
def partition(lst, pivot):
""" Partition a list into low and high elements, based on the pivot index"""
pivot_val = lst[pivot]
small_list = []
large_list = []
for i, value in enumerate(lst):
if i == pivot:
continue
if value < pivot_val:
small_list.append(value)
else:
large_list.append(value)
return small_list, large_list
def quicksort(lst):
"""Perform quicksort on a list, in place"""
if len(lst) <= 1:
return lst
# pick a random partition
pivot = random.randint(0, len(lst)-1)
small_list, large_list = partition(lst, pivot)
return quicksort(small_list) + [lst[pivot]] + quicksort(large_list)