public static void insertSort(int[] arr){
for (int i=1;iarr[i],则元素一直前移,直到找到合适的位置
for (j=i-1;j>=0&&arr[j]>temp;j--){
//元素前移
arr[j+1]=arr[j];
}
//找到合适的位置
arr[j+1]=temp;
}
}
public static void binaryInsertSort(int[] arr){
int length = arr.length;
//从第二个元素开始遍历
for (int i=1;ikey){
high=mid-1;
}else{
high=mid+1;
}
}
//找到合适位置后将left到i-1位置上的数据全部向后移动
for(int j=i-1;j<=low;j--){
arr[j+1]=arr[j];
}
arr[low]=key;
}
}
public static void shellSort(int[] arr){
int length=arr.length;
//初始化间隔
int gap=length/2;
//当间隔大于零时按序列排序并减少间隔
while (gap>0){
//按序列进行插入排序
for (int i=gap;i=gap&&arr[j-gap]>temp;j-=gap){
//元素向前移动找到插入位置
arr[j]=arr[j-gap];
}
arr[j]=temp;
}
//缩小间隔序列
gap/=2;
}
}
public static void bubbleSort(int[] arr){
//设置标志位,若为true,则表示已经排好序
boolean swapped;
for (int i=0;iarr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
//交换位置说明还有元素顺序不对
swapped=true;
}
}
//一趟遍历完所有数据后,若swapped为false,则说明已经排好序
if (!swapped){
break;
}
}
}
public static int partition(int[] arr,int low,int high){
//设置末尾元素为基准元素
int pivot=arr[high];
//分界索引
int i=low-1;
for (int j=low;j public static void selectSort(int[] arr){
int n=arr.length;
for (int i=0;i //堆排序
public static void heapSort(int[] arr){
//找到第一个非叶结点,开始调整
for (int i=arr.length/2-1;i>=0;i--){
adjustHeap(arr,i,arr.length);
}
//将最后一个与第一个交换,然后调整
for (int i=arr.length-1;i>0;i--){
int temp=arr[i];
arr[i]=arr[0];
arr[0]=temp;
adjustHeap(arr,0,i);
}
}
//将一个数组序列调整成大顶堆
/**
*函数功能:将以i为根的子树调整为大顶堆
* @param arr 待调整数组
* @param i 表示非叶结点在数组中的索引
* @param length 表示堆多少个元素进行调整,length逐渐减少
*/
public static void adjustHeap(int[] arr,int i,int length){
//取出当前元素的值
int temp=arr[i];
//调整节点,k初始值为左子结点
for (int k=2*i+1;ktemp){
arr[i]=arr[k];//将较大的值赋给当前节点
i=k;
}else {
break;
}
}
arr[i]=temp;
}
public static void mergeSort(int[] arr,int left,int right){
if (left>>1;//相当于/2
//递归排序左子序列
mergeSort(arr,left,mid);
//递归排序右子序列
mergeSort(arr,mid+1,right);
merge(arr,left,mid,right);
}
}
public static void merge(int[] arr,int left,int mid,int right){
//获取两部分序列的大小
int n1=mid-left+1;
int n2=right-mid;
//创建临时数组,存放两个子序列的元素
int[] L = new int[n1];
int[] R = new int[n2];
//将两个子序列元素复制到临时数组
System.arraycopy(arr,left,L,0,n1);
System.arraycopy(arr,mid+1,R,0,n2);
//初始化索引
int i=0,j=0,k=left;
//比较并合并
while (i //基数排序
/**
* 辅助函数:
* 创建桶函数creatBuckets
* 获取位数函数getMaxDigits
* 获取指定位函数getDigit
* @param arr
*/
public static void radixSort(int[] arr){
if (arr==null||arr.length==0){
return;
}
//获取最大值以及位数
int maxVal = Arrays.stream(arr).max().getAsInt();
int maxDigits=getMaxDigits(maxVal);
//创建桶集合
List> buckets = creatBuckets(10);
//根据个位,十位,等递增循环的分配元素到桶中,再重新取出,再分配
for (int digit=1;digit<=maxDigits;digit++){
//分配元素到桶中
for (int num:arr){
//取出指定数位的值
int bucketIndex = getDigit(num, digit);
buckets.get(bucketIndex).add(num);
}
//一个数位分配完毕,重新取出元素
int index=0;
for (List bucket:buckets){
for (int num:bucket){
arr[index++]=num;
}
//清空每个桶
bucket.clear();
}
}
}
//根据大小创建桶
public static List> creatBuckets(int size){
List> buckets =new ArrayList<>();
for (int i=0;i());
}
return buckets;
}
//获取这个数有几位
public static int getMaxDigits(int num){
int digits=0;
while (num>0){
num/=10;
digits++;
}
return digits;
}
/**
*
* @param num 数字
* @param digit 目标位1表示个位,2表示十位,以此类推
* @return 获取数字在其指定位上的数字
*/
public static int getDigit(int num,int digit){
//对数取10的余数得到的就是个位上的值,获取地n位的值就应该让此数除以10的n-1次方
return (num/(int)Math.pow(10,digit-1))%10;
}
public static void bucketSort(int[] arr){
//1.初始化桶,找到最大最小值
int minValue=Integer.MIN_VALUE;
int maxValue=Integer.MAX_VALUE;
for (int num:arr){
minValue=Math.min(minValue,num);
maxValue=Math.max(maxValue,num);
}
//2.初始化桶,创建桶的集合
int bucketSize=(maxValue-minValue)/arr.length-1;
ArrayList> buckets = new ArrayList<>(bucketSize);
//初始化桶集合
for (int i=0;i());
}
//3.分配元素到桶
for (int num:arr){
//计算元素所属桶的索引
int bucketIndex=(num-minValue)/bucketSize;
//将元素添加到对应的桶中
buckets.get(bucketIndex).add(num);
}
//4.对每个桶进行排序
for (ArrayList bucket:buckets){
Integer[] array = (Integer[]) bucket.toArray();
int[] array1 = Arrays.stream(array).mapToInt(Integer::intValue).toArray();
//选择排序
insertSort(array1);
}
//5.合并桶内元素
int index = 0;
for (ArrayList bucket:buckets){
for (int num:bucket){
arr[index++]=num;
}
}
}
public static void countSort(int[] arr){
//获取数组最大和最小值
int maxVal = Arrays.stream(arr).max().getAsInt();
int minVal = Arrays.stream(arr).min().getAsInt();
//初始化数组
int range = maxVal - minVal + 1;
int[] count = new int[range];
//统计每个元素出现次数
for (int num:arr){
count[num-minVal]++;
}
//计算前驱元素累计次数
for (int i=1;i=0;i--){
int num=arr[i];
//元素减去偏移量是在count数组的下标,对应count[countIndex]是,小于countIndex值的累加量
int countIndex = num - minVal;
//在最终排序序列中的下标是count[countIndex]-1;
resultSort[--count[countIndex]]=num;
}
//将排序结果复制回原来的数组中
System.arraycopy(resultSort,0,arr,0,arr.length);
}
| 适用场景 | 最好时间复杂度 | 最坏时间复杂度 | 平均时间复杂度 | 空间复杂度 | 稳定性 | |
|---|---|---|---|---|---|---|
| 插入排序 | 数据规模小,近乎有序 | O(n) | O(n²) | O(n²) | O(1)(原地排序) | 稳定 |
| 希尔排序 | 数据规模较大,且初始状态无明显有序特征 | 取决于所选增量序列,最优情况下可达到O(n log n) | 赖于增量序列的选择 | 赖于增量序列的选择 | O(1)(原地排序) | 不稳定 |
| 冒泡排序 | 数据规模小,或近乎有序的数组 | O(n)-已排序 | O(n²)-逆序 | O(n²) | O(1)(原地排序) | 稳定 |
| 快速排序 | 大规模,无特殊性质 | O(n log n) | (已排序或逆序)为O(n²) | O(n log n) | O(log n)(递归栈空间) | 不稳定 |
| 选择排序 | 数据规模小,对稳定性要求不高 | O(n²) | O(n²) | O(n²) | O(1)(原地排序) | 不稳定 |
| 堆排序 | 对数据稳定性要求不高,且数据规模较大的情况 | O(n log n) | O(n log n) | O(n log n) | O(1)(原地排序) | 不稳定 |
| 归并排序 | 对稳定性有要求,且数据规模适中,内存空间充足的情况 | O(n log n) | O(n log n) | O(n log n) | O(n)(需额外空间存储子数组) | 稳定 |
| 基数排序 | 数据为整数或可以表示为整数的字符串,且位数相差不大时,尤其是数据规模大但k相对较小的情况,k为最大元素的位数(或字符长度) | O(nk),其中n为元素个数,k为最大元素的位数 | O(nk) | O(nk) | O(n+k) | 稳定 |
| 桶排序 | 数据均匀分布且能确定合适的桶划分规则时,尤其是数据规模大且能有效利用数据分布特性的场合 | 取决于桶内排序算法,理想情况下桶内排序为O(1),总体为O(n + k) | 取决于桶内排序算法 | 取决于桶内排序算法 | O(n + k) | 取决于桶内排序算法的稳定性 |
| 计数排序 | 数据范围有限且值分布均匀,且k远小于n时,其中n为元素个数,k为最大值与最小值之差 | O(n+k) | O(n+k) | O(n+k) | O(k) | 稳定 |