- 排序数组:https://leetcode-cn.com/problems/sort-an-array/
class Solution {
public int[] sortArray(int[] nums) {
// selectionSort(nums);
// insertionSort(nums, 0, nums.length - 1);
// shellSort(nums);
quickSort(nums, 0, nums.length - 1);// 最快
// mergeSort(nums, 0, nums.length - 1, new int[nums.length]);
// radixSort(nums); // 报错,因为基数排序不支持排序负数
//heapSort(nums);
return nums;
}
// 冒泡排序 O(n^2):可通过判断一轮比较后没有进行交换提前跳出来优化
void bubbleSort(int[] nums) {
// 比较次数
for (int i = 0; i < nums.length - 1; i++) {
// 每次比较需要遍历的下标
for (int j = 0; j < nums.length - 1 - i; j++) {
if (nums[j] > nums[j + 1]) {
swap(nums, j, j + 1);
}
}
}
}
// 选择排序 O(n^2)
void selectionSort(int[] nums) {
for (int i = 0; i < nums.length - 1; i++) {
int minIndex = i;
int min = nums[i];
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] < min) {
min = nums[j];
minIndex = j;
}
}
swap(nums, i, minIndex);
}
}
// 插入排序 O(n^2)
void insertionSort(int[] nums, int left, int right) {
for (int i = left + 1; i <= right; i++) {
int insertedVal = nums[i];
int insertedIndex = i - 1;// 待插入数前面数的下标
while (insertedIndex >= 0 && insertedVal < nums[insertedIndex]) {
nums[insertedIndex + 1] = nums[insertedIndex];
insertedIndex--;
}
nums[insertedIndex + 1] = insertedVal;
}
}
// 希尔排序 O(nlog^2(n)):增量分组 + 插入排序
void shellSort(int[] nums) {
for (int gap = nums.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < nums.length; i++) {
int insertedVal = nums[i];
int insertedIndex = i - gap;
while (insertedIndex >= 0 && insertedVal < nums[insertedIndex]) {
nums[insertedIndex + gap] = nums[insertedIndex];
insertedIndex -= gap;
}
nums[insertedIndex + gap] = insertedVal;
}
}
}
// 快速排序 O(nlog(n)):冒泡排序的改进
final int INSERTION_SORT_THRESHOLD = 7;
void quickSort(int[] nums, int left, int right) {
// 小于一定阈值换用插入排序
if (right - left <= INSERTION_SORT_THRESHOLD) {
insertionSort(nums, left, right);
return;
}
int pIndex = partition(nums, left, right);
quickSort(nums, left, pIndex - 1);
quickSort(nums, pIndex + 1, right);
}
Random random = new Random();
int partition(int[] nums, int left, int right) {
int randomIndex = left + random.nextInt(right - left + 1);
swap(nums, left, randomIndex);
int pivot = nums[left];
int lt = left;
for (int i = left + 1; i <= right; i++) {
if (nums[i] < pivot) {
lt++;
swap(nums, i, lt);
}
}
swap(nums, lt, left);
return lt;
}
// 归并排序 O(nlog(n))
void mergeSort(int[] nums, int left, int right, int[] tmp) {
if (left >= right) {
return;
}
int mid = left + (right - left) / 2;
mergeSort(nums, left, mid, tmp);
mergeSort(nums, mid + 1, right, tmp);
merge(nums, left, right, tmp);
}
void merge(int[] nums, int left, int right, int[] tmp) {
// 1. 合并到临时数组
int mid = left + (right - left) / 2;
int i = left, j = mid + 1, t = 0;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
tmp[t++] = nums[i++];
} else {
tmp[t++] = nums[j++];
}
}
while (i <= mid) {
tmp[t++] = nums[i++];
}
while (j <= right) {
tmp[t++] = nums[j++];
}
// 2. 复制回原数组
t = 0;
i = left;
while (i <= right) {
nums[i++] = tmp[t++];
}
}
// 基数排序 O(n * bucketSum):空间换时间的经典算法,不支持排序负数
void radixSort(int[] nums) {
final int RADIX = 10;
int[][] bucket = new int[RADIX][nums.length];
int[] bucketElementCount = new int[RADIX];
int max = nums[0];
for (int i = 0; i < nums.length; i++) {
max = Math.max(max, nums[i]);
}
int maxDigit = ("" + max).length();
for (int i = 0, digit = 1; i < maxDigit; i++, digit *= 10) {
for (int j = 0; j < nums.length; j++) {
int digitElement = nums[j] / digit % 10;
bucket[digitElement][bucketElementCount[digitElement]] = nums[j];
bucketElementCount[digitElement]++;
}
int index = 0;
for (int k = 0; k < RADIX; k++) {
for (int l = 0; l < bucketElementCount[k]; l++) {
nums[index++] = bucket[k][l];
}
bucketElementCount[k] = 0;
}
}
}
// 堆排序 O(nlog(n))
void heapSort(int[] nums) {
for (int i = nums.length / 2 - 1; i >= 0; i--) {
adjustHeap(nums, nums.length, i);
}
for (int i = nums.length - 1; i >= 0; i--) {
swap(nums, i, 0);
adjustHeap(nums, i, 0);
}
}
void adjustHeap(int[] nums, int len, int nodeIndex) {
int tmp = nums[nodeIndex];
for (int i = 2 * nodeIndex + 1; i < len; i = 2 * i + 1) {
if (i + 1 < len && nums[i + 1] > nums[i]) {
i++;
}
if (nums[i] > tmp) {
nums[nodeIndex] = nums[i];
nodeIndex = i;
} else {
break;
}
}
nums[nodeIndex] = tmp;
}
void swap(int[] nums, int a, int b) {
int tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
}
}
```## 排序算法总结
```java
class Solution {
public int[] sortArray(int[] nums) {
// selectionSort(nums);
// insertionSort(nums, 0, nums.length - 1);
// shellSort(nums);
quickSort(nums, 0, nums.length - 1);// 最快
// mergeSort(nums, 0, nums.length - 1, new int[nums.length]);
// radixSort(nums); // 报错,因为基数排序不支持排序负数
//heapSort(nums);
return nums;
}
// 冒泡排序 O(n^2):可通过判断一轮比较后没有进行交换提前跳出来优化
void bubbleSort(int[] nums) {
// 比较次数
for (int i = 0; i < nums.length - 1; i++) {
// 每次比较需要遍历的下标
for (int j = 0; j < nums.length - 1 - i; j++) {
if (nums[j] > nums[j + 1]) {
swap(nums, j, j + 1);
}
}
}
}
// 选择排序 O(n^2)
void selectionSort(int[] nums) {
for (int i = 0; i < nums.length - 1; i++) {
int minIndex = i;
int min = nums[i];
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] < min) {
min = nums[j];
minIndex = j;
}
}
swap(nums, i, minIndex);
}
}
// 插入排序 O(n^2)
void insertionSort(int[] nums, int left, int right) {
for (int i = left + 1; i <= right; i++) {
int insertedVal = nums[i];
int insertedIndex = i - 1;// 待插入数前面数的下标
while (insertedIndex >= 0 && insertedVal < nums[insertedIndex]) {
nums[insertedIndex + 1] = nums[insertedIndex];
insertedIndex--;
}
nums[insertedIndex + 1] = insertedVal;
}
}
// 希尔排序 O(nlog^2(n)):增量分组 + 插入排序
void shellSort(int[] nums) {
for (int gap = nums.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < nums.length; i++) {
int insertedVal = nums[i];
int insertedIndex = i - gap;
while (insertedIndex >= 0 && insertedVal < nums[insertedIndex]) {
nums[insertedIndex + gap] = nums[insertedIndex];
insertedIndex -= gap;
}
nums[insertedIndex + gap] = insertedVal;
}
}
}
// 快速排序 O(nlog(n)):冒泡排序的改进
final int INSERTION_SORT_THRESHOLD = 7;
void quickSort(int[] nums, int left, int right) {
// 小于一定阈值换用插入排序
if (right - left <= INSERTION_SORT_THRESHOLD) {
insertionSort(nums, left, right);
return;
}
int pIndex = partition(nums, left, right);
quickSort(nums, left, pIndex - 1);
quickSort(nums, pIndex + 1, right);
}
Random random = new Random();
int partition(int[] nums, int left, int right) {
int randomIndex = left + random.nextInt(right - left + 1);
swap(nums, left, randomIndex);
int pivot = nums[left];
int lt = left;
for (int i = left + 1; i <= right; i++) {
if (nums[i] < pivot) {
lt++;
swap(nums, i, lt);
}
}
swap(nums, lt, left);
return lt;
}
// 归并排序 O(nlog(n))
void mergeSort(int[] nums, int left, int right, int[] tmp) {
if (left >= right) {
return;
}
int mid = left + (right - left) / 2;
mergeSort(nums, left, mid, tmp);
mergeSort(nums, mid + 1, right, tmp);
merge(nums, left, right, tmp);
}
void merge(int[] nums, int left, int right, int[] tmp) {
// 1. 合并到临时数组
int mid = left + (right - left) / 2;
int i = left, j = mid + 1, t = 0;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
tmp[t++] = nums[i++];
} else {
tmp[t++] = nums[j++];
}
}
while (i <= mid) {
tmp[t++] = nums[i++];
}
while (j <= right) {
tmp[t++] = nums[j++];
}
// 2. 复制回原数组
t = 0;
i = left;
while (i <= right) {
nums[i++] = tmp[t++];
}
}
// 基数排序 O(n * bucketSum):空间换时间的经典算法,不支持排序负数
void radixSort(int[] nums) {
final int RADIX = 10;
int[][] bucket = new int[RADIX][nums.length];
int[] bucketElementCount = new int[RADIX];
int max = nums[0];
for (int i = 0; i < nums.length; i++) {
max = Math.max(max, nums[i]);
}
int maxDigit = ("" + max).length();
for (int i = 0, digit = 1; i < maxDigit; i++, digit *= 10) {
for (int j = 0; j < nums.length; j++) {
int digitElement = nums[j] / digit % 10;
bucket[digitElement][bucketElementCount[digitElement]] = nums[j];
bucketElementCount[digitElement]++;
}
int index = 0;
for (int k = 0; k < RADIX; k++) {
for (int l = 0; l < bucketElementCount[k]; l++) {
nums[index++] = bucket[k][l];
}
bucketElementCount[k] = 0;
}
}
}
// 堆排序 O(nlog(n))
void heapSort(int[] nums) {
for (int i = nums.length / 2 - 1; i >= 0; i--) {
adjustHeap(nums, nums.length, i);
}
for (int i = nums.length - 1; i >= 0; i--) {
swap(nums, i, 0);
adjustHeap(nums, i, 0);
}
}
void adjustHeap(int[] nums, int len, int nodeIndex) {
int tmp = nums[nodeIndex];
for (int i = 2 * nodeIndex + 1; i < len; i = 2 * i + 1) {
if (i + 1 < len && nums[i + 1] > nums[i]) {
i++;
}
if (nums[i] > tmp) {
nums[nodeIndex] = nums[i];
nodeIndex = i;
} else {
break;
}
}
nums[nodeIndex] = tmp;
}
void swap(int[] nums, int a, int b) {
int tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
}
}