算法笔记:归并排序 快速排序 计数排序

归并排序

public static void mergeSort(int[] a) {
        mergeSort(a, 0, a.length - 1);
}

public static void mergeSort(int[] a, int start, int end) {
    // 递归出口:数组长度为1时
    if (start >= end) {
        return;
    }
    // 取中点
    int mid = start + (end - start) / 2;
    // 递归排序左半部分
    mergeSort(a, start, mid);
    // 递归排序右半部分
    mergeSort(a, mid + 1, end);
    // 运行到这里时 [start, mid] [mid + 1, end]已经各自有序 将两个有序数组合并为一个
    merge(a, start, mid, end);
}

public static void merge(int[] a, int start, int mid, int end) {
    int i = start, j = mid + 1, k = 0;
    // 需要创建临时数组存储数组 因为同一时间内只会创建一个数组(只有位于线程的栈的顶部的方法才会被运行) 所以空间复杂度为O(n)
    int[] temp = new int[end - start + 1];
    while (i <= mid && j <= end) {
        if (a[i] <= a[j]) {
            temp[k++] = a[i++];
        } else {
            temp[k++] = a[j++];
        }
    }
    while (i <= mid) {
        temp[k++] = a[i++];
    }
    while (j <= end) {
        temp[k++] = a[j++];
    }
    k = 0; i = start;
    while (i <= end) {
        a[i++] = temp[k++];
    }
}

快速排序

public static void quickSort(int[] a) {
    quickSort(a, 0, a.length - 1);
}

public static void quickSort(int[] a, int start, int end) {
    // 递归出口:数组长度为1
    if (start >= end) {
        return;
    }
    // 分区方法:将数组分为三个部分 前半部分的所有数均小于a[pivot] 后半部分的数均大于a[pivot]
    int pivot = partition(a, start, end);
    // 递归排序前半部分
    quickSort(a, start, pivot - 1);
    // 递归排序后半部分
    quickSort(a, pivot + 1, end);
}

public static int partition(int[] a, int start, int end) {
    // 取最后一个数为pivot
    int pivot = a[end];
    // 使得[start, i-1]中的所有数为小于pivot的
    int i = start;
    for (int j = start; j < end; j++) {
        if (a[j] < pivot) {
            swap(a, i, j);
            i++;
        }
    }
    // 将最后一个数放到分割的位置上
    swap(a, i, end);
    // 返回其索引
    return i;
}

public static void swap(int[] a, int i, int j) {
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}


// 快速选择 找到无序数组中第k大的数
public static int findKthLargest(int[] a, int k) {
        return quickSelect(a, 0, a.length - 1, a.length - k);
    }

    public static int quickSelect(int[] a, int start, int end, int k) {
        if (start >= end) {
            return start;
        }
        int pivot = partition(a, start, end);
        if (pivot == k) {
            return a[pivot];
        } else if (pivot > k) {
            return quickSelect(a, start, pivot - 1, k);
        } else {
            return quickSelect(a, pivot + 1, end, k);
        }
    }

    public static int partition(int[] a, int start, int end) {
        int pivot = a[end];
        int i = start;
        for (int j = start; j < end; j++) {
            if (a[j] < pivot) {
                swap(a, i, j);
                i++;
            }
        }
        swap(a, i, end);
        return i;
    }

计数排序

/**
 * 要求数组中的元素为非负数 且范围不能太大
 */
public static void countingSort(int[] a) {
   // 确定范围
   int max = a[0];
   int len = a.length;
    for (int i = 1; i < len; i++) {
        if (a[i] > max) {
            max = a[i];
        }
    }
    // 计算每个元素的个数
    int[] count = new int[max + 1];
    for (int num : a) {
        count[num]++;
    }
    // 累加个数 count[i]中的值为 <=i的数个数
    for (int i = 1; i <= max; i++) {
        count[i] = count[i - 1] + count[i];
    }
    int[] temp = new int[len];
    // 从后向前遍历 将元素插入到相应位置
    for (int i = len - 1; i >= 0; i--) {
        temp[--count[a[i]]] = a[i];
    }
    System.arraycopy(temp, 0, a, 0, len);
}

/**
 * 假设我们现在需要对 D,a,F,B,c,A,z 这个字符串进行排序,
 * 要求将其中所有小写字母都排在大写字母的前面,
 * 但小写字母内部和大写字母内部不要求有序。
 * 比如经过排序之后为 a,c,z,D,F,B,A,这个如何来实现呢?
 * 如果字符串中存储的不仅有大小写字母,还有数字。
 * 要将小写字母的放到前面,大写字母放在最后,数字放在中间,
 * 不用排序算法,又该怎么解决呢?
 */
public static void sortChar(char[] c) {
    // 双指针
    int i = 0, j = c.length - 1;
    while (i < j) {
        while (Character.isLowerCase(c[i])) {
            i++;
        }
        while (!Character.isLowerCase(c[j])) {
            j--;
        }
        if (i >= j) {
            break;
        }
        swap(c, i, j);
        i++;
        j--;
    }
    j = c.length - 1;
    while (i < j) {
        while (Character.isDigit(c[i])) {
            i++;
        }
        while (Character.isUpperCase(c[j])) {
            j--;
        }
        if (i >= j) {
            break;
        }
        swap(c, i, j);
        i++;
        j--;
    }
}

public static void swap(char[] c, int i, int j) {
    char temp = c[i];
    c[i] = c[j];
    c[j] = temp;
}
上一篇:数据结构与算法分析


下一篇:【JZ-11】旋转数组的最小数字(二分查找)