java十大经典算法

java十大经典算法1.希尔排序希尔排序是插入排序的改进,不必再像插入排序一样一个一个比较再交换,它的精髓在于增量交换,因此又叫做缩小增量排序。常用初始增量为len/2,这样就把所有元素分为了若干组,每次通过比较、交换相差增量的元素,然后缩小增量,重复这个过程直至增量变为1,这样每一个元素都排好了位置。希尔排序的时间

大家好,欢迎来到IT知识分享网。

1.希尔排序

希尔排序是插入排序的改进,不必再像插入排序一样一个一个比较再交换,它的精髓在于增量交换,因此又叫做缩小增量排序。常用初始增量为len/2,这样就把所有元素分为了若干组,每次通过比较、交换相差增量的元素,然后缩小增量,重复这个过程直至增量变为1,这样每一个元素都排好了位置。希尔排序的时间复杂度为O(nlogn),是首个时间复杂度冲破O(n^2)的算法。

下面是它的java代码实现

@Test
public void sort(){
    int []array = new int[100000];
    Random random = new Random();
    for (int i =0;i < 100000;i++){
        array[i]= random.nextInt(9000000);
    }
    //实现
    for (int d = array.length/2 ; d > 0 ; d/=2) {//初始增量d为len/2,每次缩小一半直至最后为1
        for (int i = d ;i<array.length;i++){//循环每一个分组
          for (int j = i-d;j>=0 && array[j+d]<array[j];j-=d){//同一组且相邻增量的元素比较大小并交换,此循环结束代表该组的大小排序完成
              swap(array,j,j+d);
          }
        }
    }
    log.info(Arrays.toString(array));
}
//交换元素
void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
经过测试,10w个元素的数组使用希尔排序耗时436ms
java十大经典算法
2.插入排序

看不懂希尔排序的话,不如先看看插入排序,插入排序顾名思义,把最小或最大的元素插入到合适的位置直至遍历所有元素即可。也就是说插入排序要把第一个元素看作是有序的,从第二个元素开始和前一个元素比较

大小,若符所有元素即可。也就是说插入排序要把第一个元素看作是有序的,从第二个元素开始和前一个元素比较大小,若符合条件则交换他们,重复这个过程直到不符合条件为止,这样一来这个元素之前的都是有序的
,之后的都是无序的。重复这个过程直到最后一个元素比较完,排序就结束了。插入排序时间复杂度为O(n^2)

下面是代码实现

@Test
public void sort(){
    int []array = new int[100000];
    Random random = new Random();
    for (int i =0;i < 100000;i++){
        array[i]= random.nextInt(9000000);
    }
    //实现
    for (int i = 1;i<array.length;i++){
        for (int j = i-1;j>=0;j--){
            if (array[j+1]<array[j]){
                swap(array,j,j+1);
            }
        }
    }
    log.info(Arrays.toString(array));
}
经过测试,10w个元素的数组使用插入排序耗时10s175ms
java十大经典算法

 

是不是相差挺大的,当数据量小的时候两个算法差异还差不多,数据量大起来,耗费的时间只会越拉越大。不过细心的小伙伴已经发现了,内层循环里面的逻辑仅仅只有一个交换逻辑,所以这个代码可以优化成下面的样子

 //实现
for (int i = 1;i<array.length;i++){
    for (int j = i-1; j>=0 && array[j+1]<array[j] ;j--){
        swap(array,j,j+1);
    }
}
优化后的代码耗时4s232ms
java十大经典算法

 这样的话代码就是最优的了

3.归并排序

归并排序典型的运用了分治法、递归的思想,但是它需要用到额外的内存空间,简单来说需要不断的分割原数组至所有元素只剩一个,然后比较大小把值赋给中间数组,最后中间数组把值赋值给原数组。由于运用了

递归的思想,只需要每次将数组分割为两份,直至所有数组里的元素只剩一个,然后比较大小递归的合并他们。这样中间数组的值就已经全部有序,最后将中间数组复制给原数组,排序就结束了。说着很简单,让我

们来看看代码实现

@Test
public void sort(){
    int []array = new int[200000];
    Random random = new  Random();
    for (int i =0;i < 200000;i++){
        array[i]= random.nextInt(9000000);
    }
    //实现
    int length = array.length;
    int []tmp = new int[length];
    mergeSort(array,0,length-1,tmp);
    log.info(Arrays.toString(array));
}
void mergeSort(int []array, int left ,int right, int []tmp){
    int mid = (left+right)/2;
    if (left<right){//拆分至每组只有一个元素
        mergeSort(array, left, mid, tmp);
        mergeSort(array, mid+1, right, tmp);
        merge(array, left, right, tmp);
    }
}

