Posts /

CS2040 Notes

Twitter Facebook Google+
07 Mar 2021

2040 Revisison

Big-O Notation

Eg.

log(n!) = O(nlogn)

Recurrence

T(n) = T(n/2) + n
T(n) = T(n/2) + 1
T(n) = aT(n/b) + f(n)
// pseudo code
int search(A, key, n) {
    int begin = 0;
    int end = n - 1;
    while(begin < end){
        int mid = (begin + end) / 2;
        if (key <= A[mid]) {
            end = mid;
        } else {
            begin = mid + 1;
        }
    }
    return (A[begin] == key) ? begin : -1;
}

Preconditions:

Postcondition:

Invariants:

L4 Peak finding

Invariant

FindPeak(A,n)
    if A[n/2] is a peak then return n/2
    else if A[n/2+1] > A[n/2] then
        Search for peak in right half
    else if A[n/2-1] > A[n/2] then
        Search for peak in left half

Running Time

T(n) = T(n/2) + theta(1) = O(log n)

Steep peaks?

If we need to recurse on both sides: T(n) = 2T(n/2) + O(1) = O(n)

L5 6 7 Sorting

BubbleSort

void bubbleSort(int arr[]) {
    int n = arr.length;
    for (int i = 0; i < n-1; i++) {
        for (int j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                // swap arr[j+1] and arr[j]
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }      
    }    
}

Selection Sort

void sort(int arr[]) {
    int n = arr.length;

    // One by one move boundary of unsorted subarray
    for (int i = 0; i < n-1; i++) {
        // Find the minimum element in unsorted array
        int min_idx = i;
        for (int j = i+1; j < n; j++)
            if (arr[j] < arr[min_idx])
                min_idx = j;

                // Swap the found minimum element with the first
                // element
        int temp = arr[min_idx];
        arr[min_idx] = arr[i];
        arr[i] = temp;
    }
}

Insertion Sort

void sort(int arr[]) {
    int n = arr.length;
    for (int i = 1; i < n; ++i) {
        int key = arr[i];
        int j = i - 1;

        /* Move elements of arr[0..i-1], that are
        greater than key, to one position ahead
        of their current position */
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}

Merge Sort

Concept

Split into two halves -> sort each part -> Combine

Merge two sorted halves requires O(n) Hence T(n) = 2T(n/2) + cn = O(nlogn)

Code

void merge(int arr[], int l, int m, int r) {
    // Find sizes of two subarrays to be merged
    int n1 = m - l + 1;
    int n2 = r - m;

    /* Create temp arrays */
    int L[] = new int[n1];
    int R[] = new int[n2];

    /*Copy data to temp arrays*/
    for (int i = 0; i < n1; ++i)
        L[i] = arr[l + i];
    for (int j = 0; j < n2; ++j)
        R[j] = arr[m + 1 + j];

    /* Merge the temp arrays */

    // Initial indexes of first and second subarrays
    int i = 0, j = 0;

    // Initial index of merged subarry array
    int k = l;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            i++;
        }
        else {
            arr[k] = R[j];
            j++;
        }
        k++;
    }

    /* Copy remaining elements of L[] if any */
    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }

    /* Copy remaining elements of R[] if any */
    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }
}

// Main function that sorts arr[l..r] using
// merge()
void sort(int arr[], int l, int r) {
    if (l < r) {
    // Find the middle point
        int m =l+ (r-l)/2;

        // Sort first and second halves
        sort(arr, l, m);
        sort(arr, m + 1, r);

        // Merge the sorted halves
        merge(arr, l, m, r);
    }
}

QuickSort

Concept

Find pivot -> Partition the array -> Sort Each half

Optimised => Random pivot Paranoid Quicksort

repeat until p > (1/x)n and < (1-1/x)n

Partition

partition (A[1...n], n, pIndex)
    pivot = A[pIndex];
    swap(A[1], A[pIndex]);
    low = 2;
    high = n + 1;
    while(low < high)
        while (A[low] < pivot) and (low< high) do low++;
        while (A[high] > pivot) and (low < high) do high--;
        if(low < high) then swap (A[low], A[high]);
    swap(A[1], A[low-1]);
    return low-1;    

3-way Partition => Optimised Partition

< pivot = pivot In Proress > pivot

Sort component

void quicksort(A[1..n], n)
    if (n == 1) return
    else
        Choose Pivot index // random
        p = partition(A[1..n], n, pIndex)
        x = quicksort(A[1..p-1], p-1)
        y = quicksort(A[p+1..n], n-p)

Quick Select

Find the kth largest/smallest element Similar to quicksort but only need to recurse on ONE SIDE.

Select(A[1..n], n, k)
    if (n == 1) then return A[1]
    else Choose random pivot index pIndex
        p = partition(A[1..n], n, pIndex)
        if (k == p) then return A[p];
        else if (k < p) then
            return Select(A[1..p-1], k)
        else if (k > p ) then
            return Select(A[p+1], k - p)

