Skip to content

Vipinkthomas/DSAL

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 

Repository files navigation

DSAL

Data Structures and Algorithms - Python

Data Structure Complexity

Data Structure Average Time Complexity Worst Time Complexity Space Complexity Desc
nth element acess Search Insertion Deletion nth element acess Search Insertion Deletion Intrinsic Auxilary
Arrays O(1) O(n) O(n) O(n) O(1) O(n) O(n) O(n) O(n) O(1) Intrinsic space complexity-> storage for elements, auxilary -> space need to run operations like insert, delete and search (recursive/iterative)
Stacks O(n) O(n) O(1) O(1) O(n) O(n) O(1) O(1) O(n) O(1)
Queues O(n) O(n) O(1) O(1) O(n) O(n) O(1) O(1) O(n) O(1)
Binary Tree O(n) O(n) O(n) O(n) O(n) O(n) O(n) O(n) O(n) O(1)-iterative or O(n)-recursive
Binary Search Tree (BST) O(logn) O(logn) O(logn) O(logn) O(n) O(n) O(n) O(n) O(n) O(1)-iterative or O(n)-recursive
Balanced BST O(logn) O(logn) O(logn) O(logn) O(logn) O(logn) O(logn) O(logn) O(n) O(1)-iterative or O(logn)-recursive
Hash Table N/A O(1) O(1) O(1) N/A O(n) O(n) O(n) bucket+elements O(m+n)-> O(n) O(1)-iterative to maintain efficiency load factor(a=n/m) sould be less than 0.7, in practice n/m is usually kept as 1. recursive data structure to store elements is uncommon

Sorting Algo

Sorting Algorithm Time Complexity Space Complexity Stable Sorting Class Remarks
Best Case Average Case Worst Case Intrinsic Auxilary
Bubble Sort O(n) O(n^2) O(n^2) O(n) O(1) Yes Comparison Not preferred
Insertion Sort O(n) O(n^2) O(n^2) O(n) O(1) Yes Comparison stable sort: it preserve relative order of equal elements. efficient for small or nearly ordered lists. works as part of Timesort : Merge sort and insertion sort. In best case, every insert takes constant time
Selection Sort O(n^2) O(n^2) O(n^2) O(n) O(1) No Comparison it even takes ~ n^2 times to processe sorted array.
Merge Sort O(nlogn) O(nlogn) O(nlogn) O(n) O(n) Yes Comparison stable sort. part of timesort
Quick Sort O(nlogn) O(nlogn) O(nlogn) O(n) O(n) Yes Comparison stable sort: it preserve relative order of equal elements. efficient for small or nearly ordered lists. works as part of Timesort : Merge sort and insertion sort. In best case, every insert takes constant time

bubble sort

# bubble sort
def BubbleSort(arr):
    times_ran=0
    for i in range(len(arr)-1,0,-1):
        swapped=False
        for j in range(0,i):
            if arr[j]>arr[j+1]:
                temp=arr[j]
                arr[j]=arr[j+1]
                arr[j+1]=temp
                swapped=True
            times_ran+=1
            print(j,arr)
        if not swapped:
            break
    return arr,times_ran

BubbleSort([1,2,3,4,5,6])

Insertion Sort

# Insertion sort
def InsertionSort(arr):
    times_ran=0
    for i in range(1,len(arr)):
        key = arr[i]
        j= i-1
        times_ran+=1
        while j>=0 and arr[j]>key:
            arr[j+1]=arr[j]
            j-=1
            times_ran+=1
        arr[j+1]=key

    return arr,times_ran

InsertionSort([1,2,3,4,5,6])

Selection Sort

# Selection Sort
def selectionSort(arr):
    times_ran=0
    for i in range(0,len(arr)):
        times_ran+=1
        min_index=i
        for j in range(i+1,len(arr)):
            times_ran+=1
            if arr[min_index]>arr[j]:
                min_index=j
        arr[i],arr[min_index]=arr[min_index],arr[i]
        print(arr)

    return arr,times_ran
selectionSort([6,5,4,3,2,1])

Merge Sort

# Merge Sort
def mergeSort(arr,times_ran=0):
    times_ran+=1
    if len(arr)<=1:
        return arr
    
    mid = len(arr)//2

    left = mergeSort(arr[:mid],times_ran)
    right = mergeSort(arr[mid:],times_ran)
    
    return merge(left,right,times_ran)

def merge(left,right,times_ran=0):
    sorted_list = []
    i=j=0

    while i<len(left) and j<len(right):
        times_ran+=1
        if left[i]<right[j]:
            sorted_list.append(left[i])
            i+=1
        else:
            sorted_list.append(right[j])
            j+=1
    sorted_list.extend(left[i:])
    sorted_list.extend(right[j:])
    print(times_ran,left,right,sorted_list)
    return sorted_list

mergeSort([6,5,4,3,2,1])       

GCD

Common Algo

def gcd(a,b):
    result = min(a,b)

    for _ in range(result,0,-1):
        if (a%_ == 0) and (b%_ == 0):
           break
        else:
            result  = result - 1
    return result

Euclidean Algo

def GCD_eculidean(a:int,b:int):
    # a or b == 0 break recursal
    if a == 0:
        return b
    elif b == 0:
        return a
    
    # break recursal when a == b, base case
    if a == b:
        return a
    
    # recursal when a>b or b>a
    elif a > b:
        return GCD_eculidean(a - b, b)
    return GCD_eculidean(a, b-a)

Birthday Paradox

Taylors Series

e^x = 1 + x + (x^2)/2! + ... e^x ~ 1 + x (when x << 1)

P(same) = 1 - P(different)

P(different) = 1 * (364/365) * (363/365) * (362/365) .. (1-((n-1)/365))

using Taylors series,

x ==   - a / 365

e^(-1/365) ~ 1 - (a/365)

P(different) can be rearranged as ,  P(different) =1*  (1- 1/365) * (1- 2/365) * (1- 3/365) .. (1- n-1/365)

P(different) ~ 1* e^(-1/365) * e^(-2/365) * e^(-3/365) .. * e^(-(n-1)/365)

                   ~ 1 * e^-(n*(n-1)/(2*365))

P(same) ~ 1 - e^-(n*(n-1)/(2*365))

e^-(n^2/(2*365)) ~ 1- P(same)

(n^2)/(2*365) ~ ln (1/ (1 - P(same))) 

approx formula for finding least number of people need to have P(same) of handshakes n ~ sqrt( (2*365) *ln(1/(1- P(same)))

#n ~ sqrt( (2*365) *ln(1/(1- P(same)))
from math import log as ln
from math import sqrt,ceil
def handshakes(prob:float):
    if prob == 1:
        return 367
    return ceil(sqrt((2*365)* ln(1/(1-prob))))

Fibanocci Series

0,1,1,2,3,5,8,13,21,34 series follows as, even, odd, odd, even, odd, odd, even, ...

Even numbers

a,b=0,2 a,b=b,a+4*b

all numbers

a,b = 0,1 a,b = b,a+b

recursive method (not good resource-wise)

def fibanocci(n:int):
    if n<=1:
        return n
    else:
        return fibanocci(n-1) + fibanocci(n-2)

for i in range(10):
    print(fibanocci(i))

image

calculating Fibonacci(5) : it computes the value of Fibonacci(2) three times, and the value of Fibonacci(1) five times. That just gets worse and worse the higher the number you want to compute.

Prime Factorisation

Inefficient method (Brute Force)

use 1..n

Pollard’s Rho Algorithm

improvised brute force algorithm use 1..sqrt(n)

Sieve O(log n) for multiple queries

About

Data Structures and Algorithms - Python

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors