0、复杂度及稳定性
排序算法 | 平均时间复杂度 | 最差时间复杂度 | 最好时间复杂度 | 空间复杂度 | 稳定性(相等元素相对顺序不变) |
冒泡排序 | O(n^2) | O(n^2) | O(n)有序 | O(1) | 稳定 |
插入排序 | O(n^2) | O(n^2) | O(n)有序 | O(1) | 稳定 |
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
希尔排序 | O(nlogn) | O(n^2) | O(nlogn) | O(1) | 不稳定 |
快速排序 | O(nlogn) | O(n^2)逆序 | O(nlogn) | O(logn) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
桶排序 | O(k + n) | O(n^2) | O(n) | O(n+k) | 稳定 |
计数排序 | O(n+k) | O(n+k) | O(n+k) | O(k) | 稳定 |
基数排序 | O(n×k) | O(n×k) | O(n×k) | O(n×k) | 稳定 |
一、冒泡排序
比较相邻的元素,若顺序错误则交换
public void bubbleSort(int[] array) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (array[j] > array[j+1]) {
swap(j, j+1, array)
}
}
}
}
二、选择排序
在未排序序列中找到最小元素,存放到排序序列的起始位置。再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
public void selectionSort(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
// 找到最小元素的索引
int minIndex = i;
for (int j = i + 1; j < array.length; j++) {
if (array[j] < array[minIndex]) {
minIndex = j;
}
}
swap(i, minIndex, array);
}
}
三、插入排序
将一个待排序的元素插入到已排序的序列中的适当位置(从后向前扫描),直到全部插入完
public void insertionSort(int[] array) {
int n = array.length;
for (int i = 1; i < n; ++i) {
int pre = i - 1;
while (pre >= 0 && array[pre] > array[i]) {
array[pre + 1] = array[pre];
pre = pre - 1;
}
array[pre + 1] = array[i];
}
}
四、希尔排序
插入排序的一种更高效的改进版
public void shellSort(int[] array) {
int n = array.length;
int gap = n / 2;
// Start with a big gap, then reduce the gap
while (gap > 0) {
for (i = gap; i < n; i++) {
int pre = i - gap;
while (pre >= 0 && array[pre] > array[i]) {
array[pre + gap] = array[pre];
pre -= gap;
}
array[pre + gap] = array[i];
}
gap /= 2;
}
}
五、快速排序
采用分治法。选择一个“基准”元素,通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比基准元素小,另一部分的所有数据都比基准元素大。以此类推,达到有序
详解:https://segmentfault.com/a/1190000040022056#item-2-1
class Solution {
public int[] sortArray(int[] nums) {
//快排
sort(0, nums.length, nums);
return nums;
}
public void sort(int start, int end, int[] nums) {
if (start >= end) {
return;
}
int partition = partition(start, end, nums);
sort(start, partition, nums);
sort(partition + 1, end, nums);
}
public int partition(int start, int end, int[] nums) {
int point = start;
int piovt = nums[end - 1];
for (int i = start; i < end - 1 ; i++) {
if (nums[i] <= piovt) {
swap(i, point, nums);
point++;
}
}
swap(point, end - 1, nums);
return point;
}
public void swap(int i, int j, int[] nums) {
if (i == j) {return;}
nums[i] ^= nums[j];
nums[j] ^= nums[i];
nums[i] ^= nums[j];
}
}
六、归并排序
先递归分解数组,再将已有序的子序列合并,得到完全有序的序列
public void mergeSort(int[] array, int left, int right) {
if (left < right) {
// 找到中间位置
int mid = (left + right) / 2;
// 对左半部分进行归并排序
mergeSort(array, left, mid);
// 对右半部分进行归并排序
mergeSort(array, mid, right);
// 合并左右两部分
merge(array, left, mid, right);
}
}
public void merge(int[] array, int left, int mid, int right) {
// 创建一个临时数组来辅助归并操作
int[] temp = new int[right - left];
// 左指针和右指针分别指向左半部分和右半部分的起始位置
int i = left;
int j = mid;
int k = 0;
// 合并两个有序数组到临时数组
while (i < mid && j < right) {
if (array[i] <= array[j]) {
temp[k++] = array[i++];
} else {
temp[k++] = array[j++];
}
}
// 将左半部分剩余的元素复制到临时数组
while (i < mid) {
temp[k++] = array[i++];
}
// 将右半部分剩余的元素复制到临时数组
while (j < right) {
temp[k++] = array[j++];
}
// 将临时数组中的元素复制回原数组
for (k = 0; k < temp.length; k++) {
array[left + k] = temp[k];
}
}
七、堆排序
利用堆进行排序-见数据结构+算法-优快云博客