- 快排
快排原理:
在要排的数(比如数组A)中选择一个中心值key(比如A[0]),通过一趟排序将数组A分成两部分,其中以key为中心,key右边都比key大,key左边的都key小,然后对这两部分分别重复这个过程,直到整个有序。
最优的情况下,快速排序算法的时间复杂度为O(nlogn);最坏情况时间复杂度为O(n²),快速排序的平均时间复杂度为O(n×log(n))。
public static int partition(int []array,int lo,int hi){
int key=array[lo];//设置key
while(lo<hi){
while(array[hi]>=key&&hi>lo){//从后半部分向前扫描
hi--;
}
array[lo]=array[hi];
while(array[lo]<=key&&hi>lo){从前半部分向后扫描
lo++;
}
array[hi]=array[lo];
}
array[hi]=key;
return hi;
}
public static void sort(int[] array,int lo ,int hi){
if(lo>=hi){
return ;
}
int index=partition(array,lo,hi);
sort(array,lo,index-1);
sort(array,index+1,hi);
}
- 冒泡排序
分析冒泡算法最好情况是一趟排好,所以冒泡排序最好的时间复杂度为O(n);最坏情况为排到最后才排完,时间复杂度为O(n²)。所以冒泡排序的平均复杂度为O(n²) 。
for(int i=0;i<arr.length-1;i++){//外层循环控制排序趟数
for(int j=0;j<arr.length-1-i;j++){//内层循环控制每一趟排序多少次
if(arr[j]>arr[j+1]){
swap(arr[j],arr[j+1]);
}
}
}
- 归并排序
两路归并排序三个步骤:
第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素.
第二, 治理: 对每个子序列分别调用归并排序MergeSort, 进行递归操作
第三, 合并: 合并两个排好序的子序列,生成排序结果.
对长度为n的文件,需进行趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)。
public static int[] sort(int[] arr,int low,int high){
int mid = (low+high)/2;
if(low<high){
sort(arr,low,mid);
sort(arr,mid+1,high);
//左右归并
merge(arr,low,mid,high);
}
return arr;
}
public static void merge(int[] arr, int low, int mid, int high) {
int[] temp = new int[high-low+1];
int i= low;
int j = mid+1;
int k=0;
// 把较小的数先移到新数组中
while(i<=mid && j<=high){
if(arr[i]<arr[j]){
temp[k++] = arr[i++];
}else{
temp[k++] = arr[j++];
}
}
// 把左边剩余的数移入数组
while(i<=mid){
temp[k++] = arr[i++];
}
// 把右边边剩余的数移入数组
while(j<=high){
temp[k++] =arr[j++];
}
// 把新数组中的数覆盖nums数组
for(int x=0;x<temp.length;x++){
arr[x+low] = temp[x];
}
}
- 桶排序
桶排序中:无序数组有个要求,就是成员隶属于固定(有限的)的区间,即知道数组中的元素大致在哪个范围,如范围为0-9,0-99。
例如待排数字[6 2 4 1 5 9],准备10个空桶,最大数个空桶,数字几就放入几号空桶,对应后依次取值,跳过空桶即排序完成。
对于N个待排数据,M个桶,平均每个桶[N/M]个数据的桶排序平均时间复杂度为: O(N)+O(M*(N/M)log(N/M))=O(N+N(logN-logM))=O(N+NlogN-NlogM),当N=M时,即极限情况下每个桶只有一个数据时。桶排序的最好效率能够达到O(N)。
public static int[] bucketSort(int[] nums, int maxNum){
int[] sorted = new int[maxNum+1];
for(int i=0; i<nums.length; i++){
sorted[nums[i]] = nums[i];//把数据放到对应索引的位置
}
return sorted;
}
- 插入排序
直接插入排序的基本思想:在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
public void insertSort(int [] a){
int len=a.length;//单独把数组长度拿出来,提高效率
int insertNum;//要插入的数
for(int i=1;i<len;i++){//因为第一次不用,所以从1开始
insertNum=a[i];
int j=i-1;//序列元素个数
while(j>=0&&a[j]>insertNum){//从后往前循环,将大于insertNum的数向后移动
a[j+1]=a[j];//元素向后移动
j--;
}
a[j+1]=insertNum;//找到位置,插入当前元素
}
}
- 选择排序
选择排序的步骤:1.遍历整个序列,将最小的数放在最前面;2.遍历剩下的序列,将最小的数放在最前面;3.重复第二步,直到只剩下一个数。
时间复杂度为O(n²)
public void selectSort(int[]a){
int len=a.length;
for(int i=0;i<len;i++){//循环次数
int value=a[i];
int position=i;
for(int j=i+1;j<len;j++){//找到最小的值和位置
if(a[j]<value){
value=a[j];
position=j;
}
}
a[position]=a[i];//进行交换
a[i]=value;
}
}