复习希尔排序,归并排序和快速排序

希尔排序

希尔排序是插入排序的优化,添加了增长量的概念,将相距某个“增量”的记录组成一个子序列,在子序列中进行插入排序,然后减小增量,重复上述操作,继续进行排序,直至增量为一。

对于增量,我们按照每次排序为数组的长度除以三减一(即 h=a.length/3-1 )每次的除以2,知道h为1.

分析

1.选定一个增量为h,以h为依据进行分组
2.每组进行插入排序
3.减小h的值,重复操作

在这里插入图片描述

代码实现

public class ShellTest1 {
    public static void main(String[] args) {
        int[] a={1,33,465,75,47,457856,8,56,8,5768,56,87,56,7,56,7};
        shell(a);
        System.out.println(Arrays.toString(a));
    }
    public static void shell(int[] a){
        //对数组中的元素进行分组
        int h = a.length/3-1;
        while (h>=1){
            //按照增量进行分组
            for (int i = h ;i<a.length;i++){
                //每次减小增量进行比较
                for (int j = i;j>=h;j-=h){
                    if (a[j]<a[j-h]){
                        int temp = a[j];
                        a[j]=a[j-h];
                        a[j-h]=temp;
                    }else{
                        break;
                    }
                }
            }
            //每次分组比较后减小h,知道减小为1
            h/=2;
        }
    }
}

结果

[1, 7, 7, 8, 8, 33, 47, 56, 56, 56, 56, 75, 87, 465, 5768, 457856]

稳定性和时间复杂度的分析

希尔排序是对插入排序的优化,在每次比较交换的时候只有结果为小于才会出现交换,所以希尔排序是稳定的。

希尔排序的时间复杂度是:O(nlogn)~O(n2),平均时间复杂度大致是O(n√n),可以用最坏的情况验证,将100000~1一次加入数组中,查看希尔排序与插入排序所需的时间。

归并排序

归并排序就是用归并的思想来实现,将一个队列分成一个个小的队列,完成一系列操作后在合并。

分析

1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是
1为止。
2.将相邻的两个子组进行合并成一个有序的大组;
3.不断的重复步骤2,直到最终只有一个组为止。
在这里插入图片描述

代码实现

public class Merge {
    public static void main(String[] args) {
        int[] a = {1,231,43,5,2,52,43,4,24,23};
        int[] temp = new int[a.length];
        merge(a);
        System.out.println(Arrays.toString(a));
    }
    public static void merge(int[] a){
        int left = 0 ;
        int rigth =a.length-1;
        int[] temp = new int[a.length];
        mergeDevide(a,left,rigth,temp);
    }
    //分解
    public static void mergeDevide(int[] a,int left , int right ,int[] temp){
        if (left<right){
            int mid = (right+left)/2;
            //向左递归分解
            mergeDevide( a, left , mid , temp);
            //向右递归分解
            mergeDevide(a,mid+1,right,temp);
            merge1(a,left,mid,right,temp);
        }
    }
    //合并
    /**
     *
     * @param a    需要排序的数组
     * @param left 左边临时数组的下标
     * @param mid  区分两个临时数组
     * @param right 右边数组的最后下标
     * @param temp 用来储存数据的临时数组
     */
    public static void merge1(int[] a , int left , int mid,int right,int[] temp){
        int i = left;
        int j = mid+1;
        int t = 0;
        //1.将两边的有序数据填充到temp中,直到有一方填充完毕
        while (i<=mid && j<=right){
            //左边的元素小于右边的元素,则将左边元素填充到temp中
            if (a[i]<a[j]){
                temp[t]=a[i];
                i+=1;
                t+=1;
            }else{//反之将左边的数据填充到temp中
                temp[t]=a[j];
                j+=1;
                t+=1;
            }
        }
        //2.将另一方剩下的数据填充到temp中
        while (i<=mid){
            //左边有剩余则把数组填充到temp中
            temp[t]=a[i];
            i+=1;
            t+=1;
        }
        while (j<=right){
            //右边有剩余则把数组填充到temp中
            temp[t]=a[j];
            j+=1;
            t+=1;
        }
        //3.将临时数组temp拷贝到a中
        t=0;
        int tempLeft =left;
        while (tempLeft<=right){
            a[tempLeft] = temp[t];
            t+=1;
            tempLeft+=1;
        }
    }
}

结果

[1, 2, 4, 5, 23, 24, 43, 43, 52, 231]

稳定性和时间复杂度的分析

归并排序在归并的过程中,只有arr[i]<arr[i+1]的时候才会交换位置,如果两个元素相等则不会交换位置,所以它并不会破坏稳定性,归并排序是稳定的

归并排序时间复杂度:O(n log n)

快速排序

快速排序是通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对两部分记录继续进行排序,以达到整个序列有序的目的。

分析

1.首先选择一个基准数,用来和其他的数据进行比较,一班都是用数据中的第一个数来作为基准数。
2.从这组数据的最后一个位置往前与基准数比较,如果比基准数大,则继续往前比较,否则与基准数交换位置。
3.用基准数的后一个数组与基准数比较,如果比基准数大,则交换位置,否则用下一个数据继续比较。
4.最终所有的数据都与基准数比较完。
在这里插入图片描述

代码实现

public class QuickTest{

    public static void main(String[] args) {
        int[] a={100,3,111,54,545,65,8,324,45,8789,12};

        quickSort(a);
        System.out.println(Arrays.toString(a));
    }

    /*
     * 首先需要一个数组存放所有的数据
     * 定一个开始位置和一个结束为止
     * 选择一个数作为准基数
     */
    public static void quickSort(int[] a){
        int min = 0;
        int max = a.length-1;
        sort(a,min,max);
    }
    public static void sort(int a[],int min,int max) {
        int key=a[min];//准基数
        int i=min; //开始位置
        int j =max;//结束位置

        while(j>i) {  //循环条件是否数值交叉
            //从后开始往前查找
            while(j>i&&a[j]>=key) {
                //如果找到的值大于基数值,那么继续往下找,end--
                j--;
            }
            //如果找到的值小于基数值,那么进行值交换
            if(a[j]<key) {
                int temp=a[j];
                a[j]=a[i];
                a[i]=temp;

            }
            //从前往后找
            while(j>i&&a[i]<=key) {
                //如果找到的值小于基数值,那么继续往下找,start++
                i++;
            }
            //如果找到的值大于基数值,那么进行值交换
            if(a[i]>key) {
                int temp=a[i];
                a[i]=a[j];
                a[j]=temp;

            }
        }
        //这部分的数据都是小于准基数,通过递归在进行一趟快排
        if(i>min) {
            sort(a, min, i-1);  //开始位置为第一位,结束位置为关键索引-1
        }

        if(j<max) {
            sort(a, j+1, max);  //开始位置为关键索引+1,结束位置最后一位
        }
    }
}

结果

[3, 8, 12, 45, 54, 65, 100, 111, 324, 545, 8789]

稳定性和时间复杂度的分析

快速排序需要一个基准值,在基准值的右侧找一个比基准值小的元素,在基准值的左侧找一个比基准值大的元素,然后交换这两个元素,此时会破坏稳定性,所以快速排序是一种不稳定的算法

最优情况下快速排序的时间复杂度为O(nlogn);
最坏情况下,快速排序的时间复杂度为O(n^2);

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值