Skip to content

tsnaomi/data-structures

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status

Data Structures

Algorithms

Disclaimer

Don't trust anything I say.

1My feelings toward BSTs:

image that encapsulates my feelings


Doubly-linked list

This repo implements the doubly-linked list data structure. A doubly-linked list is a sequence of nodes, wherein each node links to the previous and following node. This implementation includes the following methods:

  • insert(val) inserts val at the beginning of the list
  • append(val) appends val to the end of the list
  • shift() removes and returns the first value in the list
  • pop() removes and returns the last value in the list
  • remove(val) removes the first instance of val in the list
  • size() returns the number of the nodes in the list (i.e., the list's length)
  • contains(val) returns True if the list contains val; otherwise, False

These methods perform accordingly, where n is the number of nodes in a list:

insert append shift pop remove size contains
Average/Worst O(1) O(1) O(1) O(1) O(n) O(1) O(n)

(back to top)

Queue

A queue is a first-in-first-out or FIFO data structure, from which items are removed (dequeued) in the order that they were inserted (enqueued). This repo's implementation includes the following methods:

  • enqueue(val) appends val to the end of the queue
  • dequeue() removes and returns the first value in the queue
  • peek() returns the first value in the queue without removing it from the queue
  • size() returns the number of items in the queue
enqueue dequeue peek size
Average/Worst O(1) O(1) O(1) O(1)

(back to top)

Stack

A stack is a last-in-first-out or LIFO data structure, from which the most recently inserted items are removed first. This repo's implementation includes the following methods:

  • push(val) adds val to the top of the stack
  • pop() removes and returns the topmost (i.e., most recently added) value in the stack
  • peek() returns the first value in the stack without removing it from the stack
  • size() returns the number of items in the stack
push pop peek size
Average/Worst O(1) O(1) O(1) O(1)

(back to top)

Binary heap

Binary heap description coming soon!

This repo's implementation of a binary heap includes the following methods:

  • push(val) adds val to the heap, filling in the heap at the lowest level from left to right
  • pop() removes and returns the topmost value in the heap
  • peek() returns the topmost value in the heap without removing it from the heap
  • size() returns the number of items in the heap
push pop peek size
Average O(1) O(log n) O(1) O(1)
Worst O(log n) O(log n) O(1) O(1)

(back to top)

Hash table

Hash table description coming soon!

This repo's implementation of a hash table includes the following methods:

  • set(key, val) stores the key-val pair in the hash table (assuming that key is not already in the table)
  • get(key) retrieves the value stored at key
set get
Average O(1) O(1)
Worst O(n) O(n)

(back to top)

Graph

Graph description coming soon!

This repo uses adjacency lists to represent undirected graphs. The following methods are available in this implementation:

  • add_node(val) adds the node val to the graph
  • add_edge(val1, val2) adds an edge to the graph connecting nodes val1 and val2 (adding both nodes if need be)
  • del_node(val) deletes the node val from the graph, along with all of its edges
  • del_edge(val1, val2) deletes the edge connecting nodes val1 and val2 in the graph
  • has_node(val) returns True if the node val is in the graph; otherwise, False
  • neighbors(val) returns a list of the nodes with edges connecting to the node val
  • is_adjacent(val1, val2) returns True if there is an edge connecting nodes val1 and val2; otherwise, False

These methods perform accordingly, where n is the number of nodes in a graph and e is the number of edges:

add_node add_edge del_node del_edge has_node neighbors is_adjacent
O(1) O(1) O(e) O(n) O(n) O(1) O(n)

(back to top)

Binary search tree

Once again:

feelings

Available methods:

  • insert(val) inserts val into the tree
  • contains(val) returns True if the tree contains val; otherwise, False
  • delete(val) deletes val from the tree
  • size() returns the number of nodes in the tree
  • depth() returns the depth of the tree
  • get_balance() returns an integer i indicating the tree's balance
    • if i == 0, the tree is perfectly balanced
    • if i < 0, the tree is left-heavy
    • if i > 0, the tree is right-heavy
  • in_order() traverses and returns the tree's nodes in order
  • pre_order() traverses and returns the tree's nodes, yielding parents first
  • post_order() traverses and returns the tree's nodes, yielding children first
  • breadth_first() traverses and returns the tree's nodes in level order
insert contains delete
Average O(log n) O(log n) O(log n)
Worst O(n) O(n) O(n)

(back to top)


Insertion sort

Insertion sort constructs a sorted list one item at a time by iterating up the provided list and accruing a sorted sub-list behind it. At each position in the list, it compares the current value with the previous value. If the current value is greater, the algorithm moves on to the next iteration. Otherwise, it moves the current value to its correct position in the sub-list and shifts all rightward values in the sub-list up by one position.

The best case for insertion sort is an input that is already sorted. With a sorted list, the algorithm merely iterates across the list without shifting any items, thus taking O(n) time, where n is the number of items in the list.

The worst case is an input sorted in descending order. This forces the algorithm to shift the current value to the front of the sorted sub-list at each iteration, taking O(n2) time.

The average case also takes O(n2) time, rendering it impractical for larger lists.

Best Average Worst
O(n) O(n2) O(n2)

(back to top)

Merge sort

Merge sort is a divide-and-conquer sorting algorithm. The implementation in this repo takes a top-down approach that recursively divides the input list into halves, sorts each halve, then merges the sorted halves back together.

Merge sort always takes O(n log n) time, since the order of the input does not impact how often the algorithm invokes itself. See here for a more in-depth analysis of merge sort's performance.

Best Average Worst
O(n log n) O(n log n) O(n log n)

(back to top)

Quicksort

Quicksort is another divide-and-conquer sorting algorithm. It picks a value, called a pivot, then partitions the input list into two sub-lists: a list containing values less than (or equal) to the pivot and a list containing values greater than the pivot. It then recursively sorts each sub-list accordingly. This repo implements both the Lomuto and Hoare partitioning schemes.

The best case for quicksort is a balanced input, where each partitioning results in two approximately equally-sized sub-lists. With such an input, quicksort takes O(n log n) time.

Likewise, the average case for quicksort also takes O(n log n) time.

The worst case for quicksort is when the partitioning results in an empty sub-list and a sub-list of size n - 1, taking O(n2) time to sort. This can happen if the pivot is equal to the lowest or greatest value in the input or, in the Lomuto scheme, when all of the items are equal in value.

Best Average Worst
O(n log n) O(n log n) O(n2)

(back to top)

Radix sort

Coming (not so) soon! Until then, check out this brief YouTube video on radix sort.

(back to top)

About

Python data structures and algorithms

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages