当前位置:首页 » 《随便一记》 » 正文

排序之八大绝技_秃子D的博客

21 人参与  2022年05月14日 13:25  分类 : 《随便一记》  评论

点击全文阅读


目录

一.插入排序

1.插入排序思想

2.动态图形演示

 3.插排思路与图解

4.插入排序代码实现(升序)

5.时间复杂度,空间复杂度及稳定性

6.应用场景

二.希尔排序

1.引言

2.希尔排序思想

3.希尔排序动图

4.希尔排序思路图解

​ 5.代码实现

 6.时间复杂度,空间复杂度及稳定性分析

7.应用场景

三.选择排序(升序)

1.排序思想

2.选择排序动态图示

3.思路图解

 4.代码实现

5.时间复杂度,空间复杂度及稳定性分析

6.应用场景

四.堆排序

1.堆排序的排序思想

2.堆排序动图演示

 3.思路图解及代码实现

4.时间复杂度,空间复杂度及稳定性

5.应用场景

五.冒泡排序

1.排序思想

2.冒泡排序动图演示

3.冒泡排序图解

4.冒泡排序代码:

 5.时间复杂度,空间复杂度及稳定性

6.应用场景

六.快速排序

1.快速排序思想

2.快速排序动图演示

 3.思路图解

5.时间复杂度,空间复杂度及稳定性分析

6.应用场景

七.归并排序

1.归并思想

2.归并排序动图演示

 3.实现归并的思路图解

4.代码实现

八.计数排序

1.排序思想

2.应用场景

3,思路图解​

 4.代码实现

5.时间复杂度,空间复杂度及稳定性

6.应用场景


一.插入排序

1.插入排序思想

就是将待排序的数字插入到已经排序好的指定位置即可,直到所有需要排序的数字都插入到序列即可,从而得到一个有序的序列。(相当于我们平常玩扑克牌时将接到的牌插入到指定的位置)

2.动态图形演示
 

 3.插排思路与图解

4.插入排序代码实现(升序)

(1)控制排序的次数,保存需要插入的值。

(2)将大的元素向后移,找到合适的位置。

(3)将元素插入指定位置,然后继续执行上述操作。

(4)这里需要注意在找的时候可能会到最前面,需要注意数组越界问题。

代码实现:

//插入排序(升序)
    public static void insertSort(int[] arr){
        //排序的次数
        for(int i=1;i<arr.length;i++){
            int end=arr[i];//保存需要插入的值
            int k=i-1;//保存需要插入的位置
            while(k>=0 && arr[k]>end){//寻找需要插入的位置
                arr[k+1]=arr[k];
                k--;
            }
            arr[k+1]=end;//将元素是插入到指定的位置
        }
    }

5.时间复杂度,空间复杂度及稳定性

(1)时间复杂度:O(N^2)

 (2)空间复杂度:O(1)

执行过程中没有借助辅助空间。

(3)什么是稳定性

(4)稳定性:稳定       

6.应用场景

适合于基本有序的数组或者数据量特别小的数组,因为基本有序,那么中间进行比较的次数就会减少。

二.希尔排序

1.引言

如果需要排序的数字量特别多而且比较凌乱,而且还需要使用插入排序,这时候就有了希尔排序。

2.希尔排序思想

先选定一个合适的距离,然后以该距离为分割长度,依次对该距离的所有元素进行插入排序,然后再缩小这个距离,直到距离为1时结束。

3.希尔排序动图


 

4.希尔排序思路图解

这里每次对于gap间距的值为gap=gap/3+1来处理

 5.代码实现

 public static void shellSort(int[] arr){
        int gap=arr.length;
        while(gap>1){
            gap= gap/3+1;
           for(int i=gap;i<arr.length;i++){
                int end=arr[i];
                int k=i-gap;
                while(k>=0 && arr[k]>end){
                    arr[k+gap]=arr[k];
                    k-=gap;
                }
                arr[k+gap]=end;
           }
        }

    }

 6.时间复杂度,空间复杂度及稳定性分析

(1)时间复杂度

如果gap选取的不同,则时间复杂度就,对于希尔排序,时间复杂度没有一个确定的值,当前增量法的时间复杂度大致为O(N^1.25)到O(1.6N^1.25)之间。

(2)空间复杂度        

        O(1)

(3)稳定性分析

由于每次都时间隔排序,所以不稳定

7.应用场景

对于数据量特别大,数字比较凌乱的情况下,而且还需要使用插入排序的情况下,可以使用希尔排序来进行处理。

