七大排序算法

1.插入排序

思想:拿一个元素和它相邻前面的元素相比较,如果比这个元素小,那么就不动,如果比它大那么就交换位置。利用这种思想,我们先拿第二个元素与第一个元素相比较,比较完后,前两个就是有序的,然后再拿第三个与前两个相比,前三个就是有序的,以此类推,一直到arr.lenth的元素与前arr'.lenth-1个元素相比较。那么前arr.lenth的元素都是有序的。

代码如下:

public static void sort1(int []arr){
        int i = 1;
        while(i< arr.length) {
            int j = i - 1;
            int tmp = arr[i];
            while(j>=0&&arr[j] > tmp){
                arr[j+1] = arr[j];
                arr[j] = tmp;
                j--;
            }
            i++;
        }
    }

时间复杂度

最好:O(n)

平均:O(n^2)

最坏:O(n^2)

空间复杂度:O(1)

稳定性:稳定

特点:插入排序,初始数据越接近有序,时间效率越高。

2.希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个步长,把数据隔步长分为几个组,先在这几个组中把数据进行排序好,然后缩小步长,重复上述操作,当步长为1时,进行排序这段数据就是有序的了。

希尔排序可以看为改进版的直接插入排序,因为插入排序,初始数据越接近有序,时间效率越高,所以我们想先分组把它排得大概有序,然后再当步长为1时,就是直接插入排序,然后进行排序。这样时间复杂度可降低。

public static void headle_gap(int[]arr){
        int gap=arr.length;
        while(gap>1){
            gap=gap/3+1;
            sort2(arr,gap);
        }
    }
    public static void sort2(int []arr,int gap){

        for (int i = gap; i < arr.length; i++) {
            int j=i;
            j-=gap;
            int tmp=arr[i];
            while(arr[j]>tmp&&j>=0){
                arr[j+gap]=arr[j];
                arr[j]=tmp;
                if(j-1<0){
                    break;
                }
                j-=gap;
            }
        }
    }

时间复杂度

最好:O(n)

平均:(O^1.3)

最坏:O(n^2)

空间复杂度:O(1)

稳定性:不稳定

3.选择排序

选择排序就是拿一个元素与每一个元素进行比较进行,如果这个元素与后面的元素相比大于它,则交换,把每个元素都与其后面的元素相比。则最终排序好。

代码如下:

public static void sort3(int []arr){
        int i=0;
        while(i<arr.length){
            for (int j = i+1; j < arr.length; j++) {
                if(arr[i]>arr[j]){
                    int tmp=arr[i];
                    arr[i]=arr[j];
                    arr[j]=tmp;
                }
            }
            i++;
        }
    }

时间复杂度

恒为:O(n^2)

空间复杂度:O(1)

稳定性:不稳定

4.堆排序

原理:把堆按大根堆进行排序,那么root就为这个这个堆的最大值,所以可以建一个数组把它放进去,然后再把堆重新整理为大根堆,然后再把新的root放入数组中,重复上述操作直到把值放完。然后再逆序数组就可以得到排序好的数组。

public static  void  dui(int []arr,int root,int len){
        int parent=root;
        int child= 2*parent+1;
        while (child<len) {
            //先判断是否有右节点且左右节点谁大
            if (child + 1 < len && arr[child + 1] > arr[child]) {
                child++;
            }
            if(arr[child]>arr[parent]){
                int tmp=arr[child];
                arr[child]=arr[parent];
                arr[parent]=tmp;
                parent=child;
                child=parent*2+1;
            }else {
                break;
            }

        }
    }
    //把数组建为大根堆
    public static void creat_dui(int []arr) {
        for (int i = (arr.length-1-1)/2; i >=0; i--) {
            dui(arr,i,arr.length);
        }
    }
    public  static void sort4(int[]arr){
        creat_dui(arr);
        int end= arr.length-1;
        while(end>0){
            int tmp=arr[0];
            arr[0]=arr[end];
            arr[end]=tmp;
            dui(arr,0,end);
            end--;
        }
    }

时间复杂度

恒为:O(nlog(n))    //log以二为底的n

空间复杂度:O(1)

稳定性:不稳定

5.冒泡排序

原理:在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序.

public static void sort5(int []arr){
        for (int i = 0; i < arr.length-1; i++) {
            boolean flg=false;
            for (int j = 0; j < arr.length-1-i; j++) {
                if(arr[j+1]<arr[j]){
                    int tmp=arr[j+1];
                    arr[j+1]=arr[j];
                    arr[j]=tmp;
                    flg=true;
                }
            }
            if(flg==false){
                break;
            }
        }
    }

时间复杂度

最好:O(n)

平均:O(n^2)

最坏:O(n^2)

空间复杂度:O(1)

稳定性:稳定

6.快速排序

