Data Structures and Algorithms
muigai unaka
Week 3
Sorting
A comparison-based sorting algorithm in which a pair of elements, current and next, is compared and the elements are swapped if they are not in order. This algorithm is not suitable for large data sets as its time complexity is quadratic Ο (n^2)
Bubble Sort
Say you are sorting a line of 5 people by height from shortest to tallest...
- Start with them lined up in any order
- Go to the first two people and swap them if the second person is taller than the first
- Compare the 2nd person with the person after them, repeat until at end of line
- Repeat until you have gone through the line 5 times
Bubble Sort
Example
/*
* ITERATIVE BUBBLE SORT IMPLEMENTATION
* @params {Array} an array of numbers
* @return {Array} a sorted array of numbers
* @complexity time: O(n^2), space: O(1)
*/
const bubbleSort = (arr = [3, 2, 4, 5]) => {
let len = arr.length;
for (let i = 1; i < len; i++) {
// bubble up the numbers until the last element is in correct place
for (let j = 0; j < len - 1; j++) {
let current = arr[j];
let next = arr[j + 1];
// Compare current item with next. If current item is greater than next item, swap
if (current > next) {
// swap elemenets in place
arr[j] = next;
arr[j + 1] = current;
}
}
}
return arr;
}
bubbleSort([7, 5, 2, 4, 3, 9]); //[2, 3, 4, 5, 7, 9]
bubbleSort([9, 7, 5, 4, 3, 1]); //[1, 3, 4, 5, 7, 9]
bubbleSort([1, 2, 3, 4, 5, 6]); //[1, 2, 3, 4, 5, 6]
Bubble Sort
BubbleSort runs in quadratic time and takes up constant space. This is far too inefficient. We can do better. . .
Quick sort is a divide-and-conquer algorithm. You start off by choosing one element as a pivot element and partitioning the array around it such that: Left side of pivot contains all the elements that are less than the pivot element and Right side contains all elements greater than the pivot.
Quick Sort
Say you are sorting a line of 5 people by height from shortest to tallest...
- Start with them lined up in any order
- Pick a random person in line to use as your pivot.
- Anyone shorter than your pivot goes to their left, anyone taller goes to their right
- Combine everyone then repeat these steps on the people to the left and the right of the original pivot
Quick Sort
Example
/*
* RECURSIVE QUICKSORT IMPLEMENTATION
* @params {Array} arr is an array of numbers
* @returns {Array} an array of sorted numbers
* @complexity time: O(n^2), space: O(log n)
*/
const quicksort = (arr) => {
if (arr.length < 2) return arr;
// select pivot index at middle of array (or at random)
let pivot = Math.floor((arr.length - 1) / 2);
// store element from the array at that pivot index
let val = arr[pivot];
// array to hold elements less than pivot and one for elements greater than pivot
let lesser = [], greater = [];
// remove the pivot from the array so it is not compared
arr.splice(pivot, 1)
// iterate through the array to partition it into 2 sub arrays
for (let item of arr) {
if (item < val) {
lesser.push(item)
} else {
greater.push(item)
}
}
// recurse on the elements that are less/greater than the pivot,
// and place the pivot in between
return [
...quicksort(lesser), val, ...quicksort(greater)
];
}
quicksort([2, 45, 1, 24, 5325, 6, 4])
// [1,2,4,6,24,45,5325]
Quick Sort
Quicksort runs in quadratic time [O(n^2)] in it's worst case but it's average case runs in logarithmic time [O(log n)].
Merge Sort
Merge sort is a divide and conquer algorithm. It divides the bigger problem into smaller problems, conquers (or solves) them and then combines each of the solutions to the small problems in order to solve the bigger problem that we started out with.
/*
* RECURSIVE MERGE SORT IMPLEMENTATION
* @params {Array} an array of numbers
* @return {Array} a sorted array of numbers
* @complexity time: O(n*log n), space: O(n)
*/
function merge_sort(arr) {
// BASE CASE: if array only has one item, it's sorted, return it
if (arr.length === 1) { return arr; }
// find midpoint of array, use it to divide
const center = Math.floor(arr.length / 2);
// all the elements to the left of arr[center]
const left = arr.slice(0, center);
// all the elements to the right of arr[center]
const right = arr.slice(center);
// call merge helper to merge the sorted arrays
return merge_helper(merge_sort(left), merge_sort(right));
}
function merge_helper(left, right) {
// linear space complexity
const results = [];
// iterate through left and right
while (left.length && right.length) {
if (left[0] < right[0]) {
results.push(left.shift());
} else {
results.push(right.shift());
}
}
// all elements sorted, and either left or right has been emptied
return [...results, ...left, ...right];
}
Many Ways to Sort
There are many ways to go about sorting elements from a collection. The ones worth learning are:
- Quicksort ( O (n^2) )
- Heap Sort ( O(n log(n)) )
- Mergesort ( O(n log(n)) )
- Bucket Sort ( O (n^2) )
- Radix Sort ( O(nk) )
асуултууд?
Divide and Conquer
Divide/Break
This step involves breaking the problem into smaller sub-problems. Sub-problems should represent a part of the original problem. This step generally takes a recursive approach to divide the problem until no sub-problem is further divisible. At this stage, sub-problems become atomic in nature but still represent some part of the actual problem.
Conquer/Solve
This step receives a lot of smaller sub-problems to be solved. Generally, at this level, the problems are considered 'solved' on their own.
Merge/Combine
When the smaller sub-problems are solved, this stage recursively combines them until they formulate a solution of the original problem. This algorithmic approach works recursively and conquer & merge steps works so close that they appear as one.
Divide and Conquer
Divide and conquer is the basis for a few common algorithms:
- Quicksort
- Mergesort
- Binary Search
- Strassen's Matrix Multiplication
- Closest Pair (points)
Binary Search
The most popular search algorithms; it finds the position of a target value within a sorted array by repeatedly dividing the search interval in half
Say you are given a list of all of the names in the world sorted alphabetically and you want to find the position of a specific name
- Start off by picking the name at the middle of the list and compare it to the name you are searching for
- If that name is before your name in the alphabet, ignore the names that come before it; else ignore the names after it
- Your list is now half the size it was; select a new middle and repeat the above steps
Binary Search
Example
/*
* ITERATIVE BINARY SEARCH IMPLEMENTATION
* @description Find the position of a passed in value in a sorted collection of data
* @params {Array} a sorted array of numbers
* @params {Number} the number to search for
* @returns the index of the found value, -1 if not found
* @complexity time: O(log n), space: O(1)
* @variants Must operate on a sorted collection
*/
const binarySearchIterative = (arr, numToFind) => {
// set low and high bounds
let low = 0;
let high = arr.length - 1;
let mid;
while (low <= high) {
// find midppint of array
mid = Math.floor(low + ((high - low) / 2));
if (numToFind == arr[mid]) {
return mid; // SUCCESS! found value at this index
} else if (numToFind < arr[mid]) {
// set new high since the value at the
// most recent midpoint is greater than what we're searching for
high = mid - 1;
} else {
// set new low since the value at the
// most recent midpoint is less than what we're searching for
low = mid + 1;
}
}
// numToFind is not found in the array so let's return -1
return -1;
}
binarySearchIterative([1, 2, 3, 4, 5, 6], 4) // 3
Perguntas?
Data Structures and Algorithms Week 3
By Muigai Unaka
Data Structures and Algorithms Week 3
Data Structures and Algorithms week 3 at Resilient Coders. Sorting Algorithms and Binary Search
- 391