import java.util.Arrays;
/**
* 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
* 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
* 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
* 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。
*/
public class Sort {
/**
* 选择排序
* <p>
* 时间复杂度(平均):O(n^2)
* 时间复杂度(最好):O(n^2)
* 时间复杂度(最坏):O(n^2)
* 空间复杂度:O(1)
* 稳定性:不稳定
*
* @param arr
*/
public static void selectionSort(int[] arr) {
for (int i = 0, len = arr.length - 1; i < len; i++) {
int minIndex = i;
for (int j = i + 1; j < arr.length; j++) {//选择最小的数
if (arr[j] < arr[i]) {
minIndex = j;
}
}
if (minIndex != i) {
swap(arr, i, minIndex);
}
}
}
/**
* 冒泡排序
* <p>
* 时间复杂度(平均):O(n^2)
* 时间复杂度(最好):O(n^2)
* 时间复杂度(最坏):O(n^2)
* 空间复杂度:O(1)
* 稳定性:稳定
*
* @param arr
*/
public static void bubbleSort(int arr[]) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0, len = arr.length - i - 1; j < len; j++) {
if (arr[j + 1] < arr[j]) {
swap(arr,j+1,j);
}
}
}
}
/**
* 快速排序
* <p>
* 时间复杂度(平均):O(nlogn)
* 时间复杂度(最好):O(nlogn)
* 时间复杂度(最坏):O(n^2)
* 空间复杂度:O(nlogn)
* 稳定性:不稳定
*
* @param arr
*/
public static void QuickSort(int[] arr) {
QuickSort(arr, 0, arr.length - 1);
}
public static void QuickSort(int[] arr, int start, int end) {
if (start >= end) {
return;
}
int k = arr[start];
int l = start, r = end;
//使k左边的值小于等于k,k右边的值大于等于k
while (l < r) {
while (l < r && arr[r] >= k) r--;
arr[l] = arr[r];
while (l < r && arr[l] <= k) l++;
arr[r] = arr[l];
}
arr[l] = k;
QuickSort(arr, start, l - 1);
QuickSort(arr, l + 1, end);
}
/**
* 归并排序
* <p>
* 时间复杂度(平均):O(nlogn)
* 时间复杂度(最好):O(nlogn)
* 时间复杂度(最坏):O(nlogn)
* 空间复杂度:O(n)
* 稳定性:稳定
*
* @param arr
*/
public static void mergeSort(int[] arr) {
mergeSort(arr, new int[arr.length], 0, arr.length - 1);
}
public static void mergeSort(int[] arr, int[] temp, int start, int end) {
if (start < end) {
int mid = (start + end) >> 1;
mergeSort(arr, temp, start, mid);
mergeSort(arr, temp, mid + 1, end);
merge(arr, temp, start, mid, end);
}
}
/**
* 合并
*
* @param arr
* @param temp
* @param start
* @param mid
* @param end
*/
private static void merge(int[] arr, int[] temp, int start, int mid, int end) {
int i = start;
int j = mid + 1;
int t = 0;
while (i <= mid && j <= end) {
if (arr[i] < arr[j]) {
temp[t++] = arr[i++];
} else {
temp[t++] = arr[j++];
}
}
//剩余的数,直接赋值
while (i <= mid) temp[t++] = arr[i++];
while (j <= end) temp[t++] = arr[j++];
System.arraycopy(temp, 0, arr, start, end - start + 1);
}
/**
* 插入排序
* <p>
* 时间复杂度(平均):O(n^2)
* 时间复杂度(最好):O(n)
* 时间复杂度(最坏):O(n^2)
* 空间复杂度:O(1)
* 稳定性:稳定
*
* @param arr
*/
public static void insertSort(int[] arr) {
for (int i = 0, len = arr.length - 1; i < len; i++) {
int current = arr[i + 1];
int j = i;
while (j >= 0 && arr[j] > current) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = current;
}
}
/**
* 堆排序
* <p>
* 时间复杂度(平均):O(nlogn)
* 时间复杂度(最好):O(nlogn)
* 时间复杂度(最坏):O(nlogn)
* 空间复杂度:O(1)
* 稳定性:不稳定
*
* @param arr
*/
public static void heapSort(int[] arr) {
//从堆的第一个非叶子节点(位置:(arr.length - 1)/2)开始从右至左,从下到上,构建大顶堆
for (int i = (arr.length - 1) >> 1; i >= 0; i--) {
buildMaxHeap(arr, i, arr.length - 1);
}
for (int i = arr.length - 1; i >= 0; i--) {
swap(arr, i, 0);//将大顶堆的根,交换到堆的末尾
buildMaxHeap(arr, 0, i - 1);//构建新的大顶堆
}
}
private static void buildMaxHeap(int[] arr, int index, int len) {
int max = (index << 1) + 1;//2*index+1
if (max > len) {
return;
}
int right = max + 1;
//有右节点,且比左节点大
if (right <= len && arr[right] > arr[max]) {
max++;
}
if (arr[max] > arr[index]) {
swap(arr, max, index);
buildMaxHeap(arr, max, len);//对被置换的原父节点重新构建大顶堆
}
}
public static void swap(int[] arr, int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}