> For the complete documentation index, see [llms.txt](https://amartyushov.gitbook.io/tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://amartyushov.gitbook.io/tech/computer-science/general-notes.md).

# Data structures

## Power of 2

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M6WITIehqU8bj9DChgX%2F-M6WIb6vGHGGCDemSiIj%2FScreen%20Shot%202020-05-04%20at%2022.06.36.png?alt=media\&token=04e03c21-437c-4912-912d-97357d7ffe6c)

## Linear data structures

* Ordered data and order matters
* Logical start and end
* Sequential order with previous + next pointers
* Representatives
  * Arrays
  * Linked Lists
  * Queues
  * Stacks

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M4TKJqJrQGUMnrIrOrj%2F-M4TQJgk1xyoLqfDnGL3%2FLinear_data_structure.jpeg?alt=media\&token=561f0222-922c-4c55-bc7c-7dba74970957)

## List

**Ordered** Can contain duplicate objects.

### Resizable array

Which is ArrayList in Java.&#x20;

* :white\_check\_mark: Access is `O(1)` (**list.get(index)**)
* If (full & appendElement) => :white\_check\_mark: double the size. It takes `O(n)` .
* :white\_check\_mark: Amortized insertion time is still `O(1)`&#x20;
  * to insert **N** elements to array with size **N** you need:
    * final capacity increase: n/2 elements to copy
    * previous capacity increase: n/4 elements to copy
    * previous capacity increase: n/8 elements to copy
    * ...
    * second capacity increase: 2 elements to copy
    * first capacity increase: 1 elements to copy
      * in total you have total number of copies $$n/2 + n/4 + n/8 + .. + 2 + 1 < N$$&#x20;
      * \=> inserting N elements takes `O(N)` => `O(1)` on average
        * even though some insertions take `O(N)` in worst case
* push - add the element ( O(1))&#x20;
* pop - take an element from the stack ( O(1))&#x20;
* peek - returns the item from the top of the stack without removing it
* peek - returns the item from the top of the stack without removing it

LIFO (Last in, first out)

## Stack

<details>

<summary>Implement Stack using LinkedList</summary>

Time: O(1)

Space: O(n)&#x20;

**Dynamic memory allocation**: The size of the stack can be increased or decreased dynamically by adding or removing nodes from the linked list, without the need to allocate a fixed amount of memory for the stack upfront (which will be the case when we implement Stack using Array).

```java
public class StackByLinkedList {
	
	private static class Node {
		int data;
		public Node next;
	}
	
	Node top;
	
	/**
	 * Initially: 1 <- 2 <- 3 (top pointer)
	 * After push: 1 <- 2 <- 3 <- new_value (top pointer)
	 */
	public Node push(int value) {
		Node temp = new Node();
		if (temp == null) {
			System.out.println("Heap is full. Inserting an element would lead to stack overflow");
		}
		
		temp.data = value;
		temp.next = top;
		top = temp;
		return temp;
	}
	
	public boolean isEmpty() {
		return top == null;
	}
	
	public int peek() {
		if (isEmpty()) {
			System.out.println("Stack is empty");
			return -1;
		} else {
			return top.data;
		}
	}
	
	public int pop() {
		if (isEmpty()) {
			System.out.println("Stack is empty");
			return -1;
		} else {
			int temp = top.data;
			top = top.next;
			return temp;
		}
	}
	
	public void display() {
		if (isEmpty()) {
			System.out.println("Stack is empty");
			return;
		}
		
		Node current = top;
		while (current != null) {
			System.out.print(current.data + " ");
			current = current.next;
		}
	}
	
	public static void main(String[] args)
	{
		StackByLinkedList theStack = new StackByLinkedList();
		theStack.push(11);
		theStack.push(22);
		theStack.push(33);
		theStack.push(44);
		
		theStack.display();
		
		System.out.printf("\nTop element is %d\n", theStack.peek());
		
		theStack.pop();
		theStack.pop();
		
		theStack.display();
		
		System.out.printf("\nTop element is %d\n", theStack.peek());
	}
}

```

</details>

## Queue

