arrow-left

All pages
gitbookPowered by GitBook
1 of 10

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Graph Topological Sort

def graph_topo_sort(num_nodes, edges):
    from collections import deque
    nodes, order, queue = {}, [], deque()
    for node_id in range(num_nodes):
        nodes[node_id] = { 'in': 0, 'out': set() }
    for node_id, pre_id in edges:
        nodes[node_id]['in'] += 1
        nodes[pre_id]['out'].add(node_id)
    for node_id in nodes.keys():
        if nodes[node_id]['in'] == 0:
            queue.append(node_id)
    while len(queue):
        node_id = queue.pop()
        for outgoing_id in nodes[node_id]['out']:
            nodes[outgoing_id]['in'] -= 1
            if nodes[outgoing_id]['in'] == 0:
                queue.append(outgoing_id)
        order.append(node_id)
    return order if len(order) == num_nodes else []

print(graph_topo_sort(3, [[0, 1], [0, 2]]))

Iterative Sorting

# TO-DO: Complete the selection_sort() function below 
def selection_sort( arr ):
    # loop through n-1 elements
    for i in range(0, len(arr) - 1):
        smallest_index = i

        # TO-DO: find next smallest element
        # (hint, can do in 3 loc) 
        for j in range(i+1, len(arr)):
            if arr[j] < arr[smallest_index]:
                smallest_index = j

        # TO-DO: swap
        arr[i], arr[smallest_index] = arr[smallest_index], arr[i]

    return arr

# TO-DO:  implement the Bubble Sort function below
def bubble_sort( arr ):

    # Compare two and swap if a > b
    for i in range(0, len(arr)-1):
        for j in range(i+1, len(arr)):
            if arr[i] > arr[j]:
                arr[i], arr[j] = arr[j], arr[i]

    return arr

# STRETCH: implement the Count Sort function below
def count_sort( arr, maximum=-1 ):
    hash_length = 0

    for i in range(0, len(arr)):
        # If any negative numbers, returns error
        if arr[i] < 0:
            return "Error, negative numbers not allowed in Count Sort"
        # Find highest number in arr
        if arr[i] > hash_length:
            hash_length = arr[i]
        
    # Create hash table with maximum arr values as keys, set to 0
    hash = { i: 0 for i in range(0, hash_length+1)}

    # In hash, increase count of each instance of i in arr
    for i in range(0, len(arr)):
        hash[arr[i]] += 1
    
    # Adds two instance totals to find indices of each element in arr
    for i in range(1, len(hash)):
        hash[i] = hash[i] + hash[i-1]
    
    sorted_arr = [None] * len(arr)
    for i in range(0, len(arr)):
        # Places arr[i] instance into correct index of sorted_arr
        sorted_arr[hash[arr[i]]-1] = arr[i]
        # Decreases i's index in hash
        hash[arr[i]] = hash[arr[i]]-1

    return sorted_arr

Merge Sort

hashtag
What is Merge Sort?

In computer science, merge sort is an efficient, general-purpose, comparison-based sorting algorithm.

Most implementations produce a stable sort, which means that the order of equal elements is the same in the input and output.

It is a divide and conquers algorithm. In the divide and conquer paradigm, a problem is broken into pieces where each piece still retains all the properties of the larger problem – except its size.

hashtag
of Merge Sort

1. .

2. Much More Efficient for small and large data sets.

3. Adaptive that is efficient for the type of data sets that are already substantially sorted.

4. Stable Sorting Algorithm

hashtag
Define Merge Sorting Function

Now, let’s define a new function named merge-sorting which accepts one parameter which is list we pass as an argument to this function.

So this function is to sort an array or list using a merge sorting algorithm.

As we have discussed above, to solve the original problem, each piece is solved individually and then the pieces are merged back together.

For that, we are going to use recursive calls to a new function named merge which accepts two sorted arrays to form a single sort array.

Now in the merge-sort function, the base condition for our recursive call is that if the length of an array or list is equal to 0 or 1 then simply return the first element of the array.

Otherwise, just divide the array into two equal halves and pass both arrays to recursive calls of merge-sort.

And at last, we are going to call merge function after each recursive call to join both sorted array.

hashtag
Define Merge Function

Now we are breaking the array until they are divided individually. So what we want is just join the arrays that we passed in a sorted way to this function and then returned the new array as a result.

Complexity

The overall time complexity of Merge is O(nLogn).

The space complexity of Merge-sort is O(n).

This means that this algorithm takes a lot of space and may slow down operations for large data sets.

hashtag
Define Main Condition

Now, let’s create a main condition where we need to call the above function and pass the list which needs to be sorted.

So let’s manually defined the list which we want to pass as an argument to the function.

Source Code

Output

hashtag
JS Implementation:

hashtag
Merge sort divides an array into halves, calls itself for the two halves, and then merges the two halves.

hashtag
The merge algorithm consists of two functions: the mergeSort function, which takes care of partitioning the arrays, and the merge function, which merges the separate arrays.

hashtag
The implementation of merge sort is the following, and is the easiest to explain using animations as example:

hashtag
We invoke the mergeSort function with the array we want to have sorted. The array gets split in two parts: a left, and a right part. Then, we return the merge function with two arguments, where we call the mergeSort function for the left side of the array, and the mergeSort function for the right side of the array.

hashtag
The mergeSort function gets invoked with the items on the left side of the array, which are 6 and 4. Again, this array gets split in two parts: a left, and a right part. Then, we again return the merge function, where we call the merge sort function for the left side of the array, and the mergeSort function for the right side of the array.

hashtag
The mergeSort function gets invoked with the items on the left side of the array, which is only the item 6 right now. This means that array.length === 1 returns true, which returns the array.

hashtag
For the first time, we invoke the mergeSort function for the right side of the array! Again, this is only one item, so array.length === 1 returns true. The array gets returned.

hashtag
As both arguments returned something, the merge function actually gets called now. The merge function receives two arguments: left and right. In this case, left is 6, and right is 4. In the merge function, we declare 3 variables: a new empty array to which we will push the right values later on, the index on the left side, and the index on the right side.

hashtag
leftIndex < left.length && rightIndex < right.length returns true: the length of both arrays is 1, and the index is 0. (0 < 1 && 0 < 1). The if-statement, left[leftIndex] < right[rightIndex], returns false:

hashtag
left is [6], so left[0] is 6, and right is [4], so right[0] is 4! This means that the else-block gets run, and we push right[0] to the results array. The results array is now [4]. We also increment the rightIndex from 0 to 1. This means that now,

hashtag
leftIndex < left.length && rightIndex < right.length returns false, because 0 < 1 && 1 < 1 is not true. The two arrays get concatenated, and returned. This means that the mergeSort(left) in the merge function we invoked first, finally returned. The exact same logic now applies to mergeSort(right).

hashtag
Right now, mergeSort(left) and mergeSort(right) have returned from the very first merge call! left is [4,6] and [1, 5] is right.

hashtag
The results array, displayed as the yellow box, is by default empty. The index of both the left and the right array are 0, which are displayed with the blue box. left[leftIndex] < right[rightIndex] is 4 < 1 in this case, which returns false. right[rightIndex] gets pushed to the results array, and the rightIndex get incremented by one.

hashtag
As the rightIndex gets incremented by one, right[1] is now 5. 4 < 5 returns true, so left[leftIndex] gets pushed to the results array.

hashtag

hashtag
As the leftIndex gets incremented by one, left[1] is now 6. 6 < 5 returns false, so right[rightIndex] gets pushed to the results array.

hashtag
The while-condition now returns false, which means that the results array gets returned with the leftover value concatenated. We now have our sorted array!

hashtag
Best, average and worst: Each partitioning takes O(n) operations, and every partitioning splits the array O(log(n)). This results in O(n log(n)).

hashtag
Worst space: We save three variables for each element in the array.

Advantages arrow-up-right
Simple implementationarrow-up-right
Merge Sort implementation example in Python Output
carbon (33).png
Screen Shot 2018-12-22 at 17.33.52.png
Screen Shot 2018-12-22 at 17.40.28.png
Screen Shot 2018-12-22 at 17.41.10.png
Screen Shot 2018-12-22 at 17.41.42.png
Screen Shot 2018-12-22 at 17.42.31.png
Screen Shot 2018-12-22 at 17.44.10.png
Screen Shot 2018-12-22 at 17.53.23.png
Screen Shot 2018-12-22 at 17.55.00.png
Screen Shot 2018-12-24 at 14.52.48.png
def mergeSort(x):
    if len(x) == 0 or len(x) == 1:
        return x
    else:
        middle = len(x)//2
        a = mergeSort(x[:middle])
        b = mergeSort(x[middle:])
        return merge(a,b)
def merge(a,b):
    c = []
    while len(a) != 0 and len(b) != 0:
        if a[0] < b[0]:
            c.append(a[0])
            a.remove(a[0])
        else:
            c.append(b[0])
            b.remove(b[0])
    if len(a) == 0:
        c += b
    else:
        c += a
    return c
if __name__ == '__main__':
    List = [3, 4, 2, 6, 5, 7, 1, 9]
    print('Sorted List : ',mergeSort(List))

def merge(a,b):
    c = []
    while len(a) != 0 and len(b) != 0:
        if a[0] < b[0]:
            c.append(a[0])
            a.remove(a[0])
        else:
            c.append(b[0])
            b.remove(b[0])
    if len(a) == 0:
        c += b
    else:
        c += a
    return c

# Code for merge sort

def mergeSort(x):
    if len(x) == 0 or len(x) == 1:
        return x
    else:
        middle = len(x)//2
        a = mergeSort(x[:middle])
        b = mergeSort(x[middle:])
        return merge(a,b)

if __name__ == '__main__':
    List = [3, 4, 2, 6, 5, 7, 1, 9]
    print('Sorted List : ',mergeSort(List))

Merge Sort

# Python program for implementation of MergeSort
def mergeSort(arr):
    

SelectionSort

hashtag
What is Selection Sort?

In computer science, it is a , specifically an in-place comparison sort.

It has O(n2) time complexity, making it inefficient on large lists, and generally performs worse than the similar insertion sort.