T(n) = T(n/2) + O(n) ====> O(n)

L 8,9,10 Trees

AVL Tree

Concept

Rotation:
RightRotate(node)
    w = v.left
    w.parent = v.parent
    v.parent = w
    v.left = w.right
    w.right = v
LeftRotate(node)
    v = w.right
    v.parent = w.parent
    w.parent = v
    w.right = v.left
    v.left = w
if curr node curr is out of balance:
    if curr is left-heavy:
        curr.left is balanced/ left-heavy : RightRotate(curr)
        curr.left is right-heavy : LeftRotate(curr.left) RightRotate(curr)
    if curr is right-heavy:
        curr.right is balanced/ right-heavy : LeftRotate(curr)
        curr.right is left-heavy : RightRotate(curr.right) LeftRotate(curr)
Insert:

Sample Code (a bit different)

// Java program for insertion in AVL Tree
class Node {
	int key, height;
	Node left, right;

	Node(int d) {
		key = d;
		height = 1;
	}
}

class AVLTree {

	Node root;

	// A utility function to get the height of the tree
	int height(Node N) {
		if (N == null)
			return 0;

		return N.height;
	}

	// A utility function to get maximum of two integers
	int max(int a, int b) {
		return (a > b) ? a : b;
	}

	// A utility function to right rotate subtree rooted with y
	// See the diagram given above.
	Node rightRotate(Node y) {
		Node x = y.left;
		Node T2 = x.right;

		// Perform rotation
		x.right = y;
		y.left = T2;

		// Update heights
		y.height = max(height(y.left), height(y.right)) + 1;
		x.height = max(height(x.left), height(x.right)) + 1;

		// Return new root
		return x;
	}

	// A utility function to left rotate subtree rooted with x
	// See the diagram given above.
	Node leftRotate(Node x) {
		Node y = x.right;
		Node T2 = y.left;

		// Perform rotation
		y.left = x;
		x.right = T2;

		// Update heights
		x.height = max(height(x.left), height(x.right)) + 1;
		y.height = max(height(y.left), height(y.right)) + 1;

		// Return new root
		return y;
	}

	// Get Balance factor of node N
	int getBalance(Node N) {
		if (N == null)
			return 0;

		return height(N.left) - height(N.right);
	}

	Node insert(Node node, int key) {

		/* 1. Perform the normal BST insertion */
		if (node == null)
			return (new Node(key));

		if (key < node.key)
			node.left = insert(node.left, key);
		else if (key > node.key)
			node.right = insert(node.right, key);
		else // Duplicate keys not allowed
			return node;

		/* 2. Update height of this ancestor node */
		node.height = 1 + max(height(node.left),
							height(node.right));

		/* 3. Get the balance factor of this ancestor
			node to check whether this node became
			unbalanced */
		int balance = getBalance(node);

		// If this node becomes unbalanced, then there
		// are 4 cases Left Left Case
		if (balance > 1 && key < node.left.key)
			return rightRotate(node);

		// Right Right Case
		if (balance < -1 && key > node.right.key)
			return leftRotate(node);

		// Left Right Case
		if (balance > 1 && key > node.left.key) {
			node.left = leftRotate(node.left);
			return rightRotate(node);
		}

		// Right Left Case
		if (balance < -1 && key < node.right.key) {
			node.right = rightRotate(node.right);
			return leftRotate(node);
		}

		/* return the (unchanged) node pointer */
		return node;
	}

	// A utility function to print preorder traversal
	// of the tree.
	// The function also prints height of every node
	void preOrder(Node node) {
		if (node != null) {
			System.out.print(node.key + " ");
			preOrder(node.left);
			preOrder(node.right);
		}
	}

	public static void main(String[] args) {
		AVLTree tree = new AVLTree();

		/* Constructing tree given in the above figure */
		tree.root = tree.insert(tree.root, 10);
		tree.root = tree.insert(tree.root, 20);
		tree.root = tree.insert(tree.root, 30);
		tree.root = tree.insert(tree.root, 40);
		tree.root = tree.insert(tree.root, 50);
		tree.root = tree.insert(tree.root, 25);

		/* The constructed AVL Tree would be
			30
			/ \
		20 40
		/ \	 \
		10 25 50
		*/
		System.out.println("Preorder traversal" +
						" of constructed tree is : ");
		tree.preOrder(tree.root);
	}
}
// This code has been contributed by Mayank Jaiswal

successor
successor(node)
    if node.right not null then
        return minNode(node.right)
    parent = node.parent
    child = node
    while((parent not null) && (child = parent.right))
        child = parent
        parent = child.parent
    return parent
delete

Trie

No longer a binary tree, with max length L and n words

Argumented Trees