infuerno.github.io

CS50 - Week 3

Asymptotic Notation / Big O Notation

O() defines the upper bound of number of operations

Ω() defines the lower bound of the number of operations

theta() can be used where O() and Ω() are the same.

e.g. selection sort without any kind of optimisation - i.e. keep looking for the smallest each time and move it to the end, even if the list is already sorted the problem still takes approx n^2 steps.

Bogosort (aka stupid sort) shuffles a set of cards, then checks if they are sorted ad infinitum.

Some O(n^2) algorithms may be faster for O(n) algorithms for small data sets, but as the data set increases, O(n^2) will always take longer and can really slow down your program.

GDB

run - r - run the program / restart the program break [line/function] - b [line/function] - set a breakpoint b main - set a breakpoint on function main b prog.c:14 - set a breakpoint on line 14 continue - c - continue and break on next break point next - n - step over step - s - step into list - l - print surrounding code - keep typing to keep showing the program l 12 - show the program around line 12 print [variable] - p variable - print a variable print [variable] = [value] - set a variable e.g. p i = 2 will set i to 2 info locals - prints local vars display [variable] - displays the var for the duration - execute previous command make xxx - make the program (having updated e.g. a source file) disable - unset all breakpoints

The only way of finding something in an unsorted array.

Binary search searches for an item in a sorted list by first checking the middle element. If this isn’t what we are looking for, check if our element is bigger or smaller than this element. If bigger, ignore the left half of the list and repeat the same steps on the right side. If smaller, ignore the right half of the list and repeat the same steps on the left side.

Elements either need to be sorted first OR need to be kept sorted at all times.

Running time is O(logn) [where the base doesn’t matter for this problem] and constant time of Ω(1) for the best case scenario where you find the element first time.

Binary search tree

An easy way to keep all elements sorted at all times is to use a binary search tree.

Uses

Considerations

There are many ways to build a binary search tree, some better than others. A decent tactic is just to shuffle the input before building the tree.

Bubble Sort

Insertion Sort

Selection Sort

Quick Sort

Tends to be quicker than bubble sort and insertion sort, but not always - still O(n^2) in worst case scenarios, but more typically has a run time of O(n log n).

Take the right most element - this becomes the pivot. We now need to work up the list comparing each element to the pivot, putting elements smaller than the pivot on one side and elements larger than the pivot on the other side. Finally, place the pivot in the middle of these two sides. The pivot is now in the right place. Recursively do the same again for each side of the pivot. If one side only has one element, this side is now sorted.

In best case scenarios the pivot is in the middle of the list of elements and we truely divide and conquer. In worst case scenarios the pivot elements are at one end or the other and we have to constantly be comparing against all elements.

To improve this, we can cut down on the probability that the pivot is high or low by selecting multiple pivots and choosing the median value.

Arrays and functions

Declare a function which takes an array as a parameter using:

void sort(int values[]);

When passing a one-dimensional array as here, we don’t need to pass in the array’s size.

Call this function using:

int haystack[10];
// .. fill the array
sort(haystack);

Arrays are passed by reference here.