第一课 分治-快排-归并

这篇博客主要介绍了两种经典的排序算法——快速排序和归并排序。快速排序使用了分治策略,通过选取枢轴元素进行划分,并递归地对子数组进行排序。而归并排序同样采用分治,但需要额外的空间来合并已排序的子数组。博客提供了Java和C++两种语言的实现代码,并强调预定义数组可以提高效率。
摘要由CSDN通过智能技术生成
  • 1.快排

分治:先定数值x,再利用数值比较进行递归排序
原地排序,比较节省空间。
在这里插入图片描述
1.快排:分治
一层一层的分开使用相同的方法进行

java:

import java.io.IOException;
import java.util.Scanner;

public class 快排 {
    //分治法进行排序操作,注意边界问题
    public static int[] quicksort2(int[] A,int l,int r){
        //判断边界,如果就一个数据
        if(l>=r){return A;}
        //记录一个x数据,进行比较
        int m = l+r >>1;
        int x = A[m];
        int i=l-1;
        int j=r+1;
        //更换变量进行
        while (i<j){
            do i++;while (A[i]<x);
            do j--;while (A[j]>x);
            if(i<j){
                int temp = A[i];
                A[i] = A[j];
                A[j] = temp;
            }
        }
        //已经分成了两块
        quicksort(A,l,j);//左边排好,再去右边,右边已经变成了j;
        quicksort(A,j+1,r);
        return A;


    }
    public static void main(String[] args) throws IOException {
        //使用buffersort更快
        //BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));//先创建缓冲区,再说明是输入数据
        Scanner sc= new Scanner(System.in);
        //读入数据,数据都是String-要进行转换成整形
        int N= sc.nextInt();
        int[] A = new int[N];
        //pai-转换
        for(int i=0;i<N;i++){
            //String b = buf.readLine();
            A[i] = sc.nextInt();
        }
        //快速排序-数组
        quicksort2(A,0,N-1);//注意是N-1
        for(int i=0;i<N;i++){
            System.out.print(A[i]+" ");
        }
    }
}

c++代码比较简洁

    void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }
    quick_sort(q, l, j), quick_sort(q, j + 1, r);
  • 归并排序-先定位置,位置订好了,利用位置进行递归排序,再进行两边的合并
  • olongn–longn层
    -需要额外的辅助数组进行排序
    -List item
    网上借鉴
    trick:
    先定义数组,再进行使用会节省非常多的时间,所以先声明
    static int[]
package 大学菜;

import java.util.Scanner;

public class 归并 {
    //与快排相比,要开辟新的空间进行使用。
    //先定好一个位置,根据位置两边排序,然后进行合并
    static int N = 100010;
    static int[] temp = new int[N];
    public static int[] mergesort(int[] A,int l,int r){
        //先看边界
        if(l>=r){return A;}
        //定位置
        int middle = l+r>>1;
        //mersort
        mergesort(A,l,middle);
        mergesort(A,middle+1,r);
        //下面才是递归中内容,递归几次,后面return几次
        //开辟新的空间数组
        int k=0;//新数组的下标
        int i =l;//递归时的左边的边界l
        int j = middle+1;//递归时右边的边界j
        while (i<=middle && j<=r){//说明两边同时是满足边界 要求饿的
            //两边同时比较
            if(A[i]<=A[j]){temp[k] = A[i];i++;k++;}
            else {temp[k] = A[j];k++;j++;}
        }
        //如果有剩余的部分ze续接在后面
        while (i<=middle){temp[k++] = A[i++];}
        while (j<=r){temp[k++] = A[j++];}
        for (i = l, j = 0; i <= r; i ++, j ++ ) A[i] = temp[j];//每次都是一个分治中的一层
        return A;
    }

    public static void main(String[] args) {
        Scanner sc =new Scanner(System.in);
        int N = sc.nextInt();
        int[] A = new int[N];
        for(int i=0;i<N;i++){
            A[i] = sc.nextInt();
        }
        int[] B = mergesort(A,0,N-1);
        for(int i=0;i<N;i++){
            System.out.print(B[i]+" ");
        }
    }
}

默写程序-发现-定义数组在外面可以节省时间

import java.util.Scanner;

public class 归并 {
    //与快排相比,要开辟新的空间进行使用。
    //先定好一个位置,根据位置两边排序,然后进行合并
    /*void merge_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int mid = l + r >> 1;
    merge_sort(q, l, mid);
    merge_sort(q, mid + 1, r);

    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r)
        if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
        else tmp[k ++ ] = q[j ++ ];

    while (i <= mid) tmp[k ++ ] = q[i ++ ];
    while (j <= r) tmp[k ++ ] = q[j ++ ];

    for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}*/
    static int N = 100010;
    static int[] temp = new int[N];
    //额外定义数字
    static int M = 100010;
    static int[] tmp =new int[M];
    public static int[] mergesort(int[] A,int l,int r){
        //先看边界
        if(l>=r){return A;}
        //定位置
        int middle = l+r>>1;
        //mersort
        mergesort(A,l,middle);
        mergesort(A,middle+1,r);
        //下面才是递归中内容,递归几次,后面return几次
        //开辟新的空间数组
        int k=0;//新数组的下标
        int i =l;//递归时的左边的边界l
        int j = middle+1;//递归时右边的边界j
        while (i<=middle && j<=r){//说明两边同时是满足边界 要求饿的
            //两边同时比较
            if(A[i]<=A[j]){temp[k] = A[i];i++;k++;}
            else {temp[k] = A[j];k++;j++;}
        }
        //如果有剩余的部分ze续接在后面
        while (i<=middle){temp[k++] = A[i++];}
        while (j<=r){temp[k++] = A[j++];}
        for (i = l, j = 0; i <= r; i ++, j ++ ) A[i] = temp[j];//每次都是一个分治中的一层
        return A;
    }

    public static void main(String[] args) {
        Scanner sc =new Scanner(System.in);
        int N = sc.nextInt();
        int[] A = new int[N];
        for(int i=0;i<N;i++){
            A[i] = sc.nextInt();
        }
        int[] B = sort2(A,0,N-1);
        for(int i=0;i<N;i++){
            System.out.print(B[i]+" ");
        }
    }
    public static int[] sort2(int[] A, int l,int r){
        //第一步,判断边界
        if(l>=r){return A;}
        //归并核心是先按照位置进行分组,再进行合并操作
        //找位置
        int mid = l+r >> 1;
        //分而治之
        sort2(A,l,mid);//左
        sort2(A,mid+1,r);//右
        //递归到最后一个进行什么操作
        //临时数组的下标
        int k=0;
        //边界赋值
        int i = l;
        int j = mid+1;
        //判断
        while (i<=mid && j<=r){
            //双指针操作
            if(A[i]<A[j]){
                tmp[k++]=A[i];
                i++;
            }
            else {
                tmp[k++] = A[j];
                j++;
            }
        }
        //当上面进行完成后,是否有一部分是多余饿的?
        while (i<=mid){tmp[k++] = A[i];i++;}
        while (j<=r){tmp[k++] = A[j];j++;}
        //此时的tmp已经是赋值好的,将现在的tmo赋值会愿数组
        for(k=0,i=l;i<=r;i++,k++){//每次的l和r都是一个递归的过程,则可以原来的tmp数组进行覆盖
            A[i]=tmp[k];
        }
        return A;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值