import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 将给定数组排序
* @param arr int整型一维数组 待排序的数组
* @return int整型一维数组
*/
public int[] MySort (int[] arr) {
// write code here
if (arr.length < 2) {
return arr;
}
//return bubbleSort(arr);//冒泡排序
//return fastSort(arr, 0, arr.length - 1);//快速排序
//return insertSort(arr);//插入排序
//return hellSort(arr);//希尔排序
//return selectSort(arr);//选择排序
//return mergeSort(arr, 0, arr.length - 1); //归并排序
return heapSort(arr);//堆排序
//return radixSort(arr);//基数排序
}
//冒泡排序:从头开始遍历,如果当前数比下一个数大,就交换,扫完一遍后再扫一遍,每扫一遍终点-1
public int[] bubbleSort(int[] arr) {
int n = arr.length;
int temp;
boolean isChanged =
false;//如果一次循环中一个位置都没改,那就已经排好了,退出循环即可。
for (int i = 0; i < n - 1; i++) {
isChanged = false;
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
isChanged = true;
}
}
if (!isChanged) {
break;
}
}
return arr;
}
//快速排序:选择数组中任意一个数,将其作为target,定义一头一尾两个指针,
//如果尾指针的值比它小,将尾指针的值赋给头指针,否则尾指针左移
//如果头指针的比他大,将头指针的值赋给尾指针,否则头指针右移
//直到头尾指针重合,将该数的值修改为target
//此时target以左的值都比他小,target以右的值都比他大
//将这两部分再次进行快速排序
//直到传进来的头尾指针本就相等。
public int[] fastSort(int[] arr, int start, int end) {
if (start >= end) {
return arr;
}
int target = arr[start];
int head = start;
int rear = end;
while (head < rear) {
while (arr[rear] > target && head < rear) {
rear--;
}
if (head < rear) {
arr[head] = arr[rear];
head++;
}
while (arr[head] < target && head < rear) {
head++;
}
if (head < rear) {
arr[rear] = arr[head];
rear--;
}
}
arr[head] = target;
fastSort(arr, start, head - 1);
fastSort(arr, head + 1, end);
return arr;
}
//插入排序:从第二个数开始向前遍历,
//如果前面的数比它大,那就交换位置,继续向前遍历
//如果前面的数比它小,说明前面都有序了,那就再从下一个数开始遍历
public int[] insertSort(int[] arr) {
int n = arr.length;
int target;
for (int i = 1; i < n; i++) {
target = arr[i];
int j;
for (j = i - 1; j >= 0; j--) {
if (arr[j] > target) {
arr[j + 1] = arr[j];
} else {
break;
}
}
arr[j + 1] = target;
}
return arr;
}
//希尔排序:希尔排序是插入排序的变种
//因为插入排序如果是个几乎倒序的数组,那么时间复杂度会很高,所以用希尔排序优化
//希尔排序通过数组长度得到步长
//如题目给的数组【5,2,3,1,4】,5/2=2,步长为2
//那么5,3,4为一组,2,1为一组进行插入排序
//再将步长减半,重复操作
//直到步长为0
public int[] hellSort(int[] arr) {
int n = arr.length;
int step = arr.length / 2;
int target;
while (step > 0) {
for (int i = step; i < n; i++) {
int j;
target = arr[i];
for (j = i - step; j >= 0; j -= step) {
if (arr[j] > target) {
arr[j + step] = arr[j];
} else {
break;
}
}
arr[j + step] = target;
}
step /= 2;
}
return arr;
}
//选择排序:选择排序每遍历一次数组,找到里面的最大值放到后面,然后再从头遍历到末尾-1,直到遍历完
//找最小的数放在前面也可以
public int[] selectSort(int[] arr) {
int n = arr.length;
int max;
int index;
for (int i = 0; i < n; i++) {
max = arr[0];
index = 0;
for (int j = 0; j < n - i; j++) {
if (arr[j] > max) {
max = arr[j];
index = j;
}
}
max = arr[n - i - 1];
arr[n - i - 1] = arr[index];
arr[index] = max;
}
return arr;
}
//归并排序:本质是将两个有序数组合并为一个有序数组
//但给的单数组不是有序数组且只有一个
//因此要将连续对半分
//直到变成一系列只含有一个数的数组
//将这些数组两两合并,直到合并回一个数组
public int[] mergeSort(int[] arr, int start, int end) {
if (start == end) {
return arr;
}
int middle = (start + end) / 2;
//将前面一半送入递归
mergeSort(arr, start, middle);
mergeSort(arr, middle + 1, end);
merge(arr, start, middle, end);
return arr;
}
public void merge(int[] arr, int start, int middle, int end) {
if (start == end) {
return;
}
int i = start;
int j = middle + 1;
int index = 0;
int[] temp = new int[end - start + 1];
while (i <= middle && j <= end) {
while (i <= middle && arr[i] < arr[j]) {
temp[index] = arr[i];
index++;
i++;
}
if (i > middle) {
break;
}
while (j <= end && arr[i] >= arr[j]) {
temp[index] = arr[j];
index++;
j++;
}
}
if (i > middle) {
while (index < temp.length) {
temp[index++] = arr[j++];
}
}
if (j > end) {
while (index < temp.length) {
temp[index++] = arr[i++];
}
}
for (int k = start; k <= end; k++) {
arr[k] = temp[k - start];
}
}
//堆排序,将数组转化为大顶堆,从倒数第一个子树开始调整,
//调整的方式为对比根节点与两个子树的值
//若子节点有比根节点大的,就将其中最大的与根节点的值作交换
//这样就能保证每个根节点的值都比其子树大,从而大顶堆的根节点就是最大的数
//然后从最后一个数开始,将其与根节点交换,即将最大值放到最后
//然后调整大顶堆,使根节点替换为次大值。
public int[] heapSort(int[] arr) {
for(int i = (arr.length-2)/2; i >= 0; i--){
adjustHeap(arr,i,arr.length);
}
for(int i = arr.length - 1; i >= 0; i--){
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
adjustHeap(arr,0,i);
}
return arr;
}
public void adjustHeap(int[] arr, int i, int len){
int left = 2*i + 1;
int right = 2*i + 2;
int max = i;
if(left<len && arr[left] > arr[max]){
max = left;
}
if(right<len && arr[right] > arr[max]){
max = right;
}
if(max!=i){
int temp = arr[max];
arr[max] = arr[i];
arr[i] = temp;
adjustHeap(arr,max,len);
}
}
//基数排序:
//将每个数根据其个位放入对应的数组中,再按照0-9的顺序从数组按照先进先出的顺序中取出
//对数据的十位、百位……最高位都如此处理
//准备两组容器
//一组容器是一个二维数组,包含十个一维数组
//另一组容器是一个一维数组,存储0-9数组中的元素个数,方便存取
public int[] radixSort(int[] arr) {
int n = arr.length;
int[][] radix = new int[10][n];
int[] counts = new int[10];
int max = 0;
int cur;
for (int i = 0; i < n; i++) {
cur = String.valueOf(arr[i]).length();
if (cur > max) max = cur;
}
int ys;
for (int i = 0, j = 1; i < max; i++, j *= 10) {
for (int k = 0; k < n; k++) {
ys = arr[k]/j%10;
radix[ys][counts[ys]] = arr[k];
counts[ys]++;
}
//再从基数数组里面倒出来
int index = 0;
for(int k = 0; k < 10; k++){
for(int z = 0; z < counts[k]; z++){
arr[index++] = radix[k][z];
}
counts[k] = 0;
}
}
return arr;
}
}