void merge(int []array, int left ,int right ,int []tmp){
    int mid = (left+right)/2;
    int i = left; //左哨兵
    int j = mid +1;//右哨兵
    int index = 0;//中间数组下标
    while (i<=mid && j<=right){//左右两个哨兵指向的值比较大小并存入中间数组,总有一个哨兵走到尽头,跳出循环
        if (array[i]<=array[j]){
            tmp[index++]=array[i++];
        }else {
            tmp[index++]=array[j++];
        }
    }
    while (j<=right){//左哨兵走到尽头,右哨兵剩余未走的值全部复制给中间数组
        tmp[index++]=array[j++];
    }
    while (i<=mid){//右哨兵走到尽头,左哨兵剩余未走的值全部复制给中间数组
        tmp[index++]=array[i++];
    }
    index = 0;
    while(left<=right){//把中间数组的值复制给原数组
        array[left++] = tmp[index++];
    }
}

经过测试,20w条数据,归并排序仅需要564ms,真是越来越快了呢~

java十大经典算法

 

4.快速排序

快速排序是冒泡的改进,也采用了分治的思想。最差情况时间复杂度也是O(n^2),平均时间复杂度为O(nlogn)

上代码,注意,这里的代码采用递归的方式实现


@Test
public void sort(){
    int []array = new int[200000];
    Random random = new  Random();
    for (int i =0;i < 200000;i++){
        array[i]= random.nextInt(900000);
    }
    //实现
    quicksort(array,0,array.length-1);
    log.info(Arrays.toString(array));
}
void quicksort(int[] array, int left, int right){
    if (left>=right){
        return;
    }
    int i = left;//左哨兵
    int j = right;//右哨兵
    int index  = array[left];//采用第一个元素作为基准

    while (i<j){
        while (i<j && array[j]>=index){//右边的要全部大于基准,否则跳出循环
            j--;
        }
        while (i<j && array[i]<=index){//左边的要全部小于基准,否则跳出循环
            i++;
        }
        swap(array,i,j);//交换左右哨兵的值
    }
    swap(array,left,i);//将基准数放到哨兵相遇的位置,这样基准左边的全部小于它,右边的全部大于它,递归的执行就能完成排序
    quicksort(array,left,i-1);
    quicksort(array,i+1,right);
}
java十大经典算法

 20w的数据执行485ms

5.堆排序

堆排序是采用了堆这种数据结构而产生的算法,他的最坏最好的时间复杂度均为O(nlogn),也是不稳定排序。首先,堆是一个顺序存储的完全二叉树,每个结点的值都大于叶子的值则为大根堆,反之则为小根堆。

它的性质如下:如果根结点索引为i,左孩子为2i+1,右孩子为2i+2。它的第一个非叶子结点为i/2-1.

堆排序的主要流程为:首先将一个无序数组转换为大根堆(或小根堆,取决于降序还是升序)。转换好之后,将第一个结点和最后一个结点交换,然后固定最后一个结点,这样除开最后一个结点外的堆有可能不符合大根堆(或小根堆),所以要将它再次变为大根堆(或小根堆),重复这个过程直至整个堆的根结点,排序也就结束了。根据这个流程,我们需要写两个方法,一个就是将局部堆转换为大根堆(或小根堆),另一个就是遍历整个堆。

下面是它的代码实现:

@Test
public void sort(){
    int []array = new int[200000];
    Random random = new Random();
    for (int i =0;i < 200000;i++){
        array[i]= random.nextInt(90000000);
    }
    //实现
    heapsort(array);
    log.info(Arrays.toString(array));
}
 //堆排序
 void heapsort(int []arr){
    //1.构建大顶堆
    for(int i=arr.length/2-1;i>=0;i--){//arr.length/2-1代表第一个非叶子结点
        //从第一个非叶子结点从下至上,从右至左调整结构
        headAdjust(arr,i,arr.length);
    }
    //2.调整堆结构+交换堆顶元素与末尾元素
    for(int j=arr.length-1;j>0;j--){
        swap(arr,0,j);//将堆顶元素与末尾元素进行交换
        headAdjust(arr,0,j);//重新对堆进行调整
    }
}
//注意,该方法仅调整堆的局部
private static void headAdjust(int[] arr, int i, int len) {//i为非叶子结点
    int tmp = arr[i];//保存这个时候结点的值,相当于挖一个坑,后面让符合条件的孩子来填补
    for (int k = 2*i+1; k < len ;k = 2*k+1){//k为该非叶子结点的左孩子,k=2k+1是为了遍历该结点下的左孩子
        if (k+1<len && arr[k]<arr[k+1]){//相当于筛选出左右孩子里最大的那个孩子
            k++;
        }
        if (arr[k] > tmp){//若孩子比父结点的值大,则将孩子的值移到父结点,然后让i指向该孩子
            arr[i] = arr[k];
            i = k;
        }
    }
    arr[i] = tmp;//这里的i指向孩子
}

java十大经典算法

 20w的数据耗时537ms

总结:堆排序算法主要是针对非叶子结点的排序,从第一个非叶子结点(从下往上)开始,循环每一个非叶子结点后就能得到排好序后的数组了

 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/30130.html

(0)
上一篇 2023-10-15 11:45
下一篇 2023-10-15 19:15

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信