Java_脱产篇_排序问题

排序是Java解题中不可或缺的重点,虽说后期我们遇到的一些问题中,需要排序好才可继续的问题中,我们或许会直接使用Arrays.sort();不再去编写冗余的排序算法。但是,我们不可以忽略排序的思想,解题思想才是我们必备的技能之一。下面我们依次详述四种排序:

冒泡排序

  1. 每一轮的循环会选出当前循环中的最大元素
  2. i 可代表执行循环的轮数
  3. j 和 j+1 可看做两“指针”,用来比较当前两元素的大小关系,并判断是否将其调换位置
    下面用图帮助理解具体的实现过程:
    在这里插入图片描述
    上图为第 1 轮循环刚开始的状态,将 j 和 j+1相比较,如果后者小于前者,则互换位置,并执行 j++ 否则直接j++,逐对比较完之后,会选出一个最大值放在当前循环的最后面。具体互换大家可以自己试一遍,第一轮的遍历结果如下图,可供参考
    在这里插入图片描述
    代码奉上:
import java.util.*;
class BubbleSort{
    public static void main(String[] args){
        int[] a={4,5,3,2,6,8,1,9,7};
        for(int i=0;i<a.length-1;i++){
            for(int j=0;j<a.length-1-i;j++){
                if(a[j]>a[j+1]){
                    swap(a,j,j+1);
                }
            }
        }
        System.out.print(Arrays.toString(a));
    }
    public static void swap(int[] a,int i,int j){
        int temp=a[i];
        a[i]=a[j];
        a[j]=temp;
    }
}

选择排序

  1. 每一轮的循环会选出当前循环中的最小元素
  2. i 可代表当前循环的“标兵”,需要和后边的每个元素进行比较
  3. j 可看做 i 的“菜”,如果 i 和他比较后,比他大,则互换位置,否则j++
    下面用图帮助理解具体的实现过程:
    在这里插入图片描述
    上图为第 1 轮循环刚开始的状态,将 j 和 i 相比较,如果前者大于后者,则互换位置,并执行 j++ 否则直接j++,逐对比较完之后,会选出一个最小值放在当前循环的最前面。具体互换大家可以自己试一遍,第一轮的遍历结果如下图,可供参考
    在这里插入图片描述
    代码奉上
import java.util.*;
class SelectSort{
    public static void main(String[] args){
        int[] a={4,5,3,2,6,8,1,9,7};
        for(int i=0;i<a.length-1;i++){
            for(int j=i+1;j<a.length;j++){
                if(a[i]>a[j]){
                    swap(a,i,j);
                }
            }
        }
        
        System.out.print(Arrays.toString(a));
    }
    public static void swap(int[] a,int i,int j){
        int temp=a[i];
        a[i]=a[j];
        a[j]=temp;
    }
}

插入排序

  1. 虽说也是两个for循环,但是只将其遍历一次
  2. i 可代表当前循环的“标兵”,供“影子” j-1 和 j 比较,如果前者大于后者,且数组角标未越界,则互换位置。直到不满足左边大于右边后,i++
    下面用图帮助理解具体的实现过程:
    在这里插入图片描述
    上图为第 1 轮循环刚开始的状态,将 j-1 和 j 相比较,如果前者大于后者且数组角标未越界,则互换位置,并执行 j-- ,直到j-1 小于 j ,再将i++,j=i,循环上述步骤,直到 i 取到最大值即可排序完毕。具体互换大家可以自己试一遍,遍历结果如下图,可供参考
    在这里插入图片描述
    代码奉上
import java.util.*;
class InsertSort{
    public static void main(String[] args){
        int[] a={4,5,3,2,6,8,1,9,7};
        for(int i=1;i<a.length;i++){
            for(int j=i;j>0&&a[j-1]>a[j];j--){//因为要j-1>=0  所以j>=1  即j>0
                swap(a,j,j-1);
            }
        }
        System.out.print(Arrays.toString(a));
    }
    public static void swap(int[] a,int i,int j){
        int temp=a[i];
        a[i]=a[j];
        a[j]=temp;
    }
}

  • 改进插入排序
    在我们遍历过程中,会出现 这种情况,先见下图:
    在这里插入图片描述
    上图是遍历过程中的一个现象,很明显我们可以看到,要想将1插入到第一个位置,我们需要不断地比较j-1 和 j 的大小,并逐个调换,为此,我们可优化成为,定义一个变量e来存储当前元素,如果符合左边小于右边,可以直接跳到准确位置。进而减少时间复杂度。优化后的代码如下:
import java.util.*;
class InsertSort_up{
    public static void main(String[] args){
        int[] a={4,5,3,2,6,8,1,9,7};
        for(int i=1;i<a.length;i++){
            int e=a[i];
            int j=0;
            for(j=i;j>0&&a[j-1]>e;j--){//因为要j-1>=0  所以j>=1  即j>0
                a[j]=a[j-1];
            }
            a[j]=e;
        }
        System.out.print(Arrays.toString(a));
    }
    public static void swap(int[] a,int i,int j){
        int temp=a[i];
        a[i]=a[j];
        a[j]=temp;
    }
}

计数排序

  1. 挑出数组中的最大值和最小值
  2. 在创建新数组之前,首先考虑到存在负数的情况,需要算出偏移量,即0和最小数的差值,然后即可定义新数组来存放对应的数字;
  3. 考虑到同一个数字可能出现不止1次,所以我们最后一个循环写上b[i]–;应该可以理解。
class CountSort{
    /**
    问题:四大排序之计数排序
     */
    public static void main(String[] args){
        int[] arr={3,2,5,2,7,4,2,7,8,-3,1,8};
        //-3 8
        //1,选取最大值和最小值
        int min=arr[0];
        int max=arr[0];
        for(int i=0;i<arr.length;i++){
            if(arr[i]<min){
                min=arr[i];
            }else if(arr[i]>max){
                max=arr[i];
            }
        }
        int offset=0-min;
        int[] b=new int[max-min+1];
        for(int i=0;i<b.length;i++){
            b[arr[i]+offset]++;
        }
        for(int i=0;i<b.length;i++){
            if(b[i]!=0){
                while(b[i]!=0){
                    System.out.print(i-offset+" ");
                    b[i]--;
                }
            }
        }
    }
}

欢迎各位批评指正。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值