三.选择排序(升序)

1.排序思想

每次选择一个最大的数放在数组的末尾(或者每次选择一个最下的放在数组头,起始位置后移),然后数组长度-1,接着使用该方法,直到所有的元素排序完成即可。

2.选择排序动态图示

3.思路图解

 4.代码实现

    //选择排序(每次选最大的元素放在数组末尾)
    public static void selectSort(int[] arr){
        for(int i=0;i<arr.length-1;i++){
            int maxVal=0;
            for(int j=1;j<arr.length-i;j++){
                if(arr[maxVal]<arr[j]){
                    maxVal=j;
                }
            }
            if(maxVal!=arr.length-i)
            swap(arr,maxVal,arr.length-1-i);
        }
    }
    public static void swap(int[] arr,int left,int right){
        int tmp=arr[left];
        arr[left]=arr[right];
        arr[right]=tmp;
    }

5.时间复杂度,空间复杂度及稳定性分析

(1)时间复杂度

每一个元素都与前n-i-1个元素进行比较,所以时间复杂度为O(N^2)

(2)空间复杂度

没有额外空间的开辟,所以空间复杂度为O(1)

(3)稳定性

由于每次都是间隔进行交换,所以相同的元素最后位置可能会改变,所以不稳定。

6.应用场景

由于时间复杂度不好,平时应应用的比较少。

四.堆排序

1.堆排序的排序思想

堆排序)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

2.堆排序动图演示


 

 3.思路图解及代码实现

认识优先级队列与堆_小白 菜的博客-CSDN博客

4.时间复杂度,空间复杂度及稳定性

(1)时间复杂度

因为堆排序相当于删除元素,所以删除需要N次,然后每次向下调整最坏为二叉树的层数为,

所以时间复杂度为O(N*)

(2)空间复杂度

        O(1)

(3)稳定性

 由于间隔进行交换,所以不稳定。

5.应用场景

需要前k个最大或最小元素时,或者与其他排序一块使用

五.冒泡排序

1.排序思想

大的元素向下沉,小的元素向上浮。

2.冒泡排序动图演示

3.冒泡排序图解

4.冒泡排序代码:

    //冒泡排序
    public static void bubbleSort(int[] arr){
        //冒泡的趟数
        for(int i=0;i<arr.length-1;i++){
            boolean flag = false;//判断是否交换
            //在子区间进行冒泡
            for(int j=0;j<arr.length-1-i;j++){
                if(arr[j]>arr[j+1]){
                    swap(arr,j,j+1);//交换2个元素
                    flag=true;
                }
            }
            //没有再进行交换则退出
            if(!flag){
                return;
            }
        }
    }
   public static void swap(int[] arr,int left,int right){
        int tmp=arr[left];
        arr[left]=arr[right];
        arr[right]=tmp;
    }

 5.时间复杂度,空间复杂度及稳定性

(1)时间复杂度

O(N^2)

(2)空间复杂度

O(1)

(3)稳定性

没有间隔进行交换,所以稳定

6.应用场景

基本不使用

六.快速排序

1.快速排序思想

任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

原理:以基准值为中心,将区间划分为左边的值都小于基准值,右边的值都大于基准值,直到所有元素有序即可。

2.快速排序动图演示

 3.思路图解

 

 

 4.代码实现

如果递归深度过深,我们可以对递归到小区间的时候使用插入排序,这样可以提高排序速度,这样也是对快排进行优化。

//使用三数取中法选择合适基准值,对快排优化
    public static int midDiv(int[] arr,int left,int right){
        int mid = left+(right-left)>>1;
        //在左右值比较后然后中间值与左右进行比较
        if(arr[left]<arr[right-1]){//左小右大
            if(arr[mid]<arr[left]){
                return left;
            }else if(arr[mid]>arr[right-1]){
                return right-1;
            }else{
                return mid;
            }
        }else {//左大右小
            if(arr[mid]<arr[right-1]){
                return right-1;
            }else if(arr[mid]>arr[left]){
                return left;
            }else {
                return mid;
            }
        }

    }

//前后指针法,划分区间,得到基准值
    public static int partiton(int[] arr,int left,int right){
        int prev=left-1;
        int cur = left;
        int midDiv=midDiv(arr,left,right);//找合适基准值的位置
        swap(arr,midDiv,right-1);//基准值位置与最后元素交换
        int div = arr[right-1];
        while(cur<right){
           if(arr[cur]<div && ++prev !=cur){
               //交换
               swap(arr,prev,cur);
           }
           cur++;
        }
        if(++prev!=right-1)
        swap(arr,prev,right-1);
        return prev;
    }