Selection sorting is noted for its simplicity, and it has performance advantages over more complicated algorithms in certain situations, particularly where auxiliary memory is limited.

In JavaScript

VISUALIZED

hashtag
<----------------------(Bubble Sort)---------------->

hashtag
Bubble Sort

Insertion Sort

hashtag
What is Insertion Sort?

Insertion sort is good for collections that are very small or nearly sorted. Otherwise, it’s not a good sorting algorithm it moves data around too much.

Each time insertion is made, all elements in a greater position are shifted.

It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort.

function mergeSort(arr) {
    if (arr.length < 2) {
        // Arrays of length 0 or 1 are sorted by definition.
        return arr;
    }

    const left = arr.slice(0, Math.floor(arr.length / 2));
    const right = arr.slice(Math.floor(arr.length / 2), Math.floor(arr.length));

    return merge(mergeSort(left), mergeSort(right));
}

function merge(arr1, arr2) {
    const merged = [];
    let i = 0, j = 0;

    while (i < arr1.length && j < arr2.length) {
        if (arr1[i] <= arr2[j]) {
            merged.push(arr1[i]);
            i++;
        } else if (arr2[j] < arr1[i]) {
            merged.push(arr2[j]);
            j++;
        }
    }

    merged.push(...arr1.slice(i), ...arr2.slice(j));
    return merged;
}

const deepEqual = require('./deepEqual');

console.log(deepEqual(
    mergeSort([]),
    [],
));
console.log(deepEqual(
    mergeSort([1]),
    [1],
));
console.log(deepEqual(
    mergeSort([2, 1]),
    [1, 2],
));
console.log(deepEqual(
    mergeSort([7, 2, 4, 3, 1, 2]),
    [1, 2, 2, 3, 4, 7],
));
console.log(deepEqual(
    mergeSort([1, 2, 3, 4, 5, 0]),
    [0, 1, 2, 3, 4, 5],
));
console.log(deepEqual(
    mergeSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]),
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
));
console.log(deepEqual(
    mergeSort([98322, 3242, 876, -234, 34, 12331]),
    [-234, 34, 876, 3242, 12331, 98322],
));
if
len
(
arr
)
>
1
:
# Finding the mid of the array
mid = len(arr)//2
# Dividing the array elements
L = arr[:mid]
# into 2 halves
R = arr[mid:]
# Sorting the first half
mergeSort(L)
# Sorting the second half
mergeSort(R)
i = j = k = 0
# Copy data to temp arrays L[] and R[]
while i < len(L) and j < len(R):
if L[i] < R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
# Checking if any element was left
while i < len(L):
arr[k] = L[i]
i += 1
k += 1
while j < len(R):
arr[k] = R[j]
j += 1
k += 1
# Code to print the list
def printList(arr):
for i in range(len(arr)):
print(arr[i], end=" ")
print()
# Driver Code
if __name__ == '__main__':
arr = [12, 11, 13, 5, 6, 7]
print("Given array is", end="\n")
printList(arr)
mergeSort(arr)
print("Sorted array is: ", end="\n")
printList(arr)
hashtag
Define Selection Sort

Now, let’s create a new function named SelectionSort which accepts 1 parameter as an argument.

The argument which we pass to this function is an unordered list that is passed to this above function to perform Selection Sorting algorithm on this list and return sorted list back to function call.

Read => Binary Search Algorithm on Sorted List using Loop in Pythonarrow-up-right

So the logic or the algorithm behind Selection Sort is that it iterates all the elements of the list and if the smallest element in the list is found then that number is swapped with the first.

So for this algorithm, we are going to use two for loops, one for traversing through each element from index 0 to n-1.

Another nested loop is used to compare each element until the last element for each iteration.

The Complexity of Selection Sort

The time efficiency of selection sort is quadratic, so there are a number of sorting techniques which have better time complexity than selection sort.

One thing which distinguishes this sort from other sorting algorithms is that it makes the minimum possible number of swaps, n − 1 in the worst case.

hashtag
Define Main Condition

Now let’s define the main condition where we define our unordered list which needs to be passed to the above function we created.

So, pass the user-defined lists to function and print the returned sorted list using the print statement.

Source Code

Output

