八大排序(java实现)

第一部分:排序算法

基于交换的排序:冒泡排序、快速排序

基于插入的排序:直接插入排序、希尔排序

基于选择的排序:简单选择排序、堆排序

冒泡排序
 public static int[] Pop(int[] numbers)
    {
        for(int i=0;i<numbers.length-1;i++)//控制轮数,共需要length-1次轮
        {
            for(int j=0;j<numbers.length-1-i;j++)//控制每轮的交换次数
            {
                if(numbers[j]>numbers[j+1])
                {
                    int temp=numbers[j];
                    numbers[j]=numbers[j+1];
                    numbers[j+1]=temp;
                }
            }
        }
        return numbers;
    }

时间复杂度:最好O(n)、最坏O(n2)、平均O(n2) 分析:当序列已经是排好序时,则只需要n-1次比较,无需移动元素,当序列为逆序时,则需要n(n-1)/2次比较和移动

空间复杂度:O(1)

稳定性:两个相邻的相等元素并不会发生交换,所以稳定


快速排序
 //递归思想 传入参数,左边界,右边界及数组
    public static void quickSort(int[] arr, int leftIndex, int rightIndex) {
        if (leftIndex >= rightIndex) {
            return;
        }
        int left = leftIndex;
        int right = rightIndex;
        //待排序的第一个元素作为基准值
        int key = arr[left];
        //从左右两边交替扫描,直到left = right
        while (left < right) {
            while (right > left && arr[right] >= key) {
                //从右往左扫描,找到第一个比基准值小的元素
                right--;
            }
            //找到这种元素将arr[right]放入arr[left]中
            arr[left] = arr[right];
            while (left < right && arr[left] <= key) {
                //从左往右扫描,找到第一个比基准值大的元素
                left++;
            }
            //找到这种元素将arr[left]放入arr[right]中
            arr[right] = arr[left];
        }
        //基准值归位
        arr[left] = key;
        //对基准值左边的元素进行递归排序
        quickSort(arr, leftIndex, left - 1);
        //对基准值右边的元素进行递归排序。
        quickSort(arr, right + 1, rightIndex);
    }

时间复杂度:最好O(nlogn) 、最坏O(n^2) 平均O(nlogn) 分析:当基准值选取得当,每次都能将序列均匀划分,则能到O(nlogn),这里要用到递归算法的时间复杂度公式:T[N]=2T[N/2]+f(n)。如果基准值每次都是最大或者最小,则会将所有序列划分到一侧,为O(n^2)。

空间复杂度:O(nlogn)

稳定性:所以快速排序是一个不稳定的排序算法,不稳定发生在中枢元素和a[j] 交换的时刻


直接插入排序
  public static int[] InsertSort(int[] a)
    {
        for(int i=1;i<a.length;i++)
        {
            int temp=a[i];
            int j=i-1;
            //将temp插入到合适位置
            while(j>=0&&temp<a[j])
            {
                a[j+1]=a[j];
                j--;
            }
            a[j+1]=temp;
        }
        return a;
    }

时间复杂度:最好为O(n)、最坏均为O(n^2) 平均O(n^2)

空间复杂度:O(1)

稳定性:稳定


希尔排序
 public  static int[] ShellSort(int[] a)
    {
        int gap;
        for(gap=a.length/2;gap>0;gap=gap/2)//最外层循环
        {
           //以gap距离分组
           for(int i=0;i<gap;i++)
           {
               for(int j=i+gap;j<a.length;j+=gap)
               {
                  int temp=a[j];
                  int k=j-gap;
                   while(k>=0&&temp<a[k])
                   {
                       a[k+gap]=a[k];
                       k-=gap;
                   }
                   a[k+gap]=temp;
               }
           }
        }
        return a;
    }

时间复杂度:最好O(n) 最坏O(n^2) 平均O(n^1.3)

空间复杂度:O(1)

稳定性:不稳定


简单选择排序
 public static void simpleSelectionSort(int[] a)
    {
        for(int i=0;i<a.length;i++)
        {
            int max=i;
            for(int j=i+1;j<a.length;j++)
            {
                if(a[max]>a[j])
                {
                   max=j;
                }
            }
            int temp=a[i];
            a[i]=a[max];
            a[max]=temp;
        }
    }

时间复杂度:最好最坏平均都为O(n^2)

空间复杂度:O(1)

稳定性:不稳定