FIFO (first in first out)

* *Dequeue* - taking an element from the head
* *Enqueue* - adding element to the tail
* *Peek* - looking at head element, but not touching it

### **Deque (double-ended queue)**

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M-Bj5_YLKrWqKNepkyo%2F-M-BkACH9Ln77g_7cB1g%2Fdeque.png?alt=media\&token=9a5f176c-8823-4158-b494-892e25f662d8)

## Non-linear data structures

## Heap

[MEDIUM](https://medium.com/swlh/data-structures-heaps-b039868a521b) [HACKERRANK](https://www.youtube.com/watch?v=t0Cq6tVNRBA) [MAXHEAP](https://www.youtube.com/watch?v=WCm3TqScBM8)

* This is a complete (each level is filled up before another level is added and the levels are filled from left to right) binary tree based data structure.
* Heaps are **not** sorted. There is no particular relationship between nodes at any level
* Height of a tree with N nodes is O(logN)

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M4U2Yy3jLYggwsflJ4O%2F-M4U5GW2mXYnlRX1qjs_%2FMax_min_heap.jpeg?alt=media\&token=d3c7c3e6-3c1a-47ca-8994-f5a9be806602)

### When heap is useful

Heaps are used when the **highest or lowest order/priority element needs to be removed**. They allow quick access to this item in O(1) time. One use of a heap is to implement a priority queue.

Binary heaps are usually **implemented using arrays**, which save overhead cost of storing pointers to child nodes.

### Cons of Using Heaps <a href="#f6b1" id="f6b1"></a>

Heaps only provide easy access to the smallest/greatest item. Finding other items in the heap takes O(n) time because the heap is not ordered. We must iterate through all the nodes.

#### Indexes computation

* It’s parent is at the *floor* (i-1)/2 index.
  * floor - округление до целого в меньшую сторону (2.7 -> 2, -2.7 -> -3)
* It’s left child is at 2 \* i + 1 index.
* It’s right child is at 2 \* i + 2 index.

### Insertion

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M4U2Yy3jLYggwsflJ4O%2F-M4U9Q05R5iCoBP-aho5%2FMin_heap_insertion.jpg?alt=media\&token=d2de1f99-695d-4f1b-a632-2e2bf7a5e814)

until it finds a parent node that is smaller than it (Worst case is **O(logN)**)

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M4Y7pydayANR40Z-Rz4%2F-M4ZZ40hWs4O-njLCaIY%2Fmax_heap_insertion.png?alt=media\&token=f442773d-d5ea-47fa-b644-7fe74047d3f1)

### Deletion

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M4UAgtDe4dGK2oYgku-%2F-M4UCmQMXwPBCDCh_k36%2FMin_heap_deletion.png?alt=media\&token=65eb0bef-5fc2-4bee-bdac-4af816c0f77e)

The worst case scenario is that we have to traverse the entire tree. The cost of this is **O(logN)**.

### From array to Min Heap

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M4Y7pydayANR40Z-Rz4%2F-M4YESeywDCb8wRKF_-K%2FFrom_array_to_min_heap.jpg?alt=media\&token=fc5e9f5d-ec05-45b2-939e-b13540ea9a8c)

The worst case time complexity will be **O(n)**.

#### Building Max neap from arrays using Williams method [LINK](https://www.youtube.com/watch?v=EQzqHWtsKq4)

### Java Min Heap implementation

