排序
1.时间复杂度为O(n)的排序,计数排序,桶排序,基数排序
时间复杂度为O(n)的排序,计数排序,桶排序,基数排序
时间复杂度为O(n)的三种排序算法
比较
1.时间复杂度比较
稳定性:
稳定性
稳定性是指,比如a在b前面,a=b,排序后,a仍然应该在b前面,这样就算稳定的。
桶排序中,假如升序排列,a已经在桶中,b插进来是永远都会a右边的(因为一般是从右到左,如果不小于当前元素,则插入改元素的右侧)
所以桶排序是稳定的
PS:当然了,如果采用元素插入后再分别进行桶内排序,并且桶内排序算法采用快速排序,那么就不是稳定的
稳定性算法: 基数排序 , 直接插入排序 , 冒泡排序, 归并排序
不稳定性算法: 桶排序(不确定), 二分插入排序,希尔排序, 快速排序, 简单选择排序,堆排序
算法 | 乱序时间复杂度 | 有序时间复杂度 |
---|---|---|
插入排序 | O(N^2) | O(N) |
希尔排序 | O(N^2) | O(N) |
冒泡排序 | O(N^2) | O(N) |
基数排序 | O(N) | O(N) |
桶排序 | O(N) | |
计数排序 | O(N) | |
归并排序 | O(NlogN) | O(NlogN) |
快速排序 | O(NlogN) | O(N^2) |
堆排序 | O(NlogN) |
2.空间复杂度比较
算法 | 空间复杂度 |
---|---|
插入排序 | O(1) |
希尔排序 | O(1) |
冒泡排序 | O(1) |
基数排序 | O(N) |
桶排序 | O(N+M) M是额外辅助空间(桶数量) |
计数排序 | O(N) |
归并排序 | O(N) |
快速排序 | O(1) |
堆排序 | O(1) |
各种排序的代码实现及其排序一轮后的效果(选择)
插入排序
分为排好序和未排好序,未排好序的跟排好序的从右往左比较,找到合适的位置插入。
import java.util.Arrays;
public class Insert {
public static int[] insertSort(int[] arr) {
if(arr==null ||arr.length==0)
return null;
for(int i=1;i<arr.length;i++) {
int tmp = arr[i];
int j;
for(j=i;j>0 && arr[j-1]>tmp;j--) {
arr[j] =arr[j-1];
}
arr[j] = tmp;
}
return arr;
}
public static void main(String[] args) {
int[] array = {38,65,97,76,13,27,49};
System.out.println("排序前的数据为:");
System.out.println(Arrays.toString(array));
System.out.println("排序后的数据为:");
System.out.println(Arrays.toString(insertSort(array)));
}
}
快速排序
总体递归:
利用快速排序的结果是左边比基准元素小,右边比基准元素大。分为左右两端,不断递归。
非递归:思想是 两个指针互相比较的思想,在编程题中很常用。
快排的延申:由快速排序得到的查找数组中第K小的元素的算法:
import java.util.Arrays;
public class QuickSort {
public static void quicksort(int [] nums,int left,int right) {
if(left>=right)
return;
int privotIndex = partion(nums,left,right);
// System.out.println(Arrays.toString(nums));
// System.out.println(Arrays.toString(nums));
quicksort(nums,left,privotIndex-1);
quicksort(nums,privotIndex+1,right);
}
public static int partion(int[] nums,int left,int right) {
//进行排序交换,并返回基准元素的位置
int privot = nums[left];
int i=left;
//int i =left+1;易错点:这样会造成已经排好序的与left+1再次交换
int j =right;
while(i!=j) {
while(i<j && nums[j]>privot) {
j--;
}
while(i<j && nums[i]<=privot) {
i++;
}
if(i<j) {
int tmp = nums[i];
nums[i] =nums[j];
nums[j] =tmp;
}
}
int tmp = privot;
nums[left] =nums[i];
nums[i] =tmp;
return i;
}
//由快速排序得到的查找数组中第K小的元素的算法:
public static int Select(int[] nums,int k) {
int i=0;
int j=nums.length-1;
while(i<j) {
int temp = partion(nums,i,j);
if(temp<k-1)
i= temp+1;
else if(temp>k-1)
j=temp-1;
else
return nums[k-1];
}
return nums[k-1];
}
public static void main(String[] args) {
int[] nums = new int[] {4,7,6,5,3,2,8,1};
// int[] nums = new int[] {6, 5, 7, 8};
// int[] nums = new int[] {8,1,4,9,0,3,5,2,7,6};
quicksort(nums,0,nums.length-1);
System.out.println(Arrays.toString(nums));
System.out.println(Select(nums,3));
}
}
希尔排序
import java.util.Arrays;
public class XiEr {
public static void sort(int [] arr) {
int d = arr.length;
while(d>1) {
d= d/2;
for(int x=0;x<d;x++) {
for(int i =x+d;i<arr.length;i=i+d) {
int tmp = arr[i];
int j;
for(j=i-d;j>=0&&arr[j]>tmp;j=j-d) {//j>=0,而不是j>0
arr[j+d] =arr[j];
}
arr[j+d] = tmp;
}
}
}
}
public static void main(String[] args) {
int[] arr = {5,3,9,12,6,1,7,2,4,11,8,10};
sort(arr);
System.out.println(Arrays.toString(arr));
}
}
计数排序
小灰的计数排序](https://mp.weixin.qq.com/s/WGqndkwLlzyVOHOdGK7X4Q)
普通
import java.util.Arrays;
public class jishu1 {
public static int[] countSort(int[] array) {
//1.得到数列的最大值
int max = array[0];
for(int i=1;i<array.length;i++) {
if(array[i]>max) {
max = array[i];
}
}
//2.根据数列的最大值确定统计数组的长度
int[] countArray = new int[max+1];
//3.遍历数列,填充统计数组
for(int i =0;i<array.length;i++) {
countArray[array[i]]++;
}
//System.out.println(Arrays.toString(countArray));
//4.遍历统计数组,输出结果
int index = 0;
int [] sortedArray = new int [array.length];
for(int i=0;i<countArray.length;i++) {
for(int j =0;j<countArray[i];j++) {
sortedArray[index++] =i;
}
}
return sortedArray;
}
public static void main(String[] args) {
int[] array = new int [] {4,4,6,5,3,2,8,1,7,5,6,0,10};
int[] sortedArray = countSort(array);
System.out.println(Arrays.toString(sortedArray));
}
}
90,91…分布
public class jishuyouhua {
public static int[] countSort(int[] array) {
//1.得到数列的最大值和最小值,并计算差值d
int max = array[0];
int min = array[0];
for(int i = 1;i<array.length;i++) {
if(array[i]>max) {
max = array[i];
}
if(array[i]<min) {
min = array[i];
}
}
int d = max - min;
//2.创建统计数组并统计对应元素的个数
int[] countArray = new int[d+1];
for(int i =0;i<array.length;i++) {
countArray[array[i] - min]++;
}
int index = 0;
int [] sortedArray = new int [array.length];
for(int i=0;i<countArray.length;i++) {
for(int j =0;j<countArray[i];j++) {
sortedArray[index++] =i+min;
}
}
return sortedArray;
}
public static void main(String[] args) {
int[] array = new int [] {95,94,91,98,99,90,99,93,91,92};
int[] sortedArray = countSort(array);
System.out.println(Arrays.toString(sortedArray));
}
}
改进:稳定排序
统计数组做变形,后面的元素等于前面元素之和:相同的元素可以按照固定顺序排列
public class jishuyouhua {
public static int[] countSort(int[] array) {
//1.得到数列的最大值和最小值,并计算差值d
int max = array[0];
int min = array[0];
for(int i = 1;i<array.length;i++) {
if(array[i]>max) {
max = array[i];
}
if(array[i]<min) {
min = array[i];
}
}
int d = max - min;
//2.创建统计数组并统计对应元素的个数
int[] countArray = new int[d+1];
for(int i =0;i<array.length;i++) {
countArray[array[i] - min]++;
}
// System.out.println(Arrays.toString(countArray));
//3.统计数组做变形,后面的元素等于前面元素之和
for(int i =1;i<countArray.length;i++) {
countArray[i] +=countArray[i-1];
}
// System.out.println(Arrays.toString(countArray));
//4.倒序遍历原始数列,从统计数组找到正确位置,输出到结果数组
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]--;
}
return sortedArray;
}
堆排序
//堆排序,不稳定,时间O(nlogn),空间O(1)
import java.util.Arrays;
public class Heap {
public static void heapContrust(int[] arr) {
//初始化堆,构建大顶堆
for(int i=0;i<arr.length;i++) {
int childindex = i;
int fatherindex = (childindex - 1)/2;
while(arr[childindex] > arr[fatherindex]) {
int tmp = arr[childindex];
arr[childindex] = arr[fatherindex];
arr[fatherindex] = tmp;
childindex = fatherindex;
fatherindex = (childindex - 1)/2;
}
}
}
public static void heapAdjust(int[] arr, int index,int size) {
int left = 2*index + 1;
int right = 2*index + 2;
while(left < size) {
int maxIndex;
if(arr[left] < arr[right] && right < size)
maxIndex = right;
else
maxIndex = left;
if(arr[index] > arr[maxIndex])
maxIndex = index;
if(index == maxIndex)
break;
int tmp = arr[maxIndex];
arr[maxIndex] = arr[index];
arr[index] = tmp;
index = maxIndex;
left = 2*index + 1;
right = 2*index + 2;
}
}
public static void heapSort(int[] arr) {
heapContrust(arr);
int size = arr.length;
while(size > 0) {
int tmp = arr[0];
arr[0] = arr[size-1];
arr[size-1] = tmp;
size --;
heapAdjust(arr, 0, size);
}
}
public static void main(String[] args) {
int[] arr = {3,6,8,5,7,3,9,2};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
}
需要修改:
最好引入 swap函数, 因为交换使用比较多。