//快速排序(递归版)
    public static void quickSort(int[] arr,int left,int right){
            //剩一个元素排序结束
            if(right-left>1){
                int div = partiton(arr,left,right);//找基准值划分区间
                //左[left,val)
                quickSort(arr,left,div);
                //右[val+1,right)
                quickSort(arr,div+1,right);
            }

5.时间复杂度,空间复杂度及稳定性分析

(1)时间复杂度

注意:对于未选择三数取中的方法时,最坏的时间复杂度为O(N^2),这是因为可能每次划分的时候左边的都比最后一个小,相当于每次只能排好一个,每一个需要的时间大概为N,共有N个元素,所以为O(N^2),但是当每次最后一个数都为中间值的时候,时间复杂度就变为O(*N),为递归的深度。

通过优化后最终得到的时间复杂度为O(*N)

(2)空间复杂度

在递归的时候借助了辅助空间,空间复杂度为递归的深度,所以空间复杂度为O()。

(3)稳定性

间隔进行了交换,所以不稳定。

6.应用场景

在数据特别随机的时候使用快排比较高效

七.归并排序

1.归并思想

该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

2.归并排序动图演示

 3.实现归并的思路图解

·

 

 

4.代码实现

public static void mergeSort(int[] arr,int left,int right,int[] temp){
        if(right-left>1){
            int mid = left+((right-left)>>1);//注意优先级问题,否则会出现栈溢出
            //分区间
            mergeSort(arr,left,mid,temp);
            mergeSort(arr,mid,right,temp);
            //(合区间)将划分好的区间进行有序合并
            mergeData(arr,left,mid,right,temp);
            //将合并好的区间拷贝的原数组中
            System.arraycopy(temp,left,arr,left,right-left);
        }

    }
    //负责将划分好的区间进行合并
    public static void mergeData(int[] arr,int left,int mid,int right,int[] temp){
        int leftT=left;
        int midT = mid;
        int index=left;
        while(leftT<mid && midT<right){
            if(arr[leftT]<=arr[midT]){
                temp[index++]=arr[leftT++];
            }else {
                temp[index++]=arr[midT++];
            }
        }
        while(leftT<mid){
            temp[index++]=arr[leftT++];
        }
        while(midT<right){
            temp[index++]=arr[midT++];
        }
    }

5.时间复杂度,空间复杂度及稳定性分析

(1)时间复杂度

O(*N)

(2)空间复杂度

这里分析空间复杂度的时候不能按照递归深度*合并次数来进行计算,因为每次递归合并后,就将之前的空间释放掉了,所以借助的空间只有之前的辅助空间用来存储合并有序的数,最终空间复杂度为O(N)

(3)稳定性

在进行归并的时候没有间隔,所以稳定。

6.应用场景

应用于外部排序。

八.计数排序

1.排序思想

统计相同元素出现的次数,然后根据统计的次数回收到原来的数组中即可。

2.应用场景

对于数据特别集中在某个范围内时,效率是很高的。

3,思路图解

 

 4.代码实现

   public static void countSort(int[] arr){
        int size=arr.length;
        if(size==0){
            return;
        }
        int max=arr[0];
        int min=arr[0];
        //获取最大最小值
        for(int i=1;i<size;i++){
            if(arr[i]>max){
                max=arr[i];
            }
            if(arr[i]<min){
                min=arr[i];
            }
        }
        //这里数组的大小为max-min+1,直接使用max-min会出现数组越界
        int[] tmp = new int[max-min+1];
        //将每一个值出现的次数保存到对应的位置即可
        for(int i=0;i<size;i++){
            tmp[arr[i]-min]++;
        }
        int index=0;
        //将结果进行还原
        for(int i=0;i<tmp.length;i++){
            for(int j=0;j<tmp[i];j++){
                arr[index++]=min+i;
            }
        }
    }

5.时间复杂度,空间复杂度及稳定性

(1)时间复杂度

时间复杂度为:O(N),为元素的个数

(2)空间复杂度

空间复杂度为:O(Max-Min)

(3)稳定性

没有间隔交换稳定

6.应用场景

对于数字比较集中在某个区间范围内时排序效率比较高。


点击全文阅读


本文链接:http://zhangshiyu.com/post/40127.html

复杂度  排序  时间  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1