文章目录

  • 1.排序的基本概念
  • 1.1什么是排序
  • 1.2稳定性
  • 1.3 排序的应用
  • 2.插入排序
  • 2.1直接插入排序的原理
  • 2.2插入排序实现
  • 3.希尔排序
  • 3.1希尔排序的原理
  • 3.2希尔排序的实现
  • 4.选择排序
  • 4.1选择排序的原理
  • 4.2.选择排序的实现
  • 5.堆排序
  • 5.1基本原理
  • 5.2堆排序的实现


1.排序的基本概念

1.1什么是排序

排序:就是一串记录,按照其中某个或某个关键字的大小,递增或递减的排列起来的操作。通常意义上的排序,都是指的是原地排序(在原有的数组的基础上进行排序,而不是建立新的数组)。

1.2稳定性

两个相等的数据,如果经过排序后,排序算法能保证其相对位置不发生变化,则我们称该算法是具备稳定性的排序。

下面的排序具有稳定性:

排序 空在最后 java Compare_插入排序

1.3 排序的应用

排序的用处很多,比如是说淘宝上的商品的价格从高到低,或者说是中国大学的排名。

2.插入排序

2.1直接插入排序的原理

整个区间被分为两部分:待排序区间和已排序区间。然后每次在待排序区间选择一个元素,往有序区间内选择合适的位置插入。

排序 空在最后 java Compare_排序算法_02

2.2插入排序实现

import java.util.Arrays;

public class MySort {
    public static void insertSort(int [] arr){
      int bound=1;
      //[0,bound)是已排序区间
        //[bound,length)是待排序区间
        for(;bound<arr.length;bound++){
            //里面每次就要执行具体的比较插入过程了
            //取出待排序区间的最开始的元素
            int v=arr[bound];
            int cur=bound-1;
            for(;cur>=0;cur--){
                //这个循环就是比较插入的细节
                //拿着v这个值一次往前比较找到合适的位置
                if(arr[cur]>v){
                    //这就说明v插入到arr[cur]之前
                    arr[cur+1]=arr[cur];
                }else{
             //说明已经找到合适的位置了,可以结束循环了
                    break;
                }
            }
        //这个所谓的合适的位置就是cur的后面,就是cur+1
            arr[cur+1]=v;
        }
    }

    public static void main(String[] args) {
        int [] arr={4,8,2,9,5,1,0};
        insertSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

注意: 插入排序是一个稳定排序,但是要注意代码的实现细节,插入排序的时间复杂度为O(N^2),空间复杂度为O(1)。
插入排序的两个特点:
1)如果数组的长度比较短,则排序效率会高;
2)如果数组相对有序,排序效率也很高。

3.希尔排序

希尔排序,是争对插入排序来进行进一步的改进的。

3.1希尔排序的原理

希尔排序的基本思想:

首先选定一个整数gap,然后把所有待排序文件中的所有记录分成组,所有距离为gap的分为同一组,并对每一组的内容进行排序。然后取不同的gap(比前一个gap小),重复上述的分组和排序工作,直到gap为1时,此时所有的记录里排序即可。

排序 空在最后 java Compare_排序算法_03


gap比较常见的序列选择为:

size/2 ,size/4,size/8…1 称为希尔序列。

3.2希尔排序的实现

public class MySort{
public static void shellSort(int [] arr){
     //指定的gap序列,就用希尔序列来指定
       int gap=arr.length/2;
       while(gap>=1){
           _shellSort(arr,gap);
           gap=gap/2;
       }
    }

    public static void _shellSort(int[] arr,int gap ){
        //进行分组插排,分组的依据就是gap
        //gap同时也表示的分的组数
        //同组相邻的元素,下标的插值就是gap
        int bound=gap;
        for(;bound<arr.length;bound++){
            int v=arr[bound];
            int cur=bound-gap;
            for(;cur>=0;cur=cur-gap){
                if(arr[cur]>v){
                    //进行搬运
                    arr[cur+gap]=arr[cur];
                }else{
                    break;
                }
            }
            arr[cur+gap]=v;
        }
    }