Selection Sort using For loop in Python Output
sorting algorithmarrow-up-right
![bubble sort]((https://s3-us-west-1.amazonaws.com/appacademy-open-assets/data_structures_algorithms/naive_sorting_algorithms/bubble_sort/images/BubbleSort.gifarrow-up-right)

This project contains a skeleton for you to implement Bubble Sort. In the file lib/bubble_sort.js, you should implement the Bubble Sort. This is a description of how the Bubble Sort works (and is also in the code file).

  • Clone the project from

    https://github.com/appacademy-starters/algorithms-bubble-sort-starterarrow-up-right.

  • cd into the project folder

  • npm install to install dependencies in the project root directory

  • npm test to run the specs

  • You can view the test cases in /test/test.js. Your job is to write code in

    the /lib/bubble_sort.js that implements the Bubble Sort.

This sorting algorithm is comparison-based algorithm in which each pair of adjacent elements is compared and the elements are swapped if they are not in order. This algorithm is not suitable for large data sets as its average and worst case complexity are of Ο(n2) where n is the number of items.

How Bubble Sort Works? We take an unsorted array for our example. Bubble sort takes Ο(n^2) time so we're keeping it short and precise.

Bubble Sort Bubble sort starts with very first two elements, comparing them to check which one is greater.

Bubble Sort In this case, value 33 is greater than 14, so it is already in sorted locations. Next, we compare 33 with 27.

Bubble Sort We find that 27 is smaller than 33 and these two values must be swapped.

Bubble Sort The new array should look like this −

Bubble Sort Next we compare 33 and 35. We find that both are in already sorted positions.

Bubble Sort Then we move to the next two values, 35 and 10.

Bubble Sort We know then that 10 is smaller 35. Hence they are not sorted.

Bubble Sort We swap these values. We find that we have reached the end of the array. After one iteration, the array should look like this −

Bubble Sort To be precise, we are now showing how an array should look like after each iteration. After the second iteration, it should look like this −

Bubble Sort Notice that after each iteration, at least one value moves at the end.

Bubble Sort And when there's no swap required, bubble sorts learns that an array is completely sorted.

Bubble Sort Now we should look into some practical aspects of bubble sort.

Algorithm We assume list is an array of n elements. We further assume that swap function swaps the values of the given array elements.

begin BubbleSort(list)

for all elements of list if list[i] > list[i+1] swap(list[i], list[i+1]) end if end for

return list

end BubbleSort Pseudocode We observe in algorithm that Bubble Sort compares each pair of array element unless the whole array is completely sorted in an ascending order. This may cause a few complexity issues like what if the array needs no more swapping as all the elements are already ascending.

To ease-out the issue, we use one flag variable swapped which will help us see if any swap has happened or not. If no swap has occurred, i.e. the array requires no more processing to be sorted, it will come out of the loop.

Pseudocode of BubbleSort algorithm can be written as follows −

procedure bubbleSort( list : array of items )

loop = list.count;

for i = 0 to loop-1 do: swapped = false

end for

end procedure return list

alt-text

![bubble sort](

bubble

The algorithm bubbles up As you progress through the algorithms and data structures of this course, you'll eventually notice that there are some recurring funny terms. "Bubbling up" is one of those terms.

When someone writes that an item in a collection "bubbles up," you should infer that:

The item is in motion The item is moving in some direction The item has some final resting destination When invoking Bubble Sort to sort an array of integers in ascending order, the largest integers will "bubble up" to the "top" (the end) of the array, one at a time.

The largest values are captured, put into motion in the direction defined by the desired sort (ascending right now), and traverse the array until they arrive at their end destination

How does a pass of Bubble Sort work? Bubble sort works by performing multiple passes to move elements closer to their final positions. A single pass will iterate through the entire array once.

A pass works by scanning the array from left to right, two elements at a time, and checking if they are ordered correctly. To be ordered correctly the first element must be less than or equal to the second. If the two elements are not ordered properly, then we swap them to correct their order. Afterwards, it scans the next two numbers and continue repeat this process until we have gone through the entire array.

See one pass of bubble sort on the array [2, 8, 5, 2, 6]. On each step the elements currently being scanned are in bold.

2, 8, 5, 2, 6 - ordered, so leave them alone 2, 8, 5, 2, 6 - not ordered, so swap 2, 5, 8, 2, 6 - not ordered, so swap 2, 5, 2, 8, 6 - not ordered, so swap 2, 5, 2, 6, 8 - the first pass is complete Because at least one swap occurred, the algorithm knows that it wasn't sorted. It needs to make another pass. It starts over again at the first entry and goes to the next-to-last entry doing the comparisons, again. It only needs to go to the next-to-last entry because the previous "bubbling" put the largest entry in the last position.

2, 5, 2, 6, 8 - ordered, so leave them alone 2, 5, 2, 6, 8 - not ordered, so swap 2, 2, 5, 6, 8 - ordered, so leave them alone 2, 2, 5, 6, 8 - the second pass is complete Because at least one swap occurred, the algorithm knows that it wasn't sorted. Now, it can bubble from the first position to the last-2 position because the last two values are sorted.

2, 2, 5, 6, 8 - ordered, so leave them alone 2, 2, 5, 6, 8 - ordered, so leave them alone 2, 2, 5, 6, 8 - the third pass is complete No swap occurred, so the Bubble Sort stops.

Ending the Bubble Sort During Bubble Sort, you can tell if the array is in sorted order by checking if a swap was made during the previous pass performed. If a swap was not performed during the previous pass, then the array must be totally sorted and the algorithm can stop.

You're probably wondering why that makes sense. Recall that a pass of Bubble Sort checks if any adjacent elements are out of order and swaps them if they are. If we don't make any swaps during a pass, then everything must be already in order, so our job is done.

hashtag
<----------------------(Selection Sort)---------------->

![selection](

hashtag
Selection Sort

This project contains a skeleton for you to implement Selection Sort. In the file lib/selection_sort.js, you should implement the Selection Sort. You can use the same swap function from Bubble Sort; however, try to implement it on your own, first.

The algorithm can be summarized as the following:

  1. Set MIN to location 0

  2. Search the minimum element in the list

  3. Swap with value at location MIN

  4. Increment MIN to point to next element

  5. Repeat until list is sorted

This is a description of how the Selection Sort works (and is also in the code file).

  • Clone the project from

    https://github.com/appacademy-starters/algorithms-selection-sort-starterarrow-up-right.

  • cd into the project folder

  • npm install to install dependencies in the project root directory

  • npm test to run the specs

  • You can view the test cases in /test/test.js. Your job is to write code in

    the /lib/selection_sort.js that implements the Selection Sort.

The algorithm can be summarized as the following:

Set MIN to location 0 Search the minimum element in the list Swap with value at location MIN Increment MIN to point to next element Repeat until list is sorted

![selection](

Starting from the beginning of the list,

1, Find the minimum unsorted element 2 Swap it with the current index (front of the unsorted list) 3 Move to the next index and repeat from step 1 4 Repeat until at the end of the list

The algorithm: select the next smallest Selection sort works by maintaining a sorted region on the left side of the input array; this sorted region will grow by one element with every "pass" of the algorithm. A single "pass" of selection sort will select the next smallest element of unsorted region of the array and move it to the sorted region. Because a single pass of selection sort will move an element of the unsorted region into the sorted region, this means a single pass will shrink the unsorted region by 1 element whilst increasing the sorted region by 1 element. Selection sort is complete when the sorted region spans the entire array and the unsorted region is empty!

hashtag
<----------------------(Insertion Sort)---------------->

hashtag
Insertion Sort

insertion

![insertion](

This project contains a skeleton for you to implement Insertion Sort. In the file lib/insertion_sort.js, you should implement the Insertion Sort.

The algorithm can be summarized as the following:

  1. If it is the first element, it is already sorted. return 1;

  2. Pick next element

  3. Compare with all elements in the sorted sub-list

  4. Shift all the elements in the sorted sub-list that is greater than the

    value to be sorted

  5. Insert the value

  6. Repeat until list is sorted

This is a description of how the Insertion Sort works (and is also in the code file).

  • Clone the project from

    https://github.com/appacademy-starters/algorithms-insertion-sort-starterarrow-up-right.

  • cd into the project folder

  • npm install to install dependencies in the project root directory

  • npm test to run the specs

  • You can view the test cases in /test/test.js. Your job is to write code in

    the /lib/insertion_sort.js that implements the Insertion Sort.

The algorithm: insert into the sorted region

Insertion Sort is similar to Selection Sort in that it gradually builds up a larger and larger sorted region at the left-most end of the array.

insertion

However, Insertion Sort differs from Selection Sort because this algorithm does not focus on searching for the right element to place (the next smallest in our Selection Sort) on each pass through the array. Instead, it focuses on sorting each element in the order they appear from left to right, regardless of their value, and inserting them in the most appropriate position in the sorted region.

insertion

hashtag
<----------------------(Merge Sort)---------------->

hashtag
Merge Sort

merge sort

This project contains a skeleton for you to implement Merge Sort. In the file lib/merge_sort.js, you should implement the Merge Sort.

The algorithm can be summarized as the following:

  1. if there is only one element in the list, it is already sorted. return that

    array.

  2. otherwise, divide the list recursively into two halves until it can no more

    be divided.

  3. merge the smaller lists into new list in sorted order.

This is a description of how the Merge Sort works (and is also in the code file).

  • Clone the project from

    https://github.com/appacademy-starters/algorithms-merge-sort-starterarrow-up-right.

  • cd into the project folder

  • npm install to install dependencies in the project root directory

  • npm test to run the specs

  • You can view the test cases in /test/test.js. Your job is to write code in

    the /lib/merge_sort.js that implements the Merge Sort.

    it is easy to merge elements of two sorted arrays into a single sorted array you can consider an array containing only a single element as already trivially sorted you can also consider an empty array as trivially sorted The algorithm: divide and conquer You're going to need a helper function that solves the first major point from above. How might you merge two sorted arrays? In other words you want a merge function that will behave like so:

alttext
alt
alttext
merge sort

let arr1 = [1, 5, 10, 15]; let arr2 = [0, 2, 3, 7, 10]; merge(arr1, arr2); // => [0, 1, 2, 3, 5, 7, 10, 10, 15] Once you have that, you get to the "divide and conquer" bit.

The algorithm for merge sort is actually really simple.

if there is only one element in the list, it is already sorted. return that array. otherwise, divide the list recursively into two halves until it can no more be divided. merge the smaller lists into new list in sorted order.

hashtag
<----------------------(Quick Sort)---------------->

hashtag
Quick Sort

quick sort

This project contains a skeleton for you to implement Quick Sort. In the file lib/quick_sort.js, you should implement the Quick Sort. This is a description of how the Quick Sort works (and is also in the code file).

  • Clone the project from

    https://github.com/appacademy-starters/algorithms-quick-sort-starterarrow-up-right.

  • cd into the project folder

  • npm install to install dependencies in the project root directory

  • npm test to run the specs

  • You can view the test cases in /test/test.js. Your job is to write code in

    the /lib/quick_sort.js that implements the Quick Sort.

alt-text
alttext
alt-text
quick sort

it is easy to sort elements of an array relative to a particular target value an array of 0 or 1 elements is already trivially sorted Regarding that first point, for example given [7, 3, 8, 9, 2] and a target of 5, we know [3, 2] are numbers less than 5 and [7, 8, 9] are numbers greater than 5.

How does it work? In general, the strategy is to divide the input array into two subarrays: one with the smaller elements, and one with the larger elements. Then, it recursively operates on the two new subarrays. It continues this process until of dividing into smaller arrays until it reaches subarrays of length 1 or smaller. As you have seen with Merge Sort, arrays of such length are automatically sorted.

The steps, when discussed on a high level, are simple:

choose an element called "the pivot", how that's done is up to the implementation take two variables to point left and right of the list excluding pivot left points to the low index right points to the high while value at left is less than pivot move right while value at right is greater than pivot move left if both step 5 and step 6 does not match swap left and right if left ≥ right, the point where they met is new pivot repeat, recursively calling this for smaller and smaller arrays

The algorithm: divide and conquer Formally, we want to partition elements of an array relative to a pivot value. That is, we want elements less than the pivot to be separated from elements that are greater than or equal to the pivot. Our goal is to create a function with this behavior:

let arr = [7, 3, 8, 9, 2]; partition(arr, 5); // => [[3, 2], [7,8,9]] Partition Seems simple enough! Let's implement it in JavaScript:

// nothing fancy function partition(array, pivot) { let left = []; let right = [];

array.forEach(el => { if (el < pivot) { left.push(el); } else { right.push(el); } });

return [ left, right ]; }

// if you fancy function partition(array, pivot) { let left = array.filter(el => el < pivot); let right = array.filter(el => el >= pivot); return [ left, right ]; } You don't have to use an explicit partition helper function in your Quick Sort implementation; however, we will borrow heavily from this pattern

hashtag
<---------------(Binary Search)---------------->

hashtag
Binary Search

This project contains a skeleton for you to implement Binary Search. In the file lib/binary_search.js, you should implement the Binary Search and its cousin Binary Search Index.

The Binary Search algorithm can be summarized as the following:

  1. If the array is empty, then return false

  2. Check the value in the middle of the array against the target value

  3. If the value is equal to the target value, then return true

  4. If the value is less than the target value, then return the binary search on

    the left half of the array for the target

  5. If the value is greater than the target value, then return the binary search

    on the right half of the array for the target

This is a description of how the Binary Search works (and is also in the code file).

Then you need to adapt that to return the index of the found item rather than a Boolean value. The pseudocode is also in the code file.

  • Clone the project from

    https://github.com/appacademy-starters/algorithms-binary-search-starterarrow-up-right.

  • cd into the project folder

  • npm install to install dependencies in the project root directory

  • npm test to run the specs

  • You can view the test cases in /test/test.js. Your job is to write code in

    the /lib/binary_search.js that implements the Binary Search and Binary

    Search Index.

]

alt-text
hashtag
Advantages arrow-up-rightof Insertion Sort

1. Simple implementation.

2. Much More Efficient for small data sets, much like other quadratic sorting algorithms like bubble sortarrow-up-right and selection sortarrow-up-right.

3. Adaptive that is efficient for the type of data sets that are already substantially sorted.

4. Stable Sorting Algorithm

5. In-place sorting means O(1) space required.

hashtag
Define Insertion Sort Function

Now, let’s define a new function named insertion-sort which accepts one parameter which is list we pass as n argument to this function.

So what we are going to do is to use two for loops, one starting from index 1 and another loop inside the first loop from the previous element of the list up to index 0.

Then we compare the outer loop index value with the inner loop index value for each iteration and then swap the small one with the outer index element.

Complexity

Insertion sort has a worst-case and average complexity of О(n2), where n is the number of items being sorted.

Most practical sorting algorithms have substantially better worst-case or average complexity, often O(n log n).

When the list is already sorted (best-case), the complexity of the insertion is only O(n).

hashtag
Define Main Condition

Now, let’s create a main condition where we need to call the above function and pass the list which needs to be sorted.

So let’s manually defined the list which we want to pass as an argument to the function.

Source Code

Output

Insertion Sort implementation example in Python Output
def selectionSort(List):
    for i in range(len(List) - 1):
        minimum = i
        for j in range( i + 1, len(List)):
            if(List[j] < List[minimum]):
                minimum = j
        if(minimum != i):
            List[i], List[minimum] = List[minimum], List[i]
    return List
Best O(n^2); Average O(n^2); Worst O(n^2)
if __name__ == '__main__':
    List = [3, 4, 2, 6, 5, 7, 1, 9]
    print('Sorted List:',selectionSort(List))

def selectionSort_Ascending(List):
    for i in range(len(List) - 1):
        minimum = i
        for j in range( i + 1, len(List)):
            if(List[j] < List[minimum]):
                minimum = j
        if(minimum != i):
            List[i], List[minimum] = List[minimum], List[i]
    return List

def selectionSort_Descending(List):
    for i in range(len(List) - 1):
        minimum = i
        for j in range(len(List)-1,i,-1):
            if(List[j] > List[minimum]):
                minimum = j
        if(minimum != i):
            List[i], List[minimum] = List[minimum], List[i]
    return List

if __name__ == '__main__':
    List1 = [3, 4, 2, 6, 5, 7, 1, 9]
    print('Sorted List Ascending:',selectionSort_Ascending(List1))
    print('Sorted List Descending:',selectionSort_Descending(List1))
Bubble Sort: (array)
  n := length(array)
  repeat
  swapped = false
  for i := 1 to n - 1 inclusive do

      /* if this pair is out of order */
      if array[i - 1] > array[i] then

        /* swap them and remember something changed */
        swap(array, i - 1, i)
        swapped := true

      end if
    end for
  until not swapped
  for j = 0 to loop-1 do:

     /* compare the adjacent elements */   
     if list[j] > list[j+1] then
        /* swap them */
        swap( list[j], list[j+1] )         
        swapped = true
     end if

  end for

  /*if no number was swapped that means 
  array is sorted now, break the loop.*/

  if(not swapped) then
     break
  end if
function swap(array, idx1, idx2) {
  let temp = array[idx1];
  array[idx1] = array[idx2];
  array[idx2] = temp;
}

function bubbleSort(array) {
  let swapped = true;

  while (swapped) {
    swapped = false;

    for (let i = 0; i < array.length - 1; i++) {
      if (array[i] > array[i + 1]) {
        swap(array, i, i + 1);

        swapped = true;
      }
    }
  }

  return array;
}

let array1 = [2, -1, 4, 3, 7, 3];
bubbleSort(array1);
console.log(" bubbleSort(array): ", bubbleSort(array1));
module.exports = { bubbleSort: bubbleSort, swap: swap };
procedure selection sort(list)
   list  : array of items
   n     : size of list

   for i = 1 to n - 1
   /* set current element as minimum*/
      min = i

      /* check the element to be minimum */

      for j = i+1 to n
         if list[j] < list[min] then
            min = j;
         end if
      end for

      /* swap the minimum element with the current element*/
      if indexMin != i  then
         swap list[min] and list[i]
      end if
   end for
end procedure
function swap(arr, index1, index2) {
  let temp = arr[index1];
  arr[index1] = arr[index2];
  arr[index2] = temp;
}

function selectionSort(list) {
  let length = list.length;
  for (let i = 0; i < length - 1; i++) {
    let minPos = i;

    for (let j = i + 1; j < length; j++) {
      if (list[j] < list[minPos]) {
        minPos = j;
      }
    }

    if (minPos !== i) {
      swap(list, minPos, i);
    }
  }
}
module.exports = {
  selectionSort,
  swap,
};
procedure insertionSort( A : array of items )
   int holePosition
   int valueToInsert

   for i = 1 to length(A) inclusive do:

      /* select value to be inserted */
      valueToInsert = A[i]
      holePosition = i

      /*locate hole position for the element to be inserted */

      while holePosition > 0 and A[holePosition-1] > valueToInsert do:
         A[holePosition] = A[holePosition-1]
         holePosition = holePosition -1
      end while

      /* insert the number at hole position */
      A[holePosition] = valueToInsert

   end for

end procedure
function insertionSort(list) {
  for (let i = 1; i < list.length; i++) {
    let val = list[i];
    let pos = i;
    // console.trace("1");
    while (pos > 0 && list[pos - 1] > val) {
      // console.trace("2");
      list[pos] = list[pos - 1];
      pos -= 1;
    }
    list[pos] = val;
  }
}
let array = [2, -1, 4, 3, 7, 3];
insertionSort(array);
module.exports = {
  insertionSort,
};
procedure mergesort( a as array )
   if ( n == 1 ) return a

   /* Split the array into two */
   var l1 as array = a[0] ... a[n/2]
   var l2 as array = a[n/2+1] ... a[n]

   l1 = mergesort( l1 )
   l2 = mergesort( l2 )

   return merge( l1, l2 )
end procedure

procedure merge( a as array, b as array )
   var result as array
   while ( a and b have elements )
      if ( a[0] > b[0] )
         add b[0] to the end of result
         remove b[0] from b
      else
         add a[0] to the end of result
         remove a[0] from a
      end if
   end while

   while ( a has elements )
      add a[0] to the end of result
      remove a[0] from a
   end while

   while ( b has elements )
      add b[0] to the end of result
      remove b[0] from b
   end while

   return result
end procedure
// Implement Merge Sort

function merge(array1, array2) {
  let merged = [];

  while (array1.length || array2.length) {
    let el1 = array1.length ? array1[0] : Infinity;
    let el2 = array2.length ? array2[0] : Infinity;

    el1 < el2 ? merged.push(array1.shift()) : merged.push(array2.shift());
  }

  return merged;
}

merge([1, 5, 10, 15], [0, 2, 3, 7, 10]);

function mergeSort(array) {
  if (array.length <= 1) return array;

  let midIdx = Math.floor(array.length / 2);
  let left = array.slice(0, midIdx);
  let right = array.slice(midIdx);

  let sortedLeft = mergeSort(left);
  let sortedRight = mergeSort(right);

  return merge(sortedLeft, sortedRight);
}

module.exports = {
  merge,
  mergeSort,
};
procedure quick sort (array)
  if the length of the array is 0 or 1, return the array

  set the pivot to the first element of the array
  remove the first element of the array

  put all values less than the pivot value into an array called left
  put all values greater than the pivot value into an array called right

  call quick sort on left and assign the return value to leftSorted
  call quick sort on right and assign the return value to rightSorted

  return the concatenation of leftSorted, the pivot value, and rightSorted
end procedure quick sort
// Implement Quick Sort

function quickSort(array) {
  if (array.length <= 1) return array;

  let pivot = array.shift();

  let left = array.filter((el) => el < pivot);
  let right = array.filter((el) => el >= pivot);

  let sortedLeft = quickSort(left);
  let sortedRight = quickSort(right);

  return [...sortedLeft, pivot, ...sortedRight];
}

module.exports = {
  quickSort,
};

/*
bryan@LAPTOP-F699FFV1:/mnt/c/Users/15512/Google Drive/a-A-September/weeks/week7-outer/week-7/projects/D2/first-attempt/algorithms-sorting-starter/algorithms-sorting-starter-master/problems$ npm test

> bubble_sort_project_solution@1.0.0 test /mnt/c/Users/15512/Google Drive/a-A-September/weeks/week7-outer/week-7/projects/D2/first-attempt/algorithms-sorting-starter/algorithms-sorting-starter-master
> mocha

 bubbleSort(array):  [ -1, 2, 3, 3, 4, 7 ]


  bubbleSort()
    ✓ should sort the elements of the array in increasing order, in-place

  swap()
    ✓ should swap the elements at the given indices, mutating the original array

  selectionSort()
    ✓ should sort the elements of the array in increasing order, in-place

  insertionSort()
    ✓ should sort the elements of the array in increasing order, in-place

  merge()
    ✓ should return a single array containing elements of the original sorted arrays, in order

  mergeSort()
    when the input array contains 0 or 1 elements
      ✓ should return the array
    when the input array contains more than 1 element
      ✓ should return an array containing the elements in increasing order

  quickSort()
    when the input array contains 0 or 1 elements
      1) should return the array
    when the input array contains more than 1 element
      2) should return an array containing the elements in increasing order


  7 passing (210ms)
  2 failing

  1) quickSort()
       when the input array contains 0 or 1 elements
         should return the array:
     AssertionError: expected undefined to deeply equal []
      at Context.<anonymous> (test/05-quick-sort-spec.js:9:32)
      at processImmediate (internal/timers.js:456:21)

  2) quickSort()
       when the input array contains more than 1 element
         should return an array containing the elements in increasing order:
     AssertionError: expected undefined to deeply equal [ -1, 2, 3, 3, 4, 7 ]
      at Context.<anonymous> (test/05-quick-sort-spec.js:16:49)
      at processImmediate (internal/timers.js:456:21)



npm ERR! Test failed.  See above for more details.
bryan@LAPTOP-F699FFV1:/mnt/c/Users/15512/Google Drive/a-A-September/weeks/week7-outer/week-7/projects/D2/first-attempt/algorithms-sorting-starter/algorithms-sorting-starter-master/problems$ npm test

> bubble_sort_project_solution@1.0.0 test /mnt/c/Users/15512/Google Drive/a-A-September/weeks/week7-outer/week-7/projects/D2/first-attempt/algorithms-sorting-starter/algorithms-sorting-starter-master
> mocha

 bubbleSort(array):  [ -1, 2, 3, 3, 4, 7 ]


  bubbleSort()
    ✓ should sort the elements of the array in increasing order, in-place

  swap()
    ✓ should swap the elements at the given indices, mutating the original array

  selectionSort()
    ✓ should sort the elements of the array in increasing order, in-place

  insertionSort()
    ✓ should sort the elements of the array in increasing order, in-place

  merge()
    ✓ should return a single array containing elements of the original sorted arrays, in order

  mergeSort()
    when the input array contains 0 or 1 elements
      ✓ should return the array
    when the input array contains more than 1 element
      ✓ should return an array containing the elements in increasing order

  quickSort()
    when the input array contains 0 or 1 elements
      ✓ should return the array
    when the input array contains more than 1 element
      ✓ should return an array containing the elements in increasing order


  9 passing (149ms)

*/
procedure binary search (list, target)
  parameter list: a list of sorted value
  parameter target: the value to search for

  if the list has zero length, then return false

  determine the slice point:
    if the list has an even number of elements,
      the slice point is the number of elements
      divided by two
    if the list has an odd number of elements,
      the slice point is the number of elements
      minus one divided by two

  create an list of the elements from 0 to the
    slice point, not including the slice point,
    which is known as the "left half"
  create an list of the elements from the
    slice point to the end of the list which is
    known as the "right half"

  if the target is less than the value in the
    original array at the slice point, then
    return the binary search of the "left half"
    and the target
  if the target is greater than the value in the
    original array at the slice point, then
    return the binary search of the "right half"
    and the target
  if neither of those is true, return true
end procedure binary search
procedure binary search index(list, target, low, high)
  parameter list: a list of sorted value
  parameter target: the value to search for
  parameter low: the lower index for the search
  parameter high: the upper index for the search

  if low is equal to high, then return -1 to indicate
    that the value was not found

  determine the slice point:
    if the list has an even number of elements,
      the slice point is the number of elements
      divided by two
    if the list has an odd number of elements,
      the slice point is the number of elements
      minus one divided by two

  if the target is less than the value in the
    original array at the slice point, then
    return the binary search of the array,
    the target, low, and the slice point
  if the target is greater than the value in the
    original array at the slice point, then return
    the binary search of the array, the target,
    the slice point plus one, and high
  if neither of those is true, return true
end procedure binary search index
def insertionSort(List):
    for i in range(1, len(List)):
        currentNumber = List[i]
        for j in range(i - 1, -1, -1):
            if List[j] > currentNumber :
                List[j], List[j + 1] = List[j + 1], List[j]
            else:
                List[j + 1] = currentNumber
                break

    return List
Best O(n); Average O(n^2); Worst O(n^2)
if __name__ == '__main__':
    List = [3, 4, 2, 6, 5, 7, 1, 9]
    print('Sorted List : ',insertionSort(List))
def insertionSort(List):
    for i in range(1, len(List)):
        currentNumber = List[i]
        for j in range(i - 1, -1, -1):
            if List[j] > currentNumber :
                List[j], List[j + 1] = List[j + 1], List[j]
            else:
                List[j + 1] = currentNumber
                break

    return List

if __name__ == '__main__':
    List = [3, 4, 2, 6, 5, 7, 1, 9]
    print('Sorted List : ',insertionSort(List))
Screen Shot 2018-12-22 at 17.50.35.png
Screen Shot 2018-12-22 at 17.52.12.png

Quick Sort

hashtag
What is Quick Sort in Python?

Quicksort (sometimes called partition-exchange sortarrow-up-right) is an efficient sorting algorithm, serving as a systematic method for placing the elements of a random access file or an array in order.

Quicksort works by selecting an element called a pivot and splitting the array around that pivot in Python.

We split array such that all the elements in, say, the left sub-array are less than the pivot and all the elements in the right sub-array are greater than the pivot.

The splitting continues until the array can no longer be broken into pieces. That’s it. Quicksort is done.

hashtag
Advantages of Quick Sort in Python

1. Easy implementation.

2. High performance.

3. Cache Performance is higher than other .

4. No extra memory.

hashtag
Define Quick Sorting Function

Now, let’s define a new function named quick-sorting which accepts three parameters which is a list, starting index and the ending index we pass as an argument to this function.

So this function is to sort an array or list using a quick sorting algorithm in Python.

In this tutorial, we are going to provide two solutions, one is normal and other is more efficient than first.

Solution 1

In the first solution, we are going to first find the pivot by using a partition function and then we split the array on that pivot basis.

In this solution, we are recursively calling the quicksort function which leads to more complexity in Python.

Solution 2

This second solution is much more efficient than the first one.

Complexity

The overall time complexity of OuickSort is O(nLogn).

The space complexity of Quick Sort is O(log n).

Define Main Condition

Now, let’s create a main condition where we need to call the above functions and pass the list which needs to be sorted.

So let’s manually defined the list which we want to pass as an argument to the function.

So, one more thing we want to do is to calculate the time for both solutions to check which solution works better.

Source Code

Output

sorting algorithmsarrow-up-right
Quick Sort implementation example in Python Output
def quickSort(myList, start, end):
    if start < end:
        pivot = partition(myList, start, end)
        quickSort(myList, start, pivot-1)
        quickSort(myList, pivot+1, end)
    return myList

def partition(myList, start, end):
    pivot = myList[start]
    left = start+1
    right = end
    done = False
    while not done:
        while left <= right and myList[left] <= pivot:
            left = left + 1
        while myList[right] >= pivot and right >=left:
            right = right -1
        if right < left:
            done= True
        else:
            temp=myList[left]
            myList[left]=myList[right]
            myList[right]=temp
    temp=myList[start]
    myList[start]=myList[right]
    myList[right]=temp
    return right
def quicksortBetter(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quicksortBetter(left) + middle + quicksortBetter(right)
if __name__ == '__main__':
    List = [3, 4, 2, 6, 5, 7, 1, 9]
    start = time.time()
    print('Sorted List:',quickSort(List, 0, len(List) - 1))
    stop = time.time()
    print('Time Required:', (stop - start))
    start = time.time()
    print('Sorted List:', quicksortBetter(List))
    stop = time.time()
    print('Time Required:', (stop - start))

import time

def quickSort(myList, start, end):
    if start < end:
        pivot = partition(myList, start, end)
        quickSort(myList, start, pivot-1)
        quickSort(myList, pivot+1, end)
    return myList

def partition(myList, start, end):
    pivot = myList[start]
    left = start+1
    right = end
    done = False
    while not done:
        while left <= right and myList[left] <= pivot:
            left = left + 1
        while myList[right] >= pivot and right >=left:
            right = right -1
        if right < left:
            done= True
        else:
            temp=myList[left]
            myList[left]=myList[right]
            myList[right]=temp
    temp=myList[start]
    myList[start]=myList[right]
    myList[right]=temp
    return right

# A more efficient solution
def quicksortBetter(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quicksortBetter(left) + middle + quicksortBetter(right)

if __name__ == '__main__':
    List = [3, 4, 2, 6, 5, 7, 1, 9]
    start = time.time()
    print('Sorted List:',quickSort(List, 0, len(List) - 1))
    stop = time.time()
    print('Time Required:', (stop - start))
    start = time.time()
    print('Sorted List:', quicksortBetter(List))
    stop = time.time()
    print('Time Required:', (stop - start))

Recursive Sorting

import random

# TO-DO: complete the helper function below to merge 2 sorted arrays
def merge( arrA, arrB ):
    elements = len( arrA ) + len( arrB )
    merged_arr = [0] * elements

    # Iterate through marged_arr to insert smallest item in arrA and arrB until merged_arr is full
    for i in range(0, len(merged_arr)):
        # If arrA is empty, use arrB to fill
        if len(arrA) == 0:
            merged_arr[i] = min(arrB)
            arrB.remove(min(arrB))
        
        # If arrB is empty, use arrA to fill
        elif len(arrB) == 0:
            merged_arr[i] = min(arrA)
            arrA.remove(min(arrA))

        # If the smallest item in arrA is smaller than the smallest item in arrB, insert arrA's smallest item and then remove from arrA
        elif min(arrA) < min(arrB):
            merged_arr[i] = min(arrA)
            arrA.remove(min(arrA))

        # If the smallest item in arrB is smaller than the smallest item in arrA, insert arrB's smallest item and then remove from arrB
        elif min(arrA) >= min(arrB):
            merged_arr[i] = min(arrB)
            arrB.remove(min(arrB))
    
    return merged_arr

# TO-DO: implement the Merge Sort function below USING RECURSION
def merge_sort( arr ):
    if len(arr) == 0 or len(arr) == 1:
        return arr
    
    mid_point = round(len(arr)/2)
    arrA = merge_sort(arr[:mid_point])
    arrB = merge_sort(arr[mid_point:])

    return merge(arrA,arrB)

# STRETCH: implement an in-place merge sort algorithm
def merge_in_place(arr, start, mid, end):
    # Updating the pointers
    # Getting past the halfway 
    # Assign a variable to track the index of the other starting point 
    # Decrement

    return arr

def merge_sort_in_place(arr, l, r): 
    # TO-DO

    return arr


# STRETCH: implement the Timsort function below
# hint: check out https://github.com/python/cpython/blob/master/Objects/listsort.txt

def insertion_sort(arr):
    for i in range(1, len(arr)):
        # Starts looping from first unsorted element
        unsorted = arr[i]
        # Starts comparing against last sorted element
        last_sorted_index = i-1

        # While unsorted is less than the last sorted...
        while last_sorted_index >= 0 and unsorted < arr[last_sorted_index]:
            # Shifts last sorted to the right by one
            arr[last_sorted_index + 1] = arr[last_sorted_index]
            # Decrements down the last sorted index, until no longer larger than or hits zero
            last_sorted_index -= 1

        # Places unsorted element into correct spot
        arr[last_sorted_index + 1] = unsorted
    return arr


def timsort( arr ):
    # Divide arr into runs of 32 (or as chosen)
    # If arr size is smaller than run, it will just use insertion sort
    minirun = 32
    for i in range(0, len(arr), minirun):
        counter = 0
        range_start = minirun * counter
        range_end = minirun * (counter+1)
        print(range_start, range_end)
        print(f"i is: {i}")
        print(insertion_sort(arr[range_start:range_end]))
        counter += 1

    # Sort runs using insertion sort
    # Merge arrays using merge sort

    
    # return insertion_sort(arr)

test_sort = random.sample(range(100), 64)
print(timsort(test_sort))

Sorting


This implementation is different than the ones in the referenced books, which are different from each other.
# insertion sort

my_book = {'title'

hashtag
JavaScript:

hashtag
Bubble Sort

hashtag
Script Name

Bubble Sort Algorithm.

hashtag
Aim

To write a program for Bubble sort.

hashtag
Purpose

To get a understanding about Bubble sort.

hashtag
Short description of package/script

  • It is a python program of Bubble sort Algorithm.

  • It is written in a way that it takes user input.

hashtag
Workflow of the Project

  • First a function is written to perform Bubble sort.

  • Then outside the function user input is taken.

hashtag
Detailed explanation of script, if needed

Start with the first element, compare the current element with the next element of the array. If the current element is greater than the next element of the array, swap both of them. If the current element is less than the next element, move to the next element. Keep on comparing the current element with all the elements in the array. The largest element of the array comes to its original position after 1st iteration. Repeat all the steps till the array is sorted.

hashtag
Example

hashtag
Setup instructions

Just clone the repository .

hashtag
Output

Insertion Sort

hashtag
Divide and Conquer

circle-info

When would we use recursive solutions? Tree traversals and quick sort are instances where recursion creates an elegant solution that wouldn't be as possible iteratively.

Divide and conquer is when we take a problem, split it into the same type of sub-problem, and run the algorithm on those sub-problems.

If we have an algorithm that runs on a list, we could break the list into smaller lists and run the algorithm on those smaller lists. We will divide the data into more manageable pieces.

We break down our algorithm problems into base cases -- the smallest possible size of data we can run our algorithm upon to determine the basic way our algorithm should work.

These solutions can give us better time complexity solutions; however, they wouldn't work if a portion of the algorithm's data is dependent upon the rest. If we broke the list into two halves, and one half is required to work on the other half, we could not use recursion.

Recursion requires independent sub-data.

Let's apply recursion to breaking down what a list is. The sum of a list is equal to the first element plus the rest of the list. We could write that like in this add_list function found in :

This should print 10, or the sum of the items in our list.

On each pass, the add_list function is taking the first item and adding the sum of the rest of the list, found by calling add_list on the remainder of the list. This would loop through the rest of the list in this manner, only adding together the elements once the final element was reached.

Finding a sum like this is not the most time efficient -- it would be better to do iteratively. But this allows us to understand how recursion works.

Often, iterative solutions are easier to read and more performant.

If we add a print statement into the add_list function:

The terminal would print:

Add 1 to the sum of [2, 3, 4] Add 2 to the sum of [3, 4] Add 3 to the sum of [4] Add 4 to the sum of [] 10

This helps us understand what is happening at each recursive step.

Our base case is an empty list or 0, which is what we handle at the beginning of our function with returning 0 if the list is empty. By filling that in, it gives us our first return, so that each previous add_list call can be resolved based on the sum of the next.

When we use recursion, it uses a lot of memory, so each recursive calls allocates an amount of memory. We have a pre-set recursion limit in case we write an infinitely recursive algorithm to prevent our computer needing to reboot to end the algorithm.

With Big O, we're interested in the number of times we have to run an operation. add_list just runs basic addition, which is a single operation, and it is being called one time for every element in the list, so this is O(n).

hashtag
Quick Sort

Quick sort is a great example use case of a recursive appropriate solution.

We need to include a base case and then call itself.

Quick sort sorts a list using partitioning. The partitioning process involves splitting up data around the pivot.

If our list is [5, 3, 9, 4, 8, 1, 7].

We'll choose a pivot point to split the list. Let's say we choose 5 as the pivot. One list will contain all the numbers less than 5, and the other will contain all the numbers greater than or equal to 5. This results in two lists like so:

[3, 4, 1] 5 [9, 8, 7]

5 is already sorted into the correct place that it needs to be. All the numbers to the right and left of it are in the area they need to, just not yet sorted.

This process is partitioning.

Our next step is to repeat this process until we hit our base case, which is an empty list or a list with just one element. When everything is down to one element lists, then we know they are properly sorted.

3 and 9 are our next pivots: [1] 3 [4] 5 [8, 7] 9 Next, 8 is our pivot: [1] 3 [4] 5 [7] 8 [] 9 1 3 4 5 7 8 9

The number of sorted items doubles with each pass through this algorithm, and we have to make one complete pass through the data on each loop. That means each pass is O(n), and we have to make log n passes.

It takes O(log n) steps to pass through, with each pass taking O(n), so the average case is O(n log n), the fastest search we can aim for.

What would be a bad case for quick sort?

[1, 2, 3, 4, 5, 6, 7]

If we look at the order of this on each loop:

[] 1 [2, 3, 4, 5, 6, 7] 1 [] 2 [3, 4, 5, 6, 7] 1 2 [] 3 [4, 5, 6, 7] 1 2 3 [] 4 [5, 6, 7] 1 2 3 4 [] 5 [6, 7] 1 2 3 4 5 [] 6 [7] 1 2 3 4 5 6 7

This took a full 7 passes, for 7 elements, because there was only one sorted item being added with each pass.

Already sorted lists are the worst case scenario which results in an order O(n^2).

Quick sort shines when the first pivot chosen is roughly the median value of the list. Now, since we can't always choose the median value with the traditional quick sort.

We could use quick select to find the median at each step -- but this slows down our algorithm to O(n) run time on average.

If we choose a random pivot point, we generally do not pick the worst case pivot with each pass. Randomly selecting a pivot point results in the most time efficient average.

hashtag
Implementing Quick Sort

If we were to write out our quick sort algorithm in a basic way, it would look something like this:

Let's define our partition function next:

Let's test out a bunch of possible cases like so:

We already know off the tops of our heads that we have not setup our algorithm to handle edge cases like an input that is not a list, or is a list full of strings, etc.

Our terminal returns back:

So we can see that it handles all of our tests well.

It's important to analyze what you know about your incoming data before choosing a type of algorithm. If you know that your list is almost completely sorted, bubble sort would handle that the quickest. If the list is completely garbled, quick sort would be best.

Even when we aren't handling sort, we need to customize our algorithmic choices to the data anticipated, especially when dealing with large sets of data where time performance can have a huge impact.

hashtag
In Place Sorting

The quick sort function we wrote is not an in-place solution. When we sort that list, we're actually returning an entirely new list. It's not returning the same list.

This isn't time or space efficient because it takes time and data to copy lists over to newly allocated spots in memory. It would be more efficient to move items around within the original given list.

This is in-place sorting -- using the original list to sort items within it and returning that same original list, but now sorted. We mutate the original list rather than making new lists.

To do in-place sorting, we need to be able to pass into the function the bounds of the current part of the list that we're working on, to ensure that we are only working on certain segments of the list at a time.

We can give it a low index, and a high index, to indicate the start and stop points of the section of the list to work on.

As we keep going, the low and high indices will change. Our base case should now change to where if the low and high are the same, then our list is sorted.

Let's try it:

We're iterating through the list and checking if the item at list[i] is less than the item at list[pivot_index]. If it is, then we need to swap these items.

That has to happen in two steps. First we swap i with an item one beyond the pivot index. Then we swap the pivot with the item after the pivot.

Then we update the pivot index to search for the next item to sort in the array.

In order to call this function without passing in three parameters, we can write a short helper function:

Now we can run this function and it sorts our lists without allocating extra memory.

Let's add some print statements just to see exactly what is happening at each step on one of the sorts:

This helps us visualize why we go through each swapping step and how the list is slowly being sorted, and split apart into smaller sorting lists.

"""
- start by choosing a pivot (could be first, last, middle, random etc)
- move all of the elements smaller than the pivot to LHS
- move all of the elements larger than the pivot to RHS
- invoke a recursive call to quick sort on LHS and RHS until base case 
    (a side only contains a single element)

[8, 3, 6, 4, 7, 9, 5, 2, 1]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

pivot = [8] 
[3, 6, 4, 7, 9, 5, 2, 1]
lhs = [3, 6, 4, 7, 5, 2, 1]
rhs = [9]

[lhs call]
pivot [3] 
[6, 4, 7, 5, 2, 1]
lhs = [2, 1]
rhs = [6, 4, 7, 5]

[lhs2 call]
[2] [1]
lhs = [1]
rhs = []

[rhs2 call]
pivot = [6] 
[4, 7, 5]
lhs = [4,5]
rhs = [7]





[pivot call]
[8]

[rhs call]
[9]





"""

def partition(data):
    # make a new empty list for LHS
    lhs = []
    # make a pivot
    pivot = data[0]
    # make a new empty list for RHS
    rhs = []

    # loop over the data 
    for v in data[1:]:
        # if lower than or equal to pivot
        if v <= pivot:
            # append to LHS list
            lhs.append(v)
        # otherwise
        else:
            # append to RHS list
            rhs.append(v)
    
    # return a tuple containing the LHS list, the pivot, and the RHS list
    return lhs, pivot, rhs

def quicksort(data):
    # base case
    # if the data is empty we just return the empty list
    if data == []:
        return data

    # do something with the data
    # partition the data and set it to a tuple of left right and pivot
    left, pivot, right = partition(data)

    # do a recursive call
    # return the quicksort of left + the [pivot] + quick sort of right
    return quicksort(left) + [pivot] + quicksort(right)


lst = [8, 3, 5, 6, 4, 7, 9, 5, 2, 1]


slst = quicksort(lst)
print(lst)
print('-------------------------')
print(slst)

# Divide a problem in to subproblems (of the same type)
# Solve the subproblems
# Combine the results of the subproblems 
# to get the solution to the original problem

def quick_sort(data, low, high):
    # check base case
    # if low is greater than or equal to high
    if low >= high:
        # return the data
        return data
    # otherwise
    else:
        # divide
        pivot_index = low

    # for each element in sub list
    for i in range(low, high):
        # check if data at index is less than data at pivot index
        if data[i] < data[pivot_index]:
            # double swap to move smaller elements to the correct index
            # move current element to right of pivot
            temp = data[pivot_index + 1]
            data[pivot_index + 1] = data[i]
            data[i] = temp
            # swap the pivot with the element to its right
            temp = data[pivot_index]
            data[pivot_index] = data[pivot_index + 1]
            data[pivot_index + 1] = data[i]
            data[i] = temp

    # conqure
    # quick sort the left
    data = quick_sort(data, low, pivot_index)
    # quick sort the right
    data = quick_sort(data, pivot_index + 1, high)

    # return the data
    return data


lst = [8, 5, 6, 4, 3, 7, 9, 2, 1]
print(lst)
quick_sort(lst, 0, 9)
print('--------------------------')
print(lst)
from book import Book
# Divide a problem in to subproblems (of the same type)
# Solve the subproblems
# Combine the results of the subproblems 
# to get the solution to the original problem

def quick_sort(data, low, high):
    # check base case
    # if low is greater than or equal to high
    if low >= high:
        # return the data
        return data
    # otherwise
    else:
        # divide
        pivot_index = low

    # for each element in sub list
    for i in range(low, high):
        # check if data at index is less than data at pivot index
        if data[i].genre < data[pivot_index].genre:
            # double swap to move smaller elements to the correct index
            # move current element to right of pivot
            temp = data[pivot_index + 1]
            data[pivot_index + 1] = data[i]
            data[i] = temp
            # swap the pivot with the element to its right
            temp = data[pivot_index]
            data[pivot_index] = data[pivot_index + 1]
            data[pivot_index + 1] = data[i]
            data[i] = temp

    # conqure
    # quick sort the left
    data = quick_sort(data, low, pivot_index)
    # quick sort the right
    data = quick_sort(data, pivot_index + 1, high)

    # return the data
    return data

b1 = Book('Food for thought', 'jon jones', 'food')
b2 = Book('My life in reality', 'don davis', 'life')
b3 = Book('Apples, how you like them?', 'stan simpson', 'food')
b4 = Book('Just Do It', 'shia le boeuf', 'inspirational')
b5 = Book('What is this code anyway', 'tom jones', 'programming')

books = [b1, b2, b3, b4, b5]

for b in books:
    print(b)

quick_sort(books, 0, 5)


print('----------------------------------------------------------')
for b in books:
    print(b)
# helper function conceptual partitioning
def partition(data):
    # takes in a single list and partitions it in to 3 lists left, pivot, right
    # create 2 empty lists (left, right)
    left = []
    right = []
    # create a pivot list containing the first element of the data
    pivot = data[0]

    # for each value in our data starting at index 1:
    for value in data[1:]:
        # check if value is less than or equal to the pivot
        if value <= pivot:
            # append our value to the left list
            left.append(value)
        # otherwise (the value must be greater than the pivot)
        else:
            # append our value to the right list
            right.append(value)

    # returns the tuple of (left, pivot, right)
    return left, pivot, right

# quick sort that uses the partitioned data
def quicksort(data):
    # base case if the data is an empty list return an empty list
    if data == []:
        return data

    # partition the data in to 3 variables (left, pivot, right)
    left, pivot, right = partition(data)

    # recursive call to quicksort using the left
    # recursive call to quicksort using the right
    # return the concatination quicksort of lhs + pivot + quicksort of rhs
    return quicksort(left) + [pivot] + quicksort(right)

print(quicksort([5, 9, 3, 7, 2, 8, 1, 6]))
It uses methods and functions that do iteration versus for-loops. Just remember it's still O(n^2).
"""
from collections.abc import MutableSequence
from src.typehints import T
def selection_sort_iter(seq: MutableSequence[T]) -> None:
"""Use selection sort iteratively on a list in-place."""
for i, val in enumerate(seq):
min_val = min(seq[i:])
min_val_i = seq.index(min_val, i) # First index of min_val at or after i
seq[i] = min_val
seq[min_val_i] = val
:
'
Food for thought
'
,
'
author
'
:
'
jon jones
'
,
'
genre
'
:
'
food
'
}
class Book:
def __init__(self, title, author, genre):
self.title = title
self.author = author
self.genre = genre
def __str__(self):
return f'{self.genre}: {self.title} by {self.author}'
b1 = Book('Food for thought', 'jon jones', 'food')
b2 = Book('My life in reality', 'don davis', 'life')
b3 = Book('Apples, how you like them?', 'stan simpson', 'food')
b4 = Book('Just Do It', 'shia le boeuf', 'inspirational')
b5 = Book('What is this code anyway', 'tom jones', 'programming')
books = [b1, b2, b3, b4, b5]
def in_sort(books):
# loop through len - 1 elements
for i in range(1, len(books)):
# code up some logic
# save current i to a temp var
temp = books[i]
j = i
while j > 0 and temp.title < books[j - 1].title:
# shift left until correct tile is found
books[j] = books[j - 1]
j -= 1
# insert book in correct position
books[j] = temp
return books
# for b in books:
# print(b)
# print('---------------------')
# in_sort(books)
# for b in books:
# print(b)
"""
- **Insertion Sort** is an _in-place_ algorithm, meaning that it
does not require any additional memory to perform the sort operation.
- It works by conceptually dividing the array into _sorted_ and _unsorted_ pieces.
1. Consider element at index 0 to be our _sorted_ piece. The rest of the array is our _unsorted_ piece.
2. Save the 1st element in the _unsorted_ piece in a temp variable.
3. Shift elements in the _sorted_ piece over to the right until we find where the element
from step 2 should go.
4. Insert the element from step 2 into its correct index within the _sorted_ piece.
5. Repeat steps 2-4 until all elements have been processed.
"""
def in_sort2(lst):
# loop over n - 1 elements
for i in range(1, len(lst)):
# save initial element to temp variable
temp = lst[i]
# set inner loop index to current index
j = i
# inner loop
while j > 0 and temp < lst[j - 1]:
# shift left until correct position found
lst[j] = lst[j - 1]
# decrement inner index
j -= 1
# insert temp at correct position
lst[j] = temp
# return our list
return lst
my_nums = [23, 34, 60, 1, 4, 5, 2]
my_names = ['Dave', 'Steve', 'Bob']
print(my_nums)
in_sort2(my_nums)
print(my_nums)
print(my_names)
in_sort2(my_names)
print(my_names)
this filearrow-up-right
Arraychevron-right
Binary Search Treechevron-right
Linked Listchevron-right
Extra-Arraychevron-right
Stackchevron-right
Binary Treechevron-right
Recursionchevron-right
Hash Tablechevron-right
Searchingchevron-right
Sortingchevron-right
Queue Sandboxchevron-right
Hash Tablechevron-right
Double Linked Listchevron-right
Graphschevron-right
Exoticchevron-right
Heapchevron-right
// Implement Bubble Sort

function swap(array, idx1, idx2) {
  let temp = array[idx1];
  array[idx1] = array[idx2];
  array[idx2] = temp;
}

function bubbleSort(array) {
  let swapped = true;

  while (swapped) {
    swapped = false;

    for (let i = 0; i < array.length - 1; i++) {
      if (array[i] > array[i + 1]) {
        swap(array, i, i + 1);

        swapped = true;
      }
    }
  }

  return array;
}

let array1 = [2, -1, 4, 3, 7, 3];
bubbleSort(array1);
console.log(" bubbleSort(array): ", bubbleSort(array1));
module.exports = { bubbleSort: bubbleSort, swap: swap };
// Implement Selection Sort

// Implement swap without looking at bubble sort
function swap(arr, index1, index2) {
  let temp = arr[index1];
  arr[index1] = arr[index2];
  arr[index2] = temp;
}

function selectionSort(list) {
  let length = list.length;
  for (let i = 0; i < length - 1; i++) {
    let minPos = i;

    for (let j = i + 1; j < length; j++) {
      if (list[j] < list[minPos]) {
        minPos = j;
      }
    }

    if (minPos !== i) {
      swap(list, minPos, i);
    }
  }
}
module.exports = {
  selectionSort,
  swap,
};
// Implement Insertion Sort

function insertionSort(list) {
  for (let i = 1; i < list.length; i++) {
    let val = list[i];
    let pos = i;
    // console.trace("1");
    while (pos > 0 && list[pos - 1] > val) {
      // console.trace("2");
      list[pos] = list[pos - 1];
      pos -= 1;
    }
    list[pos] = val;
  }
}
let array = [2, -1, 4, 3, 7, 3];
insertionSort(array);
module.exports = {
  insertionSort,
};
// Implement Merge Sort

function merge(array1, array2) {
  let merged = [];

  while (array1.length || array2.length) {
    let el1 = array1.length ? array1[0] : Infinity;
    let el2 = array2.length ? array2[0] : Infinity;

    el1 < el2 ? merged.push(array1.shift()) : merged.push(array2.shift());
  }

  return merged;
}

merge([1, 5, 10, 15], [0, 2, 3, 7, 10]);

function mergeSort(array) {
  if (array.length <= 1) return array;

  let midIdx = Math.floor(array.length / 2);
  let left = array.slice(0, midIdx);
  let right = array.slice(midIdx);

  let sortedLeft = mergeSort(left);
  let sortedRight = mergeSort(right);

  return merge(sortedLeft, sortedRight);
}

module.exports = {
  merge,
  mergeSort,
};
// Implement Quick Sort

function quickSort(array) {
  if (array.length <= 1) return array;

  let pivot = array.shift();

  let left = array.filter((el) => el < pivot);
  let right = array.filter((el) => el >= pivot);

  let sortedLeft = quickSort(left);
  let sortedRight = quickSort(right);

  return [...sortedLeft, pivot, ...sortedRight];
}

module.exports = {
  quickSort,
};

/*
bryan@LAPTOP-F699FFV1:/mnt/c/Users/15512/Google Drive/a-A-September/weeks/week7-outer/week-7/projects/D2/first-attempt/algorithms-sorting-starter/algorithms-sorting-starter-master/problems$ npm test

> bubble_sort_project_solution@1.0.0 test /mnt/c/Users/15512/Google Drive/a-A-September/weeks/week7-outer/week-7/projects/D2/first-attempt/algorithms-sorting-starter/algorithms-sorting-starter-master
> mocha

 bubbleSort(array):  [ -1, 2, 3, 3, 4, 7 ]


  bubbleSort()
    ✓ should sort the elements of the array in increasing order, in-place

  swap()
    ✓ should swap the elements at the given indices, mutating the original array

  selectionSort()
    ✓ should sort the elements of the array in increasing order, in-place

  insertionSort()
    ✓ should sort the elements of the array in increasing order, in-place

  merge()
    ✓ should return a single array containing elements of the original sorted arrays, in order

  mergeSort()
    when the input array contains 0 or 1 elements
      ✓ should return the array
    when the input array contains more than 1 element
      ✓ should return an array containing the elements in increasing order

  quickSort()
    when the input array contains 0 or 1 elements
      1) should return the array
    when the input array contains more than 1 element
      2) should return an array containing the elements in increasing order


  7 passing (210ms)
  2 failing

  1) quickSort()
       when the input array contains 0 or 1 elements
         should return the array:
     AssertionError: expected undefined to deeply equal []
      at Context.<anonymous> (test/05-quick-sort-spec.js:9:32)
      at processImmediate (internal/timers.js:456:21)

  2) quickSort()
       when the input array contains more than 1 element
         should return an array containing the elements in increasing order:
     AssertionError: expected undefined to deeply equal [ -1, 2, 3, 3, 4, 7 ]
      at Context.<anonymous> (test/05-quick-sort-spec.js:16:49)
      at processImmediate (internal/timers.js:456:21)



npm ERR! Test failed.  See above for more details.
bryan@LAPTOP-F699FFV1:/mnt/c/Users/15512/Google Drive/a-A-September/weeks/week7-outer/week-7/projects/D2/first-attempt/algorithms-sorting-starter/algorithms-sorting-starter-master/problems$ npm test

> bubble_sort_project_solution@1.0.0 test /mnt/c/Users/15512/Google Drive/a-A-September/weeks/week7-outer/week-7/projects/D2/first-attempt/algorithms-sorting-starter/algorithms-sorting-starter-master
> mocha

 bubbleSort(array):  [ -1, 2, 3, 3, 4, 7 ]


  bubbleSort()
    ✓ should sort the elements of the array in increasing order, in-place

  swap()
    ✓ should swap the elements at the given indices, mutating the original array

  selectionSort()
    ✓ should sort the elements of the array in increasing order, in-place

  insertionSort()
    ✓ should sort the elements of the array in increasing order, in-place

  merge()
    ✓ should return a single array containing elements of the original sorted arrays, in order

  mergeSort()
    when the input array contains 0 or 1 elements
      ✓ should return the array
    when the input array contains more than 1 element
      ✓ should return an array containing the elements in increasing order

  quickSort()
    when the input array contains 0 or 1 elements
      ✓ should return the array
    when the input array contains more than 1 element
      ✓ should return an array containing the elements in increasing order


  9 passing (149ms)

*/
def partition(A, lo, hi):
    pivot = A[lo + (hi - lo) // 2]
    i = lo - 1
    j = hi + 1

    while True:

        i += 1
        while A[i] < pivot:
            i += 1

        j -= 1
        while A[j] > pivot:
            j -= 1

        if i >= j:
            return j
        A[i], A[j] = A[j], A[i]


def quicksort(A, lo, hi):
    if lo < hi:
        p = partition(A, lo, hi)
        quicksort(A, lo, p)
        quicksort(A, p + 1, hi)
    return A


if __name__ == "__main__":
    arr = [8, 3, 5, 1, 7, 2]
    quicksort(arr, 0, len(arr) - 1)
    #  >>> [1, 2, 3, 5, 7, 8]
Consider an array a=[5,4,3,2,1]
Iteration 1:-
         |5|4|3|2|1|
          |___________5>4 therefore we swap both of them.
         |4|5|3|2|1|
            |_________5>3 therefore we swap both.
         |4|3|5|2|1|
              |_______5>2 therefore we swap.
         |4|3|2|5|1|
                |_____5>1 therefore we swap.
         |4|3|2|1|5| Now 5 is placed at its original position

Iteration 2:-
         |4|3|2|1|5|
          |__________4>3 therefore we swap both.
         |3|4|2|1|5|
            |________4>2 therefore we swap both.
         |3|2|4|1|5|
              |______4>1 therefore we swap both.
         |3|2|1|4|5|
                 |__ 4 is placed at its original position.

Iteration 3:-
         |3|2|1|4|5|
          |_________3>2 we swap.
         |2|3|1|4|5|
            |_______3>1 we swap.
         |2|1|3|4|5|- 3 is placed at original position.

Iteration 4:-
          |2|1|3|4|5|
           |_________2>1 we swap.
          |1|2|3|4|5| the array is sorted.
#Link to problem:- 
#Bubble sort is a sorting algorithm. Sorting algorithms are used to arrange the array in particular order.In,Bubble sort larger elements are pushed at the end of array in each iteration.It works by repeatedly swapping the adjacent elements if they are in wrong order.

def bubbleSort(a): 
    n = len(a) 
    # Traverse through all array elements 

    for i in range(n-1): 
        # Last i elements are already in place 
        for j in range(0, n-i-1): 

            # traverse the array from 0 to n-i-1 
            # Swap if the element found is greater 
            # than the next element 
            if arr[j] > arr[j + 1] : 
                arr[j], arr[j + 1] = arr[j + 1], arr[j] 

arr = []
n=int(input("Enter size of array: "))
for i in range(n):
    e=int(input())
    arr.append(e)
bubbleSort(arr)
print ("Sorted array is:")
for i in range(len(arr)):
     print(arr[i])
     
#Time complexity - O(n^2)
#Space complexity - O(1)
# Insertion Sort

## Aim

The main aim of the script is to sort numbers in list using insertion sort.

## Purpose

The main purpose is to sort list of any numbers in O(n) or O(n^2) time complexity.

## Short description of package/script

Takes in an array. <br>
Sorts the array and prints sorted array along with the number of swaps and comparisions made.
Insertion sort is a simple sorting algorithm that works similar to the way you sort playing cards in your hands. The array is virtually split into a sorted and an unsorted part. Values from the unsorted part are picked and placed at the correct position in the sorted part.

## Detailed explanation of script, if needed

To sort an array of size n in ascending order: <br>
1: Iterate from a[1] to a[n] over the array. <br>
2: Compare the current element (val) to its predecessor. <br>
3: If the val is smaller than its predecessor, compare it to the elements before. Move the greater elements one position up to make space for the swapped element. <br>

## Setup instructions

Download code and run it in any python editor. Latest version is always better.

## Compilation Steps

1.Edit array a and enter your array/list you want to sort. 2. Run the code

## Sample Test Cases

### Test case 1:

input:<br>
a = [34,5,77,33] <br>

output :<br>

5, 33, 34, 77 along with <br>
no. of swaps = 3 <br>
no. of comparisons=5<br>

### Test case 2

input<br>
a=[90,8,11,3,2000,700,478] <br>

Output:<br>

No. of swaps= 8 <br>
No. of comparisions=12 <br>
Sorted Array is: <br>
3 8 11 90 478 700 2000<br>

### Test case 3

input<br>
a=[0,33,7000,344,-88,2000]<br>

output:<br>

No. of swaps= 6<br>
No. of comparisions=10<br>
Sorted Array is:<br>
-88 0 33 344 2000 7000<br>

## Output

<img width = 221 height = 27 src="../Insertion Sort/Images/input.png">
<img width = 385 height = 188 src="../Insertion Sort/Images/sort_output1.png">



def add_list(l):
    # The sum of an empty list is 0
    if l == []:
        return 0

    return l[0] + add_list(l[1:])


l = [1,2,3,4]

print(add_list(l)) # Should print 10
    print(f'Add {l[0]} to the sum of {l[1:]}')
    return l[0] + add_list(l[1:])
def quicksort(list):
    # One of our base cases is an empty list or list with one element
    if len(list) == 0 or len(list) == 1:
        return list

    # If we have a left list, a pivot point and a right list...
    left, pivot, right = partition(list)

    # Our sorted list looks like left + pivot + right, but sorted.
    # Pivot has to be in brackets to be a list, so python can concatenate all the elements to a single list
    return quicksort(left) + [pivot] + quicksort(right)
def partition(list):
    left = []
    pivot = list[0] # Or make random, as a stretch
    right = []

    for v in list[1:]:
        if v < pivot:
            left.append(v)
        else:
            right.append(v)

    return left, pivot, right
print(quicksort([]))
print(quicksort([1]))
print(quicksort([1,2]))
print(quicksort([2,1]))
print(quicksort([2,2]))
print(quicksort([5,3,9,4,8,1,7]))
print(quicksort([1,2,3,4,5,6,7]))
print(quicksort([9,8,7,6,5,4,3,2,1]))
[]
[1]
[1, 2]
[1, 2]
[2, 2]
[1, 3, 4, 5, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
def quicksort2(l, low, high):
    if len(l) == 0 or len(l) == 1:
        return l

    if low >= high:
        return l

    pivot_index = low

    # Partitioning
    for i in range(low, high):

        if l[i] < l[pivot_index]:
            # If i is less than pivot, we need to swap it with the item after the pivot
            l[i], l[pivot_index + 1] = l[pivot_index + 1], l[i]

            # Then we'll swap the pivot with the item after the pivot
            l[pivot_index], l[pivot_index + 1] = l[pivot_index + 1], l[pivot_index]

            # Update the pivot index:
            pivot_index += 1

    # Sort from low to the pivot index
    quicksort2(l, low, pivot_index)
    # Sort from the pivot index to high
    quicksort2(l, pivot_index + 1, high)
def in_place_quicksort(l):
    return quicksort2(l, 0, len(l))

print(in_place_quicksort([]))
print(in_place_quicksort([1]))
print(in_place_quicksort([1,2]))
print(in_place_quicksort([2,1]))
print(in_place_quicksort([2,2]))
print(in_place_quicksort([5,3,9,4,8,1,7]))
print(in_place_quicksort([1,2,3,4,5,6,7]))
print(in_place_quicksort([9,8,7,6,5,4,3,2,1]))
Our starting list is [5,3,9,4,8]. 

Checking against 5. Current list is [5, 3, 9, 4]. 

Checking against 3. Current list is [5, 3, 9, 4]. 

3 is less than 5, so we need to swap l[i] (3) with l[pivot_index + 1] (3).
Next, we will swap 5 with 3 and increase the pivot index from 0 to 1.
Now the current list is [3, 5, 9, 4] 

Checking against 9. Current list is [3, 5, 9, 4]. 

Checking against 4. Current list is [3, 5, 9, 4]. 

4 is less than 5, so we need to swap l[i] (4) with l[pivot_index + 1] (9).
Next, we will swap 5 with 4 and increase the pivot index from 1 to 2.
Now the current list is [3, 4, 5, 9] 


Splitting list to check quicksort([3, 4, 5, 9], 0, 2) and quicksort([3, 4, 5, 9], 3, 4). 


Checking against 3. Current list is [3, 4, 5, 9]. 

Checking against 4. Current list is [3, 4, 5, 9]. 



Splitting list to check quicksort([3, 4, 5, 9], 0, 0) and quicksort([3, 4, 5, 9], 1, 2). 

Checking against 4. Current list is [3, 4, 5, 9]. 



Splitting list to check quicksort([3, 4, 5, 9], 1, 1) and quicksort([3, 4, 5, 9], 2, 2). 

Checking against 9. Current list is [3, 4, 5, 9]. 



Splitting list to check quicksort([3, 4, 5, 9], 3, 3) and quicksort([3, 4, 5, 9], 4, 4). 

Our final sorted list is [3, 4, 5, 9]