快排采用的思想主要为分治思想,从待排序区间选择一个数,作为基准值(pivot),遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边,采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 == 1,代表已经有序,或者小区间 的长度 == 0,代表没有数据。

 //填坑法
    public  static int sap(int []arr,int low,int high){
        int tmp=arr[low];
        while (low<high){
            while(low<high&&tmp<=arr[high]){
                high--;
            }
            arr[low]=arr[high];
            while (low<high&&tmp>=arr[low]){
                low++;
            }
            arr[high]=arr[low];
        }
        arr[low]=tmp;
        return low;
    }
    //递归
    public static void fast_sort6(int []arr,int low,int high){
        if(low>=high){
            return;
        }
        int pivot=sap(arr,low,high);
        fast_sort6(arr,low,pivot-1);
        fast_sort6(arr,pivot+1,high);

    }

提升效率:1.对于这个方法取基准值是尤为重要的,当取到中间值时代码的效率是最高的,所以就出现了三数取中法。(代码如下)2.如果数据小于一个阈值,可进行直接插入排序

 public static void exchange(int arr[],int x,int y){
        int tmp=arr[x];
        arr[x]=arr[y];
        arr[y]=tmp;
    }
    public static void selectnumber(int []arr,int low,int high,int mid){
        //arr[mid]<arr[low]<arr[high]
        if(arr[low]<arr[mid]){
            exchange(arr,low,mid);
        }
        if(arr[low]>arr[high]){
            exchange(arr,low,high);
        }
        if(arr[mid]>arr[high]){
            exchange(arr,mid,high);
        }
    }

非递归版本

 /非递归实现快速排序
    public static void fast_sort8(int []arr) {
        Stack<Integer>stack=new Stack<>();
        int low=0;
        int high=arr.length-1;
        int prvot=sap(arr,low,high);
        if(prvot>low+1){
            stack.add(low);
            stack.add(prvot-1);
        }
        if(prvot<high-1){
            stack.add(prvot+1);
            stack.add(high);
        }
        while (!stack.empty()){
            high=stack.pop();
            low=stack.pop();
            prvot=sap(arr,low,high);
            if(prvot>low+1){
                stack.add(low);
                stack.add(prvot-1);
            }
            if(prvot<high-1){
                stack.add(prvot+1);
                stack.add(high);
            }
        }

    }

时间复杂度

最好:O(n * log(n))

平均:O(n * log(n))

最坏:O(n^2)

空间复杂度

最好:O(log(n))

平均:O(log(n))

最坏 : O(n)

7.归并排序

该排序主要采用的是分治法:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子 序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

 递归实现

public static void sort9(int []arr){
        sort9_detach(arr,0,arr.length-1);
    }
    //分离的过程
    public static void sort9_detach(int []arr,int low,int high){
        if(low>=high){
            return;
        }

        int mid=(low+high)/2;
        sort9_detach(arr,low,mid);
        sort9_detach(arr,mid+1,high);
        sort9_merge(arr,low,mid,high);
    }
    //合并过程
    public  static void sort9_merge(int []arr,int low,int mid,int high){
        int s1=low;
        int e1=mid;
        int s2=mid+1;
        int e2=high;
        int[] tmp=new int[high-low+1];
        int k=0;
        while(s1<=e1&&s2<=e2) {
            if (arr[s1] <= arr[s2]) {
                tmp[k++] = arr[s1++];
            } else {
                tmp[k++] = arr[s2++];
            }
        }
        while(s1<=e1){
            tmp[k++]=arr[s1++];
        }
        while(s2<=e2){
            tmp[k++]=arr[s2++];
        }
        for (int i = 0; i < tmp.length; i++) {
            arr[i+low]=tmp[i];
        }
    }

非递归实现

   public static void sort11(int[]arr,int i){
        int s1=0;
        int e1=s1+i-1;
        int s2=e1+1;
        int e2=s2+i-1>=arr.length?arr.length-1:s2+i-1;
        int[] tmp=new int[arr.length];
        int k=0;
        while(s2<arr.length) {
            while (s1 <= e1 && s2 <= e2) {
                if (arr[s1] <= arr[s2]) {
                    tmp[k++] = arr[s1++];
                } else {
                    tmp[k++] = arr[s2++];
                }
            }
            while(s1<=e1){
                tmp[k++]=arr[s1++];
            }
            while(s2<=e2){
                tmp[k++]=arr[s2++];
            }
            s1=e2+1;
            e1=s1+i-1;
            s2=e1+1;
            e2=s2+i-1>=arr.length?arr.length-1:s2+i-1;
        }

        while(s1<=arr.length-1){
            tmp[k++]=arr[s1++];
        }
        for (int j = 0; j < tmp.length; j++) {
            arr[j]=tmp[j];
        }
    }
    public static void sort10(int[]arr){
        for (int i = 1; i < arr.length; i*=2) {
            sort11(arr,i);
        }
    }

时间复杂度

恒为:O(n * log(n))

空间复杂度

恒为:O(n)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值