归并和快排

算法入门

归并排序

归并排序本身是一个递归的过程,在每一次递归的过程中,将数组分成等长的2部分,然后左边进行递归,然后右边跟着递归,然后进行一个排序,这个排序的过程的前提是左右部分都是有序的,然后左右两边的数据分别从头部进行比较,小的数就存入一个新的数组中,并且相应的位置后退一步,这样下来可以使左右两边的数据全部有序的进入,当有一边的数已经全部进入数组,那么直接把剩下的那边依次放入数组就完成了。

public class mergesort {
    /*
     * 如何进行归并排序?
     * 1.首先传入一个数组,然后我们把他分开2分,然后这2分进行递归,递归到结束的条件就是我们分开后的2分中只有
     * 一个元素,然后让这两个元素进行排序,排序的过程是两边的数从头开始比较,并且开辟一个新的数组,小的数先进数组,大的数后进入,
     * 当一侧的数据读完后,就将剩余那部分的数全部放入数组,然后在将排好序的数,重新放回最初传进来的数组,一层层递归结束后,就是
     * 排好顺序的数了
     *
     * */
    //1.先判断这个数组是否为空或者只有一个元素
    //解释一下为什么没有返回值,因为传入的参数是一个数组,我们在排序中会对数组中的
    //元素进行排序,所以说传入后,即使不返回,数组也变了
    static void mergesort(int[] arr){
        if (arr==null||arr.length<=1){
            return ;
        }
        mergesort(arr,0,arr.length-1);

    }
    //如果不为空就进入正式开始的递归排序,这里传入的参数,第一个是数组,第二个是开始位置,第三个是结束位置
    static void  mergesort(int[] arr,int start ,int end){
        //先声明递归结束的条件
        if (start==end){
            return ;
        }
        //如果不是就2分,先找到中间点
        int mid = (start+end)/2;
        //那么分开的部分进行递归的开始和结束位置分别是start mid 和 min+1 end
        mergesort(arr, start, mid);
        mergesort(arr,mid+1,end);
        //关键在于这个merge,这个merge要怎么写?
        merge(arr,start,mid,end);
    }
    static void merge(int[] arr,int start,int mid,int end){
        //传进来了三个参数,然后依次进行归并排序
        //首先要有2个指针,分别指向2边的开头,然后比较结束的条件就是任意一方的数读到边界!
        int[] newarray = new int[arr.length];
        int i = start;
        int p1 = start;
        int p2 = mid+1;
        while((p1<mid+1)&&(p2<end+1)){
            //这句话的意思就是两边指针所指向的位置进行比较,如果
            //小的一边对数组进行赋值,指针向后移动一位
            newarray[i++] = arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
        }
        while(p1<mid+1){
            newarray[i++] = arr[p1++];
        }
        while(p2<end+1){
            newarray[i++] = arr[p2++];
        }
        //拷贝回去
        for(int j = start;j<=end;j++){
            arr[j] = newarray[j];
        }
    }
    public static void main(String[] args) {
        int[] arr = new int[]{2,5,4,1};
        mergesort(arr);
        for (int i : arr) {
            System.out.println(i);
        }

    }

}

快速排序

荷兰国旗问题!

什么是荷兰国旗问题?首先我们先看荷兰国旗

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dF89QdNu-1647951934845)(C:\Users\12473\AppData\Roaming\Typora\typora-user-images\image-20220322185513369.png)]

由三种颜色组成,所以我们今天要研究的就是给定一个数组,和一个数num,对数组进行排序,把大于在这个数的数放在右边,小于这个数的数放在数组左边,等于这个数的数放在中间,当然,在大于和小于的部分,我们不要求有序。

所以我们要思考怎么去做?(要求额外的空间复杂度是O(1)),只能用有限制的几个变量进行操作
首先划分2个边界,一个是小于边界,一个是大于边界,小于边界在数组的最左边,大于边界在数组的最右边,我们根据一下的3条规则进行操作

1.数组从左向右遍历,遇到比num小的数,我们将它与小于边界的数进行交换,然后小于边界向后移动一位,

2.当遇到等于num的数,我们的不进行任何操作,继续遍历

3.当遇到大于num的数,将大于边界所指向的数和它进行交换,然后大于边界向前移动一位。然后这次循环重新进行

终止的条件就是我们遍历的数到达了大于的边界就停止遍历。

public class NetherlandsFlag {
    static void partion(int[] array,int a,int b,int nums){
        int left = a;
        int right= b;
        int i = a;
        //确定左右边界,可以直接却认为数组的开头和结尾(长度减一)
        while (i<=right) {//只要没有到达最大数的边界就一直遍历下去,3种条件
            //1.比num小
            if (array[i]<nums){
                //进行交换操作,交换的对象,当前数和小于边界所指向的数,执行结束后i++,left++
                int temp = array[i];
                array[i] = array[left];
                array[left] = temp;
                i++;
                left++;
            }
            //等于num
            else if(array[i]==nums){
                i++;
            }
            //大于nums
            else{
                int temp = array[i];
                array[i] = array[right];
                array[right] = temp;
                right--;
            }
        }
    }

    public static void main(String[] args) {
        int[] array = new int[]{0,7,8,5,5,9,5,4,5,3};
        partion(array,0,array.length-1,5);
        for (int i : array) {
            System.out.println(i);
        }
    }

}

快速排序

快速排序就是以荷兰国旗排序为基础,这次只给一个数组,我们进行排序,那么参照荷兰国旗,我们可以首先选取数组最后一个数作为num,然后对数组中的数进行排序,分为,小于,等于,大于三部分,排序之后我们将大于区域的最前面的数和num的位置进行交换,然后以num的左右边界的最后一个数作为nums,进行新一轮的排序,这样递归下来我们最终就可以确定出所有数的正确顺序,每次确定一个数。

public class NetherlandsFlag {
    static int[] partion(int[] array,int a,int b,int nums){
        int left = a;
        int right= b;
        int i = a;
        //确定左右边界,可以直接却认为数组的开头和结尾(长度减一)
        while (i<=right) {//只要没有到达最大数的边界就一直遍历下去,3种条件
            //1.比num小
            if (array[i]<nums){
                //进行交换操作,交换的对象,当前数和小于边界所指向的数,执行结束后i++,left++
                int temp = array[i];
                array[i] = array[left];
                array[left] = temp;
                i++;
                left++;
            }
            //等于num
            else if(array[i]==nums){
                i++;
            }
            //大于nums
            else{
                int temp = array[i];
                array[i] = array[right];
                array[right] = temp;
                right--;
            }
        }
        //这里的right永远指向的是下一个未知的数,所以返回最后一个确定的最大值的位置,那么就返回right-1,左边的就是left-1
        return new int[]{left-1,right+1};
    }
    static void quicksort(int[] arr,int start,int end){//最初传递的数组肯定是从0到末尾,首先确定出末尾位置
        int num = arr[end];
        //然后剩下的部分进行排序,传入数组的起点,重点 和 num
        int[] res = partion(arr, start, end - 1, num);//拿到交换的位置
        int temp = arr[end];
        arr[end] = arr[res[1]];
        arr[res[1]] = temp;
        //交换完毕,递归左右两边,右边的起点是partion+1 ,左边的起点没返回,
        if (res[0]>=start){
            quicksort(arr,start,res[0]);
        }
        if (res[1]<end){
            quicksort(arr,res[1]+1,end);
        }
       
        

    }

    public static void main(String[] args) {
        int[] array = new int[]{0,7,8,5,5,9,5,4,5,3};
        quicksort(array,0,array.length-1);
        for (int i : array) {
            System.out.println(i);
        }
    }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值