目录
题目描述
给你一个整数数组 nums,请你将该数组升序排列。
示例 1:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
示例 1:
输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]
各种解法
- 比较排序:元素之间的次序依赖于他们之间的比较,比较之后才能确定自己的位置。优势在于不在于数据的分布,适用于一切需要排序的情况。
- 非比较排序:通过确定每个元素的位置之前,应该有多少个元素,从而确定自己的位置。所以一次遍历就能实现排序。但是需要占用空间来确定唯一位置,对数据规模和数据分布有一定的要求。
1. 冒泡排序
// 1. 冒泡排序
public int[] bubbleSort(int[] array){
if(array.length == 0){
return array;
}
for(int i=0; i<array.length; i++){
for(int j=0; j<array.length-1-i; j++){
if(array[j]>array[j+1]){
swap(array, j, j+1);
}
}
}
return array;
}
2. 快速排序
// 2. 快速排序
public int[] quickSort(int[] array, int left, int right){
int dp;
if(left<right){
dp = partition(array, left, right);
quickSort(array, left, dp-1);
quickSort(array, dp+1, right);
}
return array;
}
public int partition(int[] array, int left, int right){
int pivot = array[left];
while(left<right){
while(left<right && array[right]>pivot) right--;
if(left<right) array[left++] = array[right];
while(left<right && array[left]<pivot) left++;
if(left<right) array[right--] = array[left];
}
array[left] = pivot;
return left;
}
3. 插入排序
// 3. 插入排序
public int[] insertSort(int[] array){
if(array.length == 0) return array;
int cur;
for(int i=0; i<array.length-1; i++){
cur = array[i+1];
int preIndex = i;
while(preIndex>=0 && array[preIndex]>cur){
array[preIndex+1] = array[preIndex];
preIndex--;
}
array[preIndex+1] = cur;
}
return array;
}
4. 希尔排序
// 4. 希尔排序
public int[] shellSort(int[] array){
if(array.length == 0) return array;
int length = array.length;
int temp, gap = length/2;
while(gap>0){
for(int i=gap; i<length; i++){
temp = array[i];
int preIndex = i-gap;
while(preIndex>=0 && temp<array[preIndex]){
array[preIndex+gap] = array[preIndex];
preIndex -= gap;
}
array[preIndex+gap] = temp;
}
gap /= 2;
}
return array;
}
5. 选择排序
// 5. 选择排序
public int[] selectionSort(int[] array){
if(array.length == 0) return array;
for(int i=0; i<array.length; i++){
int minIndex = i;
for(int j=i; j<array.length; j++){
if(array[j]<array[minIndex]) minIndex=j;
}
swap(array, minIndex, i);
}
return array;
}
6. 堆排序
// 6. 堆排序
public int[] heapSort(int[] array){
if(array.length == 0) return array;
for(int i=array.length/2-1; i>=0; i--){
adjustHeap(array, i, array.length);
}
for(int j=array.length-1; j>0; j--){
swap(array, 0, j);
adjustHeap(array, 0, j);
}
return array;
}
public void adjustHeap(int[] array, int i, int length){
int temp = array[i];
for(int k=2*i+1; k<length; k=2*k+1){
if(k+1<length && array[k+1]>array[k]) k++;
if(array[k]>temp){
swap(array, i, k);
i = k;
}else break;
}
}
7. 归并排序
// 7. 归并排序
public int[] mergeSort(int[] array, int left, int right){
if(array.length == 0) return array;
if(left<right){
int mid = left+(right-left)/2;
mergeSort(array, left, mid);
mergeSort(array, mid+1, right);
merge(array, left, mid, right);
}
return array;
}
public void merge(int[] array, int left, int mid, int right){
int[] tempArr = new int[array.length];
int leftStart = left;
int rightStart = mid+1;
int tempIndex = left;
while(leftStart<=mid && rightStart<=right){
if(array[leftStart]<array[rightStart]){
tempArr[tempIndex++] = array[leftStart++];
}else{
tempArr[tempIndex++] = array[rightStart++];
}
}
while(leftStart<=mid){
tempArr[tempIndex++] = array[leftStart++];
}
while(rightStart<=right){
tempArr[tempIndex++] = array[rightStart++];
}
while(left<=right){
array[left] = tempArr[left++];
}
}
8. 计数排序
// 8. 计数排序
public int[] countSort(int[] array){
int max = array[0];
int min = array[0];
for(int i=0; i<array.length; i++){
if(array[i]>max){
max = array[i];
}
if(array[i]<min){
min = array[i];
}
}
int d = max-min;
// 每个数的个数
int[] countArray = new int[d+1];
for(int i=0; i<array.length; i++){
countArray[array[i]-min]++;
}
// 每个数的个数加上前面所有数的个数之和
for(int i=1; i<countArray.length; i++){
countArray[i]+=countArray[i-1];
}
// 排好序的数组
int[] sortedArray = new int[array.length];
for(int i=array.length-1; i>=0; i--){
sortedArray[countArray[array[i]-min]-1] = array[i];
countArray[array[i]-min]--;
}
for(int i=0; i<array.length; i++){
array[i] = sortedArray[i];
}
return array;
}
9. 桶排序
// 桶排序
public static void bucketSort(int[] a, int max) {
int[] buckets;
if (a==null || max<1)
return ;
// 创建一个容量为max的数组buckets,并且将buckets中的所有数据都初始化为0。
buckets = new int[max];
// 1. 计数
for(int i = 0; i < a.length; i++)
buckets[a[i]]++;
// 2. 排序
for (int i = 0, j = 0; i < max; i++) {
while( (buckets[i]--) >0 ) {
a[j++] = i;
}
}
buckets = null;
}
10. 基数排序
// 10. 基数排序
public int[] radixSort(int[] array){
int max = array[0];
int exp;
for(int arr: array){
if(arr>max) max = arr;
}
// 从个位开始
for(exp=1; max/exp>0; exp*=10){
int[] temp = new int[array.length];
int[] buckets = new int[10];
for(int value: array){
buckets[(value/exp)%10]++;
}
for(int i=1; i<10; i++){
buckets[i] += buckets[i-1];
}
for(int i=array.length-1; i>=0; i--){
temp[buckets[(array[i]/exp)%10]-1] = array[i];
buckets[(array[i]/exp)%10]--;
}
System.arraycopy(temp, 0, array, 0, array.length);
}
return array;
}
基数排序 vs 计数排序 vs 桶排序
- 基数排序:根据键值的每位数字来分配桶
- 计数排序:每个桶只存储单一键值
- 桶排序:每个桶存储一定范围的数值
排序算法复杂度及稳定性
- 稳定:两个相等的数,在排序后,相对位置不变
- 不稳定:两个相等的数,在排序后,相对位置变化
各排序算法适用的情况
- 包含大量重复的元素:三路快排
- 数据的取值范围非常有限:计数排序
- 要求稳定排序:归并就比快排好了
- 数据的存储情况的区别:
- 快排依赖于数组的随机存储
- 链表存储更适合归并排序
- 数据量很大或者内存很小,不足以装载在内存中,使用外排序算法。不用全部装载到内存中。