java常用的排序算法(部分)

我在首次技术面试中就被问到了排序算法中效率的问题,我当时
只会冒泡排序与选择排序两种排序算法,很无奈,我没有通过技术面,
因而我对常用的排序算法进行了学习,快排为重点,面试经常遇到。
当然,我在这里只介绍了六种,剩下的我会后续跟进。有问题的地方
希望大家多多指点。

1、直接插入排序
我们经常会到这样一类排序问题:把新的数据插入到已经排好的数据列中。
将第一个数和第二个数排序,然后构成一个有序序列将第三个数插入进去,
构成一个新的有序序列。对第四个数、第五个数……直到最后一个数,重复第二步。

直接插入排序的基本思想:
在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经
是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。
如此反复循环,直到全部排好顺序。

缺点:多次的移动,假如一个很小的数在最右端的位置,那么要将该数据排序到正确的位置上,
则所有的中间数据都要向右移动一位。

代码实现:
首先设定插入次数,即循环次数,for(int i=1;i<length;i++),1个数的那次不用插入。
设定插入数和得到已经排好序列的最后一个数下标值。insertNum和j=i-1。
从最后一个数开始向前循环,如果插入数小于当前数,就将当前数向后移动一位。
将当前数放置到空着的位置,即j+1。

```
import java.util.Arrays;

public class ChaRu {
    public static 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;//找到位置,插入当前元素
                     }
        System.out.println(Arrays.toString(a));
             }

    public static void main(String[] args) {
        ChaRu.insertSort(new int[]{32,21,45,20,19,48,12});
    }
}
```
2、希尔排序
针对直接插入排序的效率低下问题,有人对次进行了改进与升级,这就是现在的希尔排序。希尔排序,
也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。

算法基本思想:
对于直接插入排序问题,数据量巨大时
将数的个数设为n,取奇数k=n/2,将下标差值为k的数分为一组,构成有序序列。
再取k=k/2 ,将下标差值为k的书分为一组,构成有序序列。
重复第二步,直到k=1执行简单插入排序。 

优点:希尔排序通过加大插入排序中元素之间间隔,并对这些间隔的元素进行插入排序,
从而使得数据可以大幅度的移动,当完成该间隔的排序后,希尔排序会减少数据的间隔
再次进行排序。依次进行下去。

代码实现:
首先确定分的组数。
然后对组中元素进行插入排序。
然后将length/2,重复1,2步,直到length=0为止。
```
import java.util.Arrays;

public class XiEr {
    public static void sheelSort(int[] arr){
        int d=arr.length;
        while (d!=0){
            d=d/2;
            //分组的数目
            for (int x=0;x<d;x++){
                //组中的元素,从第二个开始
                for (int i=x+d;i<arr.length;i+=d){
                    //j为有序序列的最后一个元素的下标
                    int j=i-d;
                    //要插入的数
                    int temp=arr[i];
                    //从后往前遍历
                    for (;j>=0&&temp<arr[j];j-=d){
                        //向后移动d个单位
                        arr[j+d]=arr[j];
                    }
                    //找到位置,插入值
                    arr[j+d]=temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }

    public static void main(String[] args) {
        XiEr.sheelSort(new int[]{32,21,45,20,19,48,12});
    }
}

```
3、快速排序(要求时间最快时)

算法基本思想:
选择第一个数为key,小于key的数放在左边,大于key的数放在右边。
递归的将key左边和右边的数都按照第一步进行,直到不能递归。