堆排序
 /**重要性质:对于大顶堆:arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]
           对于小顶堆:arr[i] <= arr[2i + 1] && arr[i] <= arr[2i + 2]

       思路:先构造大顶堆,然后交换根节点和数组最后一个数,重复步骤,
            大顶堆的构造关键,由下往上遍历
     时间复杂度O(nlogn)**/
 public static void heapSort(int[] a)
    {
        if(a == null || a.length==0)
        {
            return ;
        }
         int len = a.length;
        for(int i=len-1;i>0;i--)
        {
            heapify(a,0,len);
            swap(a,0,i);
            len--;
        }
    }

    //构建大顶堆
    private static void heapify(int[] arr, int i, int len) {
        // 先根据堆性质,找出它左右节点的索引
        int left = 2 * i + 1;
        int right = 2 * i + 2;
        // 默认当前节点(父节点)是最大值。
        int largestIndex = i;
        //这里注意两个条件书写的先后顺序,若顺序相反则会导致数组下标溢出,因为如果left不满足
        //小于len的条件,则不会判断后面的条件,就不会导致数组溢出
        if (left < len && arr[left] > arr[largestIndex]) {
            // 如果有左节点,并且左节点的值更大,更新最大值的索引
            largestIndex = left;
        }
        if (right < len && arr[right] > arr[largestIndex]) {
            // 如果有右节点,并且右节点的值更大,更新最大值的索引
            largestIndex = right;
        }

        if (largestIndex != i) {
            // 如果最大值不是当前非叶子节点的值,那么就把当前节点和最大值的子节点值互换
            swap(arr, i, largestIndex);
            // 因为互换之后,子节点的值变了,如果该子节点也有自己的子节点,仍需要再次调整。
            heapify(arr, largestIndex, len);
        }
    }


    //交换
    public static void swap(int[] arr,int i,int j)
    {
        int temp=arr[j];
        arr[j]=arr[i];
        arr[i]=temp;
    }

时间复杂度:最好最坏平均 都为O(nlogn)

空间复杂度:O(1)

稳定性:不稳定

归并排序
 public static void mergeSort(int[] a,int left,int right)
    {
        if(left>=right)
        {
            return;
        }
        int mid= (left+right)/2;
        mergeSort(a,left,mid);
        mergeSort(a,mid+1,right);
        merge(a,left,mid,right);
    }
    //将两个数组合并
    public static void merge(int[] a,int left,int mid,int right)
    {
       //创建辅助数组aux  根据要合并的数组创建相对应大小的辅助数组
        int[] aux = new int[right-left+1];
        //辅助数组aux 这里i-left 使得aux从0开始赋值
        for(int i=left;i<=right;i++)
            aux[i-left]=a[i];
//i:临时数组左边比较的元素下标;j:临时数组右边比较的元素的下标;k:原数组将要放置的元素下标
        int i=left,j=mid+1;
        for(int k=left;k<=right;k++)
        {
            //检查左下标是否越界
            if(i>mid)
            {
                a[k]=aux[j-left];
                j++;
            }
            else if(j>right)
            {
                a[k]=aux[i-left];
                i++;
            }
            else if(aux[i-left]<=aux[j-left])
            {
                a[k]=aux[i-left];
                i++;
            }
            else
            {
                a[k]=aux[j-left];
                j++;
            }
        }

    }

时间复杂度度:最好最坏平均 都为O(nlogn)

空间复杂度:O(n)

稳定性:稳定

桶排序
  public static void  radixSort(int[] arr){
        //先求出数组中的最大的数
        int max=arr[0];
        for(int i=1;i<arr.length;i++){
            if(arr[i]>max){
                max=arr[i];
            }
        }
        //得到最大数是几位数,将数字转换成字符串
        int maxLength=(max+"").length();

        //定义一个二维数组,表示10个桶,每个桶就是一个数组
        //为了在放入数时防止数据溢出,我们每个桶的大小为arr.length,
        // 即每个桶最多放进数组里的所有元素
        int[][] bucket=new int[10][arr.length];

        //定义一个一维数组来记录各个桶的每次放入的数据个数
        int[] bucketElementCount=new int[10];

        for(int i=0,n=1;i<maxLength;i++,n*=10)
        {
            //对每个元素的对应位进行处理
            for(int j=0;j<arr.length;j++){
                //取出每个元素的对应位的值
                int digiOfElement=arr[j]/n%10;
                //放入到对应的桶中
                bucket[digiOfElement][bucketElementCount[digiOfElement]]=arr[j];
                bucketElementCount[digiOfElement]++;
            }
            //按照这个桶的顺序即一维数组的下标一次取出数据放入原来数组
            int index=0;
            //遍历每一桶,并将桶中数据放入到原数组
            for(int k=0;k<bucketElementCount.length;k++){
                //如果桶中有数据,才放入原来数组
                if(bucketElementCount[k]!=0){
                    for(int m=0;m<bucketElementCount[k];m++){
                        arr[index++]=bucket[k][m];
                    }
                }
                //每一轮处理后,需将bucketElementCount[k]=0
                bucketElementCount[k]=0;
            }
            System.out.println("第"+(i+1)+"轮,对个位数的排序处理 arr="+             Arrays.toString(arr));
        }

    }

时间复杂度:最好O(n) 最坏O(n*k) 平均 O(n+k)

空间复杂度:O(n+k)

稳定性:稳定

总结:

最好最坏平均空间复杂度稳定性
冒泡排序O(n)O(n^2)O(n^2)O(1)稳定
快速排序O(nlogn)O(n^2)O(nlogn)O(nlogn)不稳定
直接插入排序O(n)O(n^2)O(n^2)O(1)稳定
希尔排序O(n)O(n^2)O(n^1.3)O(1)不稳定
直接选择排序O(n^2)O(n^2)O(n^2)O(1)不稳定
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定
桶排序O(n)O(n*2)O(n+k)O(n+k)稳定
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值