```java
public class MinHeap {

	private int capacity = 10;
	private int size = 0;
	
	int[] items = new int[capacity];
	
	private int getLeftChildIndex(int parentIndex) {return 2 * parentIndex + 1;}
	private int getRightChildIndex(int parentIndex) {return 2 * parentIndex + 2;}
	private int getParentIndex(int childIndex) {return (childIndex-1) / 2;}
	
	private boolean hasLeftChild(int index) {return getLeftChildIndex(index) < size;}
	private boolean hasRightChild(int index) {return getRightChildIndex(index) < size;}
	private boolean hasParent(int index) {return getParentIndex(index) >= 0;}
	
	private int leftChild(int index) { return items[getLeftChildIndex(index)];}
	private int rightChild(int index) { return items[getRightChildIndex(index)];}
	private int parent(int index) { return items[getParentIndex(index)];}
	
	private void swap(int indexOne, int indexTwo) {
		int temp = items[indexOne];
		items[indexOne] = items[indexTwo];
		items[indexTwo] = temp;
	}
	
	private void ensureExtraCapacity() {
		if (size == capacity) {
			items = Arrays.copyOf(items, capacity * 2);
			capacity *= 2;
		}
	}
	
	public int peek() {
		if (size == 0) throw new IllegalStateException();
		return items[0];
	}
	
	//extract min element
	public int poll() {
		if (size == 0) throw new IllegalStateException();
		int item = items[0];
		items[0] = items[size-1];
		size--;
		heapifyDown();
		return item;
	}
	
	
	public void add(int item) {
		ensureExtraCapacity();
		items[size] = item;
		size++;
		heapifyUp();
	}
	
	
	private void heapifyUp() {
		int index = size - 1;
		while (hasParent(index) && parent(index) > items[index]) {
			swap(getParentIndex(index), index);
			index = getParentIndex(index);
		}
	}
	
	
	private void heapifyDown() {
		int index = 0;
		while (hasLeftChild(index)) { // if no left child => definitely no right child
			int smallerChildIndex = getLeftChildIndex(index); // assume left is smaller
			if (hasRightChild(index) && rightChild(index) < leftChild(index)) { // if right is smaller
				smallerChildIndex = getRightChildIndex(index);
			}
			
			if (items[index] < items[smallerChildIndex]) {
				break;
			} else {
				swap(index, smallerChildIndex);
			}
			index = smallerChildIndex;
		}
	}
}
```

## Hash table

[YOUTUBE](https://www.youtube.com/watch?v=KyUTuwz_b7Q)&#x20;

```
class HashTable {
    LinkedList[] data;
    
    boolean put(String key, Person value) {
        int hashCode = getHashCode(key);
        int index = convertToIndex(hashCode);  // e.g. hashCode % data.size()
        
        // find proper linkedList for insertion
        LinkedList list = data[index];
        
        list.insert(key, value); 
    }
}
```

`key` => `hashCode` => `index`&#x20;

#### Runtime&#x20;

Worst case for *look up* is `O(N)`, when there are a lot of collisions and you have just on LinkedList of all elements. For good implementations without collisions *look up* is `O(1)` .

#### HashTable vs HashMap

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M6fTZ9ZSn_OqpjOrBCd%2F-M6fZJ6ZV1dtncJWHulh%2FhashMap_hashTable.png?alt=media\&token=b87b0fe7-d1ba-4283-ab89-a98a2ad8df36)

### Resolve collisions

Collision when two keys after defining of index (hashCode () % mod) point to the same index.

#### Linear probing

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M4nj_Xxs6sbDvS1KcJx%2F-M4nkdMt2MizDmD0hXQC%2Fhash_openAddressing.png?alt=media\&token=7822317c-2166-4326-9ffd-e9eac26987dc)

#### Quadratic probing

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M4nkhI18UMJmpffxMvo%2F-M4nly5HAT-05JXiY9Xx%2Flinear-and-quadratic-probing.png?alt=media\&token=1a83650d-1910-4ced-893b-a754a7c4dce5)

#### Double hashing

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M4nmP73apTCg7Dj124k%2F-M4nmrKZSLpmf3xPrF2J%2FDouble%2BHashing%2B--%2BExample.jpg?alt=media\&token=f2736b87-2f7d-47ab-9253-ac28f2c4d52e)

#### Chaining

![](https://415484505-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxtoAXZwwOc4XGto8vb%2F-M4nmP73apTCg7Dj124k%2F-M4nrIDaUyH-m58M69EV%2FhashChaining1.png?alt=media\&token=476ae22c-2e00-47bd-bfe1-757bbe39803a)

## TreeMap

Key-Value data structure, where keys are stored in ascending order.

Internal implementation of TreeMap has nothing to do with HashMap. TreeMap is built on red-black tree.