代码实现:
```

import java.util.Arrays;

public class KuaiPai {
    public static void main(String[] args){
        int[] a = new int[]{32,21,45,20,19,48,12};
        int start = 0;
        int end = a.length-1;
        sort(a,start,end);
        System.out.println(Arrays.toString(a));

    }

    public static void sort(int[] a,int low,int high){
        int start = low;
        int end = high;
        //左边第一个为基准值
        int key = a[low];
        while(end>start){
            //从后往前比较
            while(end>start&&a[end]>=key)  //如果没有比关键值小的,比较下一个,直到有比关键值小的交换位置,然后又从前往后比较
                end--;
            if(a[end]<=key){
                int temp = a[end];
                a[end] = a[start];
                a[start] = temp;
            }
            //从前往后比较
            while(end>start&&a[start]<=key)//如果没有比关键值大的,比较下一个,直到有比关键值大的交换位置
                start++;
            if(a[start]>=key){
                int temp = a[start];
                a[start] = a[end];
                a[end] = temp;
            }
            //此时第一次循环比较结束,关键值的位置已经确定了。左边的值都比关键值小,右边的值都比关键值大,但是两边的顺序还有可能是不一样的,进行下面的递归调用
        }
        //递归
        if(start>low) sort(a,low,start-1);//左边序列。第一个索引位置到关键值索引-1
        if(end<high) sort(a,end+1,high);//右边序列。从关键值索引+1到最后一个
    }

}

```
4、归并排序
速度仅次于快速排序,内存少的时候使用,可以进行并行计算的时候使用。
归并排序 (merge sort) 是一类与插入排序、交换排序、选择排序不同的另一种排序方法。
归并的含义是将两个或两个以上的有序表合并成一个新的有序表。归并排序有多路归并排序、
两路归并排序 , 可用于内排序,也可以用于外排序。这里仅对内排序的两路归并方法进行讨论。

算法基本思想:
分而治之(pide - conquer);每个递归过程涉及三个步骤
第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素.
第二, 治理: 对每个子序列分别调用归并排序MergeSort, 进行递归操作
第三, 合并: 合并两个排好序的子序列,生成排序结果.

代码实现:
```
import java.util.Arrays;

public class GuiBing {
    public static int[] sort(int[] a,int low,int high){
        int mid = (low+high)/2;
        if(low<high){
            sort(a,low,mid);
            sort(a,mid+1,high);
            //左右归并
            merge(a,low,mid,high);
        }
        return a;
    }

    public static void merge(int[] a, 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(a[i]<a[j]){
                temp[k++] = a[i++];
            }else{
                temp[k++] = a[j++];
            }
        }
        // 把左边剩余的数移入数组
        while(i<=mid){
            temp[k++] = a[i++];
        }
        // 把右边边剩余的数移入数组
        while(j<=high){
            temp[k++] = a[j++];
        }
        // 把新数组中的数覆盖nums数组
        for(int x=0;x<temp.length;x++){
            a[x+low] = temp[x];
        }
    }

    public static void main(String[] args) {
        int[] a = new int[]{32,21,45,20,19,48,12};
        int left = 0;
        int right= a.length-1;
        GuiBing.sort(a,left,right);
        System.out.println(Arrays.toString(a));
    }
}

```
5、冒泡排序

算法基本思想:
将序列中所有元素两两比较,将最大的放在最后面。
将剩余序列中所有元素两两比较,将最大的放在最后面。
重复第二步,直到只剩下一个数。

代码实现:
```
import java.util.Arrays;
//时间复杂度一般情况下为O(n2)
//原理:两两比较
public class MaoPao {
    public static void main(String[] args) {
        int[] arr=new int[]{32,21,45,20,19,48,12};
        //比较的轮次数为数组长度-1次,每循环一轮,内层的比较次数就会-1
        for (int j=0;j<arr.length-1;j++) {
            //第一轮循环下来,最大元素出现在最大索引处,-j为了防止下标越界
            for (int i = 0; i < arr.length - 1-j; i++) {
                int t;
                if (arr[i] > arr[i + 1]) {
                    t = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = t;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}
```
6、简单选择排序
常用于取序列中最大最小的几个数时。
(如果每次比较都交换,那么就是交换排序;如果每次比较完一个循环再交换,就是简单选择排序.)

算法基本思想:
遍历整个序列,将最小的数放在最前面。
遍历剩下的序列,将最小的数放在最前面。
重复第二步,直到只剩下一个数。

代码实现:
```
import java.util.Arrays;
//时间复杂度:O(n2)
public class XuanZe {
    //原理:一个元素与其他所有元素比较
    public static void main(String[] args) {
        int []arr=new int[]{32,21,45,20,19,48,12};
        for (int i=0;i<arr.length-1;i++){
            for (int j=i+1;j<arr.length;j++){
                if (arr[i]>arr[j]){
                    int t;
                    t=arr[i];
                    arr[i]=arr[j];
                    arr[j]=t;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}
```

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值