    public static void main(String[] args) {
        int [] arr={4,8,2,9,5,1,0};
        shellSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

希尔排序的时间复杂度仍然为O(N^2),希尔排序的空间复杂度为O(1),稳定性:不稳定排序。

4.选择排序

4.1选择排序的原理

把整个数组分成两个区间:待排序区间和已排序区间,遍历带排序区间,通过打擂台的方式,找出这个区间的最小元素,以待排序区间开始位置作为擂台。以下图为例,刚开始以9作为擂台,和待排序区间的元素比较,刚开始5比9小,然后交换元素的位置,5作为待排序区间的第一个元素,然后5与2比较,2小,然后交换元素的位置,然后2与后面的7 3 6 8按顺序比较,还是2最小,因此2就是排序好了的,以此类推。

排序 空在最后 java Compare_希尔排序_04

4.2.选择排序的实现

public class MySort{
public static void selectSort(int [] arr){
        //创建一个变量bound表示已排序区间和待排序区间的边界
        //[0,bound)已排序区间
        //[bound,length)待排序区间
        int bound=0;
        for(;bound<arr.length;bound++){
            //里层的循环要进行打擂台的过程
            //擂台的位置就是bound的下标的位置
            for(int cur=bound+1;cur<arr.length;cur++){
                if(arr[cur]<arr[bound]){
               //如果发现挑战者比擂主小,就交换两个元素
                    swap(arr,bound,cur);
                }
            }
        }
    }

    public static void swap(int [] arr,int x,int y){
       int tmp=arr[x];
       arr[x]=arr[y];
       arr[y]=tmp;
    }

    public static void main(String[] args) {
        int [] arr={4,8,2,9,5,1,0};
        selectSort(arr);
        System.out.println(Arrays.toString(arr));
    }
  }

选择排序的时间复杂度为O(N^2),空间复杂度为O(1),也是不稳定排序。

5.堆排序

5.1基本原理

堆排序?(升序)我们肯定一开始就想到的是建立一个小堆,每次取堆顶元素,依次取N次,这确实得到了升序结果,但是这种思路,不是原地排序。

为了达到原地排序的效果,就需要建立一个大堆,然后每次删除堆顶元素(拿堆顶元素和堆的最后一个元素交换),此时最大值就跑到最后面了,此时这个最大值虽然从堆上删除了,但是正好来到了数组的最末端,从0号元素向下调整,使前面的元素重新成为堆,再次把0号进行前面的操作。

排序 空在最后 java Compare_希尔排序_05


后面的操作类似于上图。

5.2堆排序的实现

public static void heapSort(int [] arr){
        //1.首先建堆
        createHeap(arr);
       //2.需要循环取出堆顶元素,和最后一个元素交换并初值
        //再对0号元素调整
        int heapSize=arr.length;
        for(int i=0;i<arr.length;i++){
            swap(arr,0,heapSize-1);
            heapSize--;
            shiftDown(arr,heapSize,0);
        }
    }
    
    public static void createHeap(int [] arr){
        for(int i=(arr.length-1-1)/2;i>=0;i--){
            shellSort(arr);
        }
    }

    public static void shiftDown(int [] arr,int size,int index){
        int parent=index;
        int child=2*parent+1;
        while(child<size){
            //找左右字数比较打大的
            if(child+1<size&&arr[child+1]>arr[child]){
                child=child+1;
            }
            if(arr[parent]<arr[child]){
              swap(arr,parent,child) ; 
            }
            parent=child;
            child=2*parent+1;
        }
    }

    public static void swap(int [] arr,int x,int y){
       int tmp=arr[x];
       arr[x]=arr[y];
       arr[y]=tmp;
    }

    public static void main(String[] args) {
        int [] arr={4,8,2,9,5,1,0};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}