【算法复习】常用排序算法

本文将介绍几种常用的排序算法

  • 选择排序
  • 插入排序
  • 希尔排序
  • 归并排序
  • 快速排序
  • 堆排序

文中部分封装代码

/*
  交换算法
  输入数组,大值索引,小值索引
  无输出
 */
public static void exch(Integer[] num, Integer max, Integer min){
    Integer type = num[max];
    num[max] = num[min];
    num[min] = type;
}

选择排序

算法思想
①找到数组中最小的元素
②将它和数组中第一个元素交换位置(如果第一个元素最小那么就和自己交换)
③在剩下的元素中找到最小的元素,将它与数组第二个元素交换
④如此往复,直到整个数组排序

    /*
     选择排序
     算法思想: 找到数组中最小的元素 --> 将它和数组中第一个元素交换位置(如果第一个元素最小那么就和自己交换)
              -->  在剩下的元素中找到最小的元素,将它与数组第二个元素交换 --> 如此往复,直到整个数组排序
     */

    public static void Selection(Integer[] num){

        Integer N = num.length;
        Integer min;     //用于存储最小数字索引,定义在循环外节省内存空间
        for(int i = 0 ; i < N ; i++){
            min = i;
            for (int j = i+1 ; j < N ; j++){
                if (num[j] < num[i] )
                    min = j;
            }
            exch(num,i,min);
        }
    }

在这里插入图片描述

插入排序

算法思想:与选择排序类似,索引右侧数据不被访问,索引左侧进行排序,交换相邻元素
在这里插入图片描述

    /*
      插入排序
      算法思想:索引右侧数据不被访问,索引左侧进行排序,交换相邻元素
     */
    public static void Insertion(Integer[] num){

        Integer N = num.length;
        for(int i = 1 ; i < N ; i++){
            for (int j = i ; j > 0 && (num[j] < num[j-1]) ; j--){
                exch(num,j-1,j);
            }
        }
    }

在这里插入图片描述

希尔排序

基于插入排序的快速的排序算法
算法思想: 使数组中任意间隔为 h 的元素都是有序的,对于每个 h 用插入排序将 h 个子数组独立地排序
更简洁的,在 h-子数组中将每个元素交换到比它大的元素之前去 --> 只需在插排代码中将移动距离由1变为h

    /*
       希尔排序 -- 基于插入排序的快速的排序算法
       算法思想: 使数组中任意间隔为 h 的元素都是有序的,对于每个 h 用插入排序将 h 个子数组独立地排序
       更简洁的,在 h-子数组中将每个元素交换到比它大的元素之前去 --> 只需在插排代码中将移动距离由1变为h
     */
    public static void Shell(Integer[] num){

        Integer N = num.length;
        Integer h = 1;
        while( h < N/3 )  h = 3*h + 1;  //得到步长h
        //嵌套外循环来得到最简洁的希尔排序
        while( h>=1 ){
            for(int i = h ; i < N ; i++){
                for(int j = i ; j >= h && (num[j] < num[j-h]) ; j -= h){
                    exch(num,j-h,j);
                }
            }
            h = h/3;
        }
    }

在这里插入图片描述

归并排序

算法思想:将两个有序的数组归并成一个更大的数组,利用递归循环实现

     /*
       归并排序
       算法思想:将两个有序的数组归并成一个更大的数组
     */
    public static void Merge(Integer[] num,Integer low,Integer mid,Integer high){
        //将已经排好序的 num[low...mid] 和 num[mid+1...high]归并
        int i = low, j = mid+1;
        Integer[] numm = new Integer[num.length];
        for (int k = low ; k <= high ; k++){
            numm[k] = num[k];
        }
        for (int k = low ; k <= high ; k++){    //归并
            if(i > mid)  num[k] = numm[j++];    //左半边用尽(取右半边元素)
            else if (j > high)                  //右半边用尽(取左半边元素)
                num[k] = numm[i++];
                else if(numm[j] < numm[i])      //右半边当前元素小于左半边当前元素
                    num[k] = numm[j++];
                else                            //右半边当前元素大于等于左半边当前元素
                    num[k] = numm[i++];
        }

    }
    public static void MSort(Integer[] num ,Integer low,Integer high){

        //递归归并,对每一小段进行归并排序
        if(high <= low) return;
        Integer mid = (low + high)/2;
        MSort(num,low,mid);
        MSort(num,mid+1,high);
        //合并
        Merge(num,low,mid,high);
    }

在这里插入图片描述

快速排序

算法思想:将一个数组分为两个数组,两部分独立排序,当两个子数组都有序时整个数组也有序了
切分位置取决于数组的内容,切分位置左侧所有元素都不大于该元素,右侧都不小于该元素

切分办法:
先随意取num[low]为切分元素;
从左端向右扫描,找到大于等于该元素的位置;
从右端向左扫描,找到小于等于该元素的位置;
交换扫描到的两个数字;
如此继续,当两指针相遇,将切分元素num[low]与左子数组最右侧元素交换,并返回索引即可。

     /*
      快速排序
      算法思想:将一个数组分为两个数组,两部分独立排序,当两个子数组都有序时整个数组也有序了
              切分位置取决于数组的内容,切分位置左侧所有元素都不大于该元素,右侧都不小于该元素
      切分办法:先随意取num[low]为切分元素 --> 从左端向右扫描,找到大于等于该元素的位置
              --> 从右端向左扫描,找到小于等于该元素的位置
              --> 交换扫描到的两个数字
              --> 如此继续,当两指针相遇,将切分元素num[low]与左子数组最右侧元素交换,并返回索引即可
     */

    //切分
    public static int partition(Integer[] num, Integer low, Integer high){

        int i = low, j = high+1;      //左右扫描指针
        Integer flag = num[low];      //切分元素
        while(true){
            while(num[++i] < flag)  if(i == high) break;
            while(flag < num[--j])  if(j == low)  break;
            if(i >= j)   break;
            exch(num,i,j);
        }
        exch(num,low,j);              //将切分元素放入正确位置
        return j;                     //返回切分索引
    }
    //快排
    public static void Quick(Integer[] num,Integer low,Integer high){
        if(low >= high) return;
        int j = partition(num,low,high);
        Quick(num,low,j-1);
        Quick(num,j+1,high);
    }

在这里插入图片描述

堆排序

算法思想:
将无序序列建成一个堆 (输出堆顶的最小(大)值)
使剩余的n-1个元素又调整成一个堆,则可得到n个元素的次小值
重复执行,得到一个有序序列

 /*
      堆排序
      算法思想: 将无序序列建成一个堆 (--> 输出堆顶的最小(大)值)
               -->使剩余的n-1个元素又调整成一个堆,则可得到n个元素的次小值
               -->重复执行,得到一个有序序列
     */

    //建立堆
    public static void BuildHeap(Integer[] num,Integer N){
        for (int k = N/2 ; k >= 0 ; k--){
            sink(num,k,N);              //初始化
        }
    }

    //块下沉
    public static void sink(Integer[] num,int k,Integer N){

       while(2*k <= N){
            int j = 2 * k;              //顶点所对左孩子
            if (j < N && (num[j] < num[j+1])) ++j;    //判断左孩子与右孩子的大小
            if (num[k] >= num[j]) break;        //
            exch(num,k,j);
            k = j;
        }
    }
    //堆排序
    public static void Sort(Integer[] num){
        Integer N = num.length-1;
        BuildHeap(num,N);
        while (N > 0){
            exch(num,0,N--);
            sink(num,0,N);
        }
    }

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值