1.希尔排序
原理:1.选定一个增长量h,按照增长量h作为数据分组的依据,对数据进行分组;
2.对分好组的每一组数据完成插入排序;
3.减小增长量,最小减为1,重复第二步操作
代码实现:
public class Shell {
public static void sort(Comparable[] a) {
int h=1;
// 确定增常量的最大值
while(h<a.length/2) {
h=h*2+1;
}
while(h>=1) {
for(int i=h;i<a.length;i++) {
for(int j=i;j>=h;j-=h) {
if(greater(a[j-h],a[j])) {
exch(a,j-h,j);
}
else {
break;
}
}
}
h=h/2;
}
}
public static boolean greater(Comparable v,Comparable w) {
return v.compareTo(w)>0;
}
public static void exch(Comparable[] a,int i,int j) {
Comparable tem;
tem=a[i];
a[i]=a[j];
a[j]=tem;
}
希尔排序的时间复杂度为O(n*log2n)
2.归并排序
原理:
1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是 1为止。
2.将相邻的两个子组进行合并成一个有序的大组;
3.不断的重复步骤2,直到最终只有一个组为止。
代码实现:
public class Merge {
private static Comparable[] assist;
public static boolean less(Comparable v,Comparable w) {
return v.compareTo(w)<0;
}
public static void exch(Comparable[] a,int i,int j) {
Comparable tem=a[i];
a[i]=a[j];
a[j]=tem;
}
public static void sort(Comparable[] a) {
assist=new Comparable[a.length];//临时数组,用来储存按指定要求排好后的次序的数组
int lo=0;
int hi=a.length-1;
sort(a,lo,hi);
}
public static void sort(Comparable[] a,int lo,int hi) {
if(hi<=lo) {
return;
}
int mid=lo+(hi-lo)/2;
// 递归调用
sort(a,lo,mid);
sort(a,mid+1,hi);
merge(a,lo,mid,hi);
}
public static void merge(Comparable[] a,int lo,int mid,int hi) {
int i=lo;
int p1=lo;//左指针:用来记录左半数组遍历的位置
int p2=mid+1;//右指针:用来记录右半数组遍历的位置
while(p1<=mid&&p2<=hi) {
if(less(a[p1],a[p2])) {
assist[i++]=a[p1++];
}else {
assist[i++]=a[p2++];
}
}
// 当p2走完右半部分时,将左半部分的剩余的值,直接放到临时数组里面
while(p1<=mid) {
assist[i++]=a[p1++];
}
// 当p1走完左半部分时,将右半部分的剩余的值,直接放到临时数组里面
while(p2<=hi) {
assist[i++]=a[p2++];
}
for(int index=lo;index<=hi;index++) {
a[index]=assist[index];
}
}
归并排序的时间复杂度为O(n*log2n)
3.快速排序
原理:
1.首先设定一个分界值,通过该分界值将数组分成左右两部分;
2.将大于或等于分界值的数据放到到数组右边,小于分界值的数据放到数组的左边。此时左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值;
3.
然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两
部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
4.
重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当
左侧和右侧两个部分的数据排完序后,整个数组的排序也就完成了。
![](https://img-blog.csdnimg.cn/366ebe9c15894060b4a19e4562cbfc52.png)
代码实现:
public class Quick {
private static boolean less(Comparable v,Comparable w) {
return v.compareTo(w)<0;
}
public static void exch(Comparable[] a,int i,int j) {
Comparable tem=a[i];
a[i]=a[j];
a[j]=tem;
}
public static void sort(Comparable[] a) {
int lo=0;
int hi=a.length-1;
sort(a,lo,hi);
}
public static void sort(Comparable[] a,int lo,int hi) {
if(hi<=lo) {
return;
}
int partition=paratition(a, lo,hi);
sort(a,lo,partition-1);
sort(a,partition+1,hi);
}
public static int paratition(Comparable[] a,int lo,int hi) {
Comparable key=a[lo];
int left=lo;
int right=hi+1;
while(true) {
//先从右往左扫描,找到一个比基准值小的元素
while(less(key,a[--right])) {
if(right==lo) {
break;
}
}
//先从左往右扫描,找到一个比基准值大的元素
while(less(a[++left],key)) {
if(left==hi) {
break;
}
}
// 扫描完所有的元素,结束循环
if(left>=right) {
break;
}else {
exch(a,left,right);
}
}
//交换最后rigth索引处和基准值所在的索引处的值
exch(a,lo,right);
return right;//right就是切分的界限
}
}
快速排序平均情况的时间复杂度为O(n*longn) ,最差的时间复杂度为O(n^2)。
基数排序:
注意:基数排序和其它排序有所不同,它只能对数字(整数)进行排序
public class RadixSort {
//交换元素
private static void swap(int[] arr,int i,int j){
int tem=arr[i];
arr[i]=arr[j];
arr[j]=tem;
}
//向数组中添加元素
private static int []arrAppend(int[] arr,int x){
arr= Arrays.copyOf(arr,arr.length+1);
arr[arr.length-1]=x;
return arr;
}
//复制一个新数组
private static int[] copy(int[] arr){
int[] tmp=new int[arr.length];
System.arraycopy(arr,0,tmp,0,arr.length);
return tmp;
}
//得到数组中最大值的长度
private static int getMaxDigit(int[] arr){
int max=0;
for (int i = 0; i < arr.length; i++) {
max=Math.max(max,arr[i]);
}
int x=max;
int ans=0;
if(x==0){
return ans;
}
while(x>0){
ans++;
x=x/10;
}
return ans;
}
//排序
public static void sort(int[] arr){
int maxDigit=getMaxDigit(arr);
int mod=10;
int div=1;
for(int i=0;i<maxDigit;++i,mod*=10,div*=10){
int[][] tmp=new int[10][0];
for (int j = 0; j < arr.length; j++) {
int bucket=arr[j]%mod/div;
tmp[bucket]=arrAppend(tmp[bucket],arr[j]);
}
int index=0;
for(int[] k:tmp){
for(int value:k){
arr[index++]=value;
}
}
}
}
}
基数排序时间复杂度:O(n)