几种常见排序

一、快速插入排序
二、希尔排序
三、选择排序
四、堆排序
五、冒泡排序
六、快速排序
七、归并排序



文章目录

  • 几种常见排序
  • 前言
  • 一、快速插入排序
  • 二、希尔排序
  • 三、选择排序
  • 四、堆排序
  • 五、冒泡排序
  • 六、快速排序
  • 七、归并排序
  • 总结
  • 排序的稳定性
  • 堆排序、快速排序、希尔排序、直接选择排序是不稳定的排序算法,而冒泡排序、直接插入排序、折半插入排序、归并排序是稳定的排序算法。



前言

将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程叫做排序。
排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。分内部排序和外部排序,若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。



一、快速插入排序

Example java 如何排序 java排序总结_java


(为了方便理解,找了一些动画帮助理解)

插入排序 定义j i;j往前走 找每次比i大的数;然后往后(j+i)放;直到 比i小或者走到0了 停止
i+1进行下一轮
// 时间复杂度O(n^2) 空间复杂度O(1) 如果数组本身就有序 那么选插入排序是最快的 O(n)

//插入排序 定义j i;j往前走 找每次比i大的数;然后往后(j+i)放;直到 比i小或者走到0了 停止
// i+1进行下一轮
    // 时间复杂度O(n^2)  空间复杂度O(1)   如果数组本身就有序 那么选插入排序是最快的 O(n)
    public static void insertSort(int[] array){
        for (int i = 0; i <array.length ; i++) {
            int tmp = array[i];
            int j = i-1;
            for (;j>=0 && tmp < array[j] ;j--){
                array[j+1] = array[j];
            }
                array[j+1] =tmp;
        }
    }

二、希尔排序

Example java 如何排序 java排序总结_java_02


希尔排序 先给数据分组 最好分成素数组例如1、3、5、7;并且最后一定是1组;所以应该先细后粗的分:5、3、1
分完组后 给每一组进行插入排序
//时间复杂度O(n1.3~n1.5) 空间复杂度O(1)

//希尔排序  先给数据分组 最好分成素数组例如1、3、5、7;并且最后一定是1组;所以应该先细后粗的分:5、3、1
    //分完组后 给每一组进行插入排序
    //时间复杂度O(n^1.3~n^1.5)  空间复杂度O(1)
    public void insertSort(int[] array,int gap){
        for (int i = gap; i <array.length ; i++) {
            int tmp = array[i];
            int j = i-gap;
            for (;j>=0 && array[j]>tmp;j--){
                array[j+gap] = array[j];
            }
            array[j+gap] = tmp;
        }
    }
    public  void  shellSort(int[] array){
        int[] team = {5,3,1};
        for (int i = 0; i < team.length; i++) {
            insertSort(array,team[i]);
        }
    }

三、选择排序

Example java 如何排序 java排序总结_java_03


选择排序 定义 i j i为最小的 j往后走 找到比i小的值交换,再往后走
走完一圈找到第一个最小值在0位置,继续i+1找第二个最小值
时间复杂度O(n^2) 空间复杂度O(1)

//选择排序  定义 i j i为最小的 j往后走 找到比i小的值交换,再往后走
 // 走完一圈找到第一个最小值在0位置,继续i+1找第二个最小值
    //时间复杂度O(n^2)  空间复杂度O(1)
    public static void selectSort(int[] array){
        for (int i = 0; i < array.length; i++) {
            for (int j = i+1; j <array.length ; j++) {
                if(array[j] < array[i]){
                    int tmp = array[j];
                    array[j] = array[i];
                    array[i] = tmp;
                }
            }
        }
    }

四、堆排序

Example java 如何排序 java排序总结_Example java 如何排序_04


堆排序 先交换在调整 向上调整 或者 向下调整–确定父亲节点(传入参数)
然后找到孩子节点 比较大小 小的往上放
需要注意的是 调整的时候传入的参数(对应) ,交换的时候每次最后一个换完就要size-1
//时间复杂度O(n^lgn) 空间复杂度O(1)

//堆排序 先交换在调整 向上调整 或者 向下调整--确定父亲节点(传入参数)
 // 然后找到孩子节点  比较大小 小的往上放
    //需要注意的是 调整的时候传入的参数(对应) ,交换的时候每次最后一个换完就要size-1
    //时间复杂度O(n^lgn)  空间复杂度O(1)
    public static void swap(int[] array, int top, int len){ //数组,第一个数,最后一个数(每调整一次都会改变 注意传参的时候)
        int tmp =array[top];
        array[top] = array[len];
        array[len] = tmp;
    }
    public static void shiftDown(int[] array, int parent, int size){
        int child = parent*2+1;
        while (child < size){
            if(child+1 <size && array[child] < array[child+1]){
                child++;
            }
            if(array[child] > array[parent]){
                int tmp = array[parent];
                array[parent] = array[child];
                array[child] = tmp;
                parent = child;
                child = parent*2+1;
            }else {
                break;
            }
        }
    }
    public static void createHeap(int[] array){
        for (int i = (array.length-1-1)/2; i >=0 ; i--) {
            shiftDown(array,i,array.length);
        }
    }
    public static void heapSort(int[] array){
        //大堆
        createHeap(array);
        //排序
       int end = array.length-1;
       while (end > 0){
           int tmp = array[0];
           array[0] = array[end];
           array[end] = tmp;
           shiftDown(array,0,end);
           end--;
       }
    }

