几种常见的排序算法

选择排序

选择排序:每次在未排序部分选择一个最小的放到前面,并把最小值的标记向后移动一位
特点:
1. 运行时间和输入无关(但是并没有用,因为即使输入时是有序的,仍然会进行遍历与比较,复杂度不变
2. 数据移动量是最少的,因为每次只移动一个元素,移动N次

时间复杂度:最坏n^2,最优n^2平均n^2
缺点:未排序部分若有序,仍会继续遍历

    public static void select(int[]arr){
        for(int i=0;i<arr.length;i++){
            int min = i;//每次假设未排序部分首位为最小值
            for(int j=i;j<arr.length;j++){
                if(arr[j] < arr[min]){//然后在剩余部分中找出最小值
                    min = j;
                }
            }
            //将剩余部分的最小值放到i上(即排序部分的末尾)
            int temp = arr[i];
            arr[i] = arr[min];
            arr[min] = temp;
        }
    }

插入排序

插入排序:即把未排序部分的第一个元素拿出来,插入到已排序的部分。将插入位置后面的元素后移。类似于从左往右整理扑克牌
特点:
1. 与选择排序一样,当前索引左边的所有元素都是有序的,但它们的最终位置还不确定,为了给更小的元素腾出空间,它们可能会被移动。但是当索引到达数组的右端时,数组排序就完成了。
2. 数组已经相对有序时,时间会减少很多(整理扑克牌时如果接近有序,也不用花太多时间)
3. 由于插入排序插入时会影响到后续元素的位置,因此用数组来实现会有大量的时间用于元素位置移动。(可以尝试用链表改进)

最坏:n^2 最优 n 平均n^2

    public static void insertSort(int arr[]){
        for(int i=1;i<arr.length;i++){//插入第i个数
            for(int j=i;j>0;j--){ //从第i-1开始往前比较,不停的往前移动
                if(arr[j]<arr[j-1]){
                    int temp = arr[j];
                    arr[j]=arr[j-1];
                    arr[j-1] = temp;
                }
            }
        }
    }

归并排序

归并排序:采用分治思想,将一个数组的排序转化为若干小数组的排序,然后将结果归并起来
采用分治思想算法复杂度始终是nlogn

    public static void merge(int arr[]){
        mergeSort(0,arr.length-1,arr);
    }
    public static void mergeSort(int lo,int hi,int arr[]){
        if(lo>=hi) return;
        int mid = lo + (hi-lo)/2;
        mergeSort(lo,mid,arr);
        mergeSort(mid+1,hi,arr);
        merge(lo,mid,hi,arr);
    }

    public static void merge(int lo,int mid,int hi,int[] arr){
        int[] temp = new int[arr.length];
        for(int i=lo;i<=hi;i++){
            temp[i] = arr[i];
        }
        int j = mid+1;
        int k = lo;
        int f = lo;
        while(f <= hi){
            if(k > mid)                  arr[f++] = temp[j++];
            else if(j > hi)              arr[f++] = temp[k++];
            else if(temp[k] < temp[j])   arr[f++] = temp[k++];
            else                         arr[f++] = temp[j++];
        }
    }

快速排序

快速排序:快速排序也是采用分治思想的排序,快速排序的思路是选取一个随机元素一般是a[lo](待排部分首位),

然后在分别从lo->hi,hi->lo进行扫描,从左边元素找到一个比a[lo]大的,在右侧找到一个比a[lo]小的,进行位置交换,直到左右扫描的标记相遇

如果i>=j ,说明 i 左侧元素一定比a[lo]小了,并且j右侧元素一定比a[lo]大了此时把a[lo]放到a[i]与a[j]之间即可

顺序或逆序的数组进行快排的性能十分之低,所以在进行操作之前应该先对其进行一个打乱操作(此处未打乱)

    public static void quick(int []arr){
        quickSort(0,arr.length-1,arr);
    }

    public static void quickSort(int lo,int hi,int[] arr){
        if(lo>=hi) return;
        int a = partion(lo,hi,arr);
        quickSort(lo,a-1,arr);
        quickSort(a+1,hi,arr);
    }
    public static int partion(int lo,int hi,int[]arr){
        int i=lo+1;
        int j=hi;
        int part=arr[lo];
        while(i<=j){
            while(arr[i]<part){
                if(i==hi) break;
                i++;
            }
            while(arr[j]>part){
                if(i==lo) break;
                j--;
            }
            if(i>=j) break;
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        arr[lo] = arr[j];
        arr[j] = part;
        return j;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值