这是之前不知道什么时候从网上截图下来的,找不到出处了,超级棒的笔记
冒泡排序
//冒泡
public void bubleSort(int[] nums) {
for (int i = 0; i < nums.length - 1; i++) {//循环n-1次,每循环完一次,冒泡得一个最大值
for (int j = 0; j < nums.length - i - 1; j++) {
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
}
冒泡的思维是很简单的,第i次比较,若nums[j]>nums[j+1],交换位置,总共有N-1趟排序,每趟排序次数是N-i次
时间复杂度:最好情况下是已排好序的情况,时间复杂度为O(n),最坏情况是O(n^2),平均时间复杂度为O(n^2)
空间复杂度:O(1)
归并排序
归并排序的基本思想是:将待排序元素分成大小大致相同的2个子集合,分别2个集合进行排序,最终将排序好的子集合合并成为所要求的有序的集合。总时间为:分解时间+排序时间+合并时间
合并算法可递归的描述如下
//合并排序
public void mergeSort(Comparable a[], int left, int right) {
Comparable b[] = new Comparable[a.length];
if (left < right) {
int i = (left + right) / 2;
mergeSort(a, left, i);
mergeSort(a, i + 1, right);
merge(a, b, left, i, right);//合并到数组b
copy(a, b, left, right);//复制回数组a
}
}
//合并c[l:m]和c[m+1:r]到d[l:r]
public void merge(Comparable c[], Comparable d[], int l, int m, int r) {
int i = 1, j = m + 1, k = l;
while ((i <= m) && (j <= r)) {
if (c[i].compareTo(c[j]) <= 0) {
d[k++] = c[i++];
} else {
d[k++] = c[j++];
}
}
if (i > m) {
for (int q = j; q <= r; q++) {
d[k++] = c[q];
}
} else {
for (int q = i; q <= m; q++) {
d[k++] = c[q];
}
}
}
时间复杂度最好最坏平均情况下均为O(nlogn),空间复杂度为O(n),此排序算法稳定
详见算法设计与分析第三版
快速排序
快速排序算法是基于分治策略的另一个排序算法
以a[p]为基准元素将a[p:r]划分为3段:a[p:q-1]、a[q]和a[q+1:r],使得a[p:q-1]中任何元素小于等于a[q],a[q+1:r]中任何元素大于等于a[q]。
//快速排序
private static void quickSort(int a[], int p, int r) {
if (p < r) {
int q = partition(a, p, r);
quickSort(a, p, q - 1);
quickSort(a, q + 1, r);
}
}
private static int partition(int a[], int p, int r) {
int i = p, j = r;
int x = a[p];
while (i < j) {
//从右往左找比x小的数,填充a[i]
while (i < j && a[j] >= x) j--;
if (i < j) {
a[i] = a[j];
}
//从左往右找比x大的数,填充a[j]
while (i < j && a[i] < x) i++;
if (i < j) {
a[j] = a[i];
}
}
a[i] = x;
return i;
}
基本思路是挖坑填坑,从右往左,找出比基准数小的数填充至a[i],从左往右,找出比基准数大的数填充至a[j],再递归地进行下去
时间复杂度:最坏情况发生在划分过程产生的两个区域分别包含n-1和1个元素的时候,此时的算法复杂度为O(n^2),最好情况是每次划分所取的基准数恰好都为中值,即每次划分都产生两个大小为n/2的区域,此时的时间算法复杂度为O(nlogn),平均时间复杂度为O(nlogn)。
其性能取决于划分的对称性,不稳定
空间复杂度:O(logn)