五、冒泡排序

Example java 如何排序 java排序总结_java_05

//冒泡排序 i是排序的总趟数   j是每一趟比较的次数  j没完成一轮就有一个大数到最后成为有序
    //时间复杂度O(n^2)  空间复杂度O(1)
    public static void bubbleSort(int[] array){
        for (int i = 0; i <array.length-1 ; i++) {
            boolean flag = false;//优化
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j] > array[j+1]){
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    flag = true;
                }
            }
            if(flag==false){
                break;
            }
        }
    }

六、快速排序

Example java 如何排序 java排序总结_排序算法_06


递归方式实现(挖坑法)

快速排序 从待排序中选出一个基准值(pivot)一般为i下标, 定义两个指针i,j 分别从0 和length-1开始,分别找比基准值小的值,和比基准值大的值

//难点 找到基准值 并且找到每次左右边的基准值,

//快速排序  从待排序中选出一个基准值(pivot)一般为i下标, 定义两个指针i,j 分别从0 和length-1开始,分别找比基准值小的值,和比基准值大的值
    //难点 找到基准值 并且找到每次左右边的基准值,
    public static void quickSort(int[] array){
        quickSortChild(array,0,array.length-1);
    }
    public static void quickSortChild(int[] array, int low, int high){
        if(low >= high) return;
        int pivot = partition(array,low,high);
        quickSortChild(array,low,pivot-1);
        quickSortChild(array,pivot+1,high);
    }
    public static int partition(int[] array, int left, int right){ //找基准值
        int pivot = array[left];
        while (left<right){
            while (left<right && array[right] >= pivot){
                right--;
            }
            if(array[right] < pivot){  //if-else语句可以直接优化为  array[left] = array[right];
                array[left] = array[right]; //此时right 空了
            }else {
                array[left] = pivot;
                break;
            }
            while (left<right && array[left] <= pivot){
                left++;
            }
            if(array[left] > pivot){  //if-else语句可以直接优化为  array[right] = array[left];
                array[right] = array[left];
            }else {
                array[left] = pivot;
                break;
            }
        }
        return left;
    }

非递归方式实现
非递归实现 利用栈 还是找基准值 然后分别将 left high放入栈 使得每一个基准值的左边都是小于基准值的 基准值的右边都是大于基准值的

//快速排序  非递归实现 利用栈 还是找基准值 然后分别将 left high放入栈 使得每一个基准值的左边都是小于基准值的  基准值的右边都是大于基准值的
    public static void quickSortNor(int[] array){
        Stack<Integer> stack = new Stack<>();
        stack.push(array.length-1);
        stack.push(0);
        while (!stack.isEmpty()){
            int left = stack.pop();
            int  right = stack.pop();
            if(left >= right){
                continue;
            }
          int pivot =  partition(array,left,right);
            stack.push(right);
            stack.push(pivot+1); //基准值右边右边

            stack.push(pivot-1); //基准值左边
            stack.push(left);

        }

    }

七、归并排序

Example java 如何排序 java排序总结_Example java 如何排序_07


归并排序的非递归实现

外层有一个分组函数来把原数组进行二分,然后调用下方函数,每一次的二分利用临时数组来保存结果,分后的数据进行比较小的放在前面,这样每一组都有序,在进行整理合并,利用合并两个有序数组的思想

public static void merge(int[] array,int low,int mid,int high) {
        int[] tmpArr = new int[high-low+1];
        int k = 0;// 数组下标
        int s1 = low;
        int s2 = mid+1;
        while (s1 <= mid && s2 <= high) {
            if(array[s1] <= array[s2]) {
                tmpArr[k++] = array[s1++];
            }else {
                tmpArr[k++] = array[s2++];
            }
        }

        while (s1 <= mid) {   //左边 数据不为空
            tmpArr[k++] = array[s1++];
        }

        while (s2 <= high) { //右边 数据不为空
            tmpArr[k++] = array[s2++];
        }
    //将temp中的元素全部拷贝到原数组中
        for (int i = 0; i < tmpArr.length; i++) {
            array[i+low] = tmpArr[i]; //放入指定位置 不能从开始放 会覆盖数据导致结果有误
        }

    }

此处代码在进行分组操作。

public static void mergeSortRec(int[] array,int low,int high) {
        if(low >= high) {
            return;
        }
        int mid = (high+low) / 2;
        mergeSortRec(array,low,mid);
        mergeSortRec(array,mid+1,high);
        merge(array,low,mid,high);
}

此处如果对归并排序的递归实现还是不太清楚,可以参考[] 的讲解,由于说明更加清晰明白

总结

Example java 如何排序 java排序总结_Example java 如何排序_08

排序的稳定性

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

需要注意的是,排序算法是否为稳定的是由具体算法决定的,不稳定的算法在某种条件下可以变为稳定的算法,而稳定的算法在某种条件下也可以变为不稳定的算法。

堆排序、快速排序、希尔排序、直接选择排序是不稳定的排序算法,而冒泡排序、直接插入排序、折半插入排序、归并排序是稳定的排序算法。