CS 111 f21 — Binary, Hexadecimal, and Binary Search
1 Binary
- base 10 vs base 2
- what is a bit?
- How many bits would be need to represent the numbers 0 to 63?
- images we've been working with have been 24-bit (8 bits for each color channel)
- How many values do we get with 8 bits?
- all together, 16,777,216 colors
- progression on wiki article https://en.wikipedia.org/wiki/Color_depth
- practice conversions:
2 Hexadecimal
- base 16
- since a single digit in base 16 can be any number between 0 and 15 in base 10, we need new symbols for the numbers beyond 9
- a, b, c, d, e, f are used for 10, 11, 12, 13, 14, and 15, respectively
- how many bits per hexadecimal digit?
- you often see colors written in hexadecimal, with two digits for each color (8 bits)
- still in RGB order
- ff0000 is max red, no green or blue
3 Binary Search
3.1 Warmup
Write a function contains(v, x)
that returns True
is x
is an element in v
and returns False
otherwise. Do not use the in
operator.3
3.2 Guessing Game
- Consider a number guessing game where you are trying to guess a number between 1 and 100.
- What strategy would you use?
- We could start by guessing 1, then 2, then 3, and so on. This would be a linear search strategy, just like
contains
used a linear search to find an element in a list - What if every time you guess, I tell you whether your guess is higher or lower than the number
- A good way to take advantage of these new rules would be to guess right in the middle of the range of possible numbers (i.e., 50).
- That way, if I say the number is higher, you can rule out the lower half of the range. If I say the number is lower, you can rule out the higher half of the range. You can continue this guessing in the middle strategy, each time ruling out half of the remaining numbers.
- Since binary means 2 (why we use it as the name for a numbering system where the digits have 2 possible values), this strategy is called binary search
3.3 Implementation
- How could we apply this binary search strategy to finding a number in a list?
- We don't have another person to say higher or lower, so we will need some other way of narrowing our search.
- In particular, when we check a number in the list, we need that to divide the list into two portions: one where all the numbers are larger and one where all the numbers are smaller.
- The key property here is that the list needs to be sorted.
- That way, when we check the number in the middle against the number we're looking for, we can narrow our search to just half the list.
- That is, if target is greater than the number in the middle of a sorted list, we know we only need to search the upper half of the list.
- Similarly, if target is less than the number in the middle of a sorted list, we know we only need to search the lower half.
def binary_search(nums, target): # we will assume nums is sorted in ascending order low = 0 high = len(nums) - 1 while low <= high: # stop when there are no more elements between low and high to check mid = (low + high) // 2 # get the middle index between low and high item = nums[mid] if target == item: # check if we've found target return True elif target < item: # we should look in the lower half of our range high = mid - 1 # move high index to one less than the mid index else: # we should look in the higher half of our range low = mid + 1 # move low index to one above the mid index return False
We can implement binary search recursively as well, using the recursive call to search the appropriate half of the list:
def binary_search_rec(nums, target): if len(nums) == 0: return False mid = len(nums) // 2 if nums[mid] == target: return True elif target < nums[mid]: return binary_search_rec(nums[:mid], target) else: return binary_search_rec(nums[mid + 1:], target)