Bubble Sort

Bubble Sort requires n - 1 pass to sort an array of n elements.
In each pass every adjacent elements a[i] and a[i + 1] is compared and if they are not in order then they are swapped.
In each pass, we have n - k comparisons, where n is the number of elements and k is the pass number.
So 1st pass requires n - 1 comparisons, kth pass requires n - k comparisons and the last pass requires 1 comparison.

Time Complexity
O(n^2)
In 1st pass we have n - 1 comparisons, in 2rd we have n -2 comparisons, kth pass we have n - k comparisons, and the last pass requires 1 comparison.
F(n) = (n -1) + (n - 2) + .... + 3 + 2 + 1 = n(n - 1)/2 = O(n^2)
Space Complexity
O(1)

public void sortIntegers(int[] A) {
    // Write your code here
    if(A == null || A.length <= 1) return;
    for(int i = 0; i < A.length; i++){
        for(int j = 1; j < A.length - i; j++){
            if(A[j] < A[j - 1]) swap(A, j , j - 1);
        }
    }
    return;
}

private void swap(int[] A, int i , int j){
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

Insertion Sort

In pass1, element a[1] is inserted either before or after a[0] so that a[0] and a[1] are sorted.
In pass2, a[2] is inserted either before a[0] or between a[0] and a[1] or after a[1] so that a[0], a[1] and a[2] are sorted.

It process is carried out n - 1 times.

Time Complexity
O(N^2)
F(n) = 1 + 2 + 3 + ... + (n - 2) + (n -1) = n(n - 1)/2 = O(N^2)
Insertion sort requires n - 1 pass to sort an array of n elements.
In each pass we have k comparisons, where k is the pass number.
So, 1st pass requires 1 comparison, kth pass requires k - 1 comparisons and the last pass requires n - 1 comparisons.

public void sortIntegers(int[] A) {
    // Write your code here
    if(A == null || A.length <= 1) return;
    int len = A.length;
    int j = 0, temp = 0;
    for(int i = 1; i < len; i++){
        j = i - 1;
        temp = A[i];
        while(j >= 0){
            if(temp < A[j]) swap(A, j, j + 1);
            j--;
        }
    }
}
private void swap(int[] A, int i, int j){
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

Selection Sort

We find the smallest element in each pass and place it in the appropriate position to get the elements in ascending or descending order.
If we have n elements then it requires (n - 1) pass to sort.

In pass1, smallest element is searched between a[0] to a[n - 1] and swapped with a[0].
In pass2, smallest element is searched between a[1] to a[n - 1] and swapped with a[1].
In a similar way, the process is carried out n - 1 times.

Selection sort requires n - 1 pass to sort an array of n elements.
In each pass, we search for the smallest element from the search range and swap it with appropriate place.
In each pass we have n - k comparisons, where n is the number of elements and k is the pass number.
So, 1st pass requires n - 1 comparisons, kth pass requires n - k comparisons and the last pass requires 1 comparison.

Time Complexity
F(n) = (n - 1) + (n - 2) + (n - 3) + ... + 3 + 2 + 1 = n(n - 1)/2 = O(n^2)

public void sortIntegers(int[] A) {
    // Write your code here
    //corner case
    if(A == null || A.length <= 1) return;
    int len = A.length;
    for(int i = 0; i < len - 1; i++){
        //find the min
        int min = A[i];
         int minIndex = i;
        for(int j = i; j < len; j++){
            if(A[j] < min){
                min = A[j];
                minIndex = j;
            }
        }
        swap(A, i, minIndex);
    }
}

private void swap(int[] A, int i, int j){
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

Merge Sort

We used the idea of divide and conquer. We divide the array into two parts, sort them and then merge them to get the elements in ascending or descending order.

Merge sort follows recursive algorithm. We divide the array into halves till the sub array has only 1 element. We need an extra temporary array of the same size as the input array for merging.

Stable (the relative position won't change)

Time Complexity
Divide: O(n)
Conquer: O(nlogn)
O(n) + O(nlogn) = O(nlogn)
Space Complexity
O(n)

One application of merge sort is external sort when the array cannot be fit in memory, doing merge in memory and flush sorted part into disk.

public void sortIntegers2(int[] A) {
    // Write your code here
    //corner case
    if(A == null || A.length <= 1) return;
    int[] helper = new int[A.length];
    mergeSort(A, helper, 0, A.length - 1);
    return;
}

private void mergeSort(int[] A, int[] helper, int left, int right){
    if(left == right) return;
    int mid = left + (right - left)/2;
    mergeSort(A, helper, left, mid);
    mergeSort(A, helper, mid + 1, right);
    merge(A, helper, left, right, mid);
}

private void merge(int[] A, int[] helper, int left, int right, int mid){
    for(int i = left; i <= right; i++){
        helper[i] = A[i];
    }
    int leftI = left;
    int rightI = mid + 1;
    while(leftI <= mid && rightI <= right){
        if(helper[leftI] < helper[rightI]){
            A[left++] = helper[leftI++];
        }else{
            A[left++] = helper[rightI++];
        }
    }
    while(leftI <= mid){
         A[left++] = helper[leftI++];
    }
}

Quick Sort

  1. Find pivot that divides the array into two halves.

  2. Quick sort the left half.

  3. Quick sort the right half.

Not stable

[0, l) < pivot
[l, r] to check
(r, length - 1 - 1] > pivot

All elements to the right of pivot must be greater than pivot. All elements to the left of pivot must be smaller than pivot.

Time Complexity
Average case: O(nlogn), every time partition the whole array into halves
Worst case: O(n^2) if every time choose the largest or smallest in the whole array, so n + n - 1 + n - 2 + .... + 2 + 1 = O(n^2)

So to avoid worst case, it's important to choose the pivot randomly.

Space Complexity
Depends on how many recursions
Best case: O(logn)
Worst case: O( n )

public void sortIntegers2(int[] A) {
    // Write your code here
    //corner case
    if(A == null || A.length <= 1) return;
    quickSort(A, 0, A.length - 1);
}

private void quickSort(int[] A, int left, int right){
    //base case
    if(left >= right) return;
    int pivotIndex = findPivot(A, left, right);
    quickSort(A, left, pivotIndex - 1);
    quickSort(A, pivotIndex + 1, right);
}

private int findPivot(int[] A, int left, int right){
    int pivotIndex = left + (int)Math.random()*(right - left + 1);
    int pivot = A[pivotIndex];
    swap(A, pivotIndex, right);
    int leftI = left;
    int rightI = right - 1;
    while(leftI <= rightI){
        if(A[leftI] < pivot) leftI++;
        else if(A[rightI] >= pivot) rightI--;
        else swap(A, leftI++, rightI--);
    }
    swap(A, leftI, right);
    return leftI;
}
private void swap(int[] A, int i, int j){
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

annielulu
5 声望5 粉丝