Java实现排序算法(2)

七大常见排序算法

  1. 直接插入排序
  2. 希尔排序
  3. 选择排序
  4. 堆排序
  5. 冒泡排序
  6. 快速排序
  7. 归并排序

接上文(前四种排序算法详解),后三种排序算法如下:

冒泡排序

算法描述:

  • 定义两个下标, i 用来描述数组大小以及判定每次循环 j 的循环次数,j 用来判断比较次数.两个下标搭配使用.
  • 循环过程中,j 和 j+1 下标元素进行比较. 两两进行交换.
  • 定义 flg 来优化排序.

过程逐步图解:
在这里插入图片描述
代码实现:

public class BubbleSort {
    public void  bubbleSort(int[] array){
        for (int i = 0; i < array.length; i++) {
            boolean flg = false;  // 进行优化
            for (int j = 0; j < array.length-1-i; j++) {  // 比较次数. 一个长度为 n 的数组需要比较 n-1 次(最坏情况下).
                if (array[j] > array[j+1]){
                    swap(array,j,j+1);
                    flg = true;
                }
            }
            if (flg == false){  // 当 j 循环完, flg 还为 false,则证明此时已经有序了,不需要 i 向后面走了
                return;
            }
        }
    }

    private void swap(int[] array,int i,int j){
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    public static void main(String[] args) {
        BubbleSort sort = new BubbleSort();
        int[] array = {12,8,32,45,56,7};
        sort.bubbleSort(array);
        System.out.println(Arrays.toString(array));
    }
}

输出结果:
在这里插入图片描述

时间复杂度:O(n^2)
稳定性:稳定

快速排序

算法描述:

  • 以首个元素为基准(pivot),将数组分成两个部分.
  • 对这两个部分分别进行排序(递归地进行).
  • 找到比基准大的数和比基准小的数,这两数进行交换.
  • 当 left 和 right 相遇的时候,将首个元素的值与 left或者right 进行交换.
  • 每部分进行递归都会再分成两部分进行排序.
  • 重复上述循环,直到数组有序.

过程逐步图解:
在这里插入图片描述

代码实现:

    public void quickSort2(int[] array){
        quick2(array,0,array.length-1);
    }
    private void quick2(int[] array,int start,int end){
        // 为什么取大于号  例子:1,2,3,4 这样一来 1 本身就是最小的,此时 end 进行 -- 的话,下标就会为 -1,越界
        if (start >= end){     // 递归结束条件. 当 start 和 end 相遇时,进行终止
            return;
        }

        int pivot = partition2(array,start,end);  // 返回一次递归 排序的基准
        quick2(array,start,pivot-1);     // 对基准左边进行递归 排序
        quick2(array,pivot+1,end);    // 对基准右边进行递归 排序
    }
    private int partition2(int[] array,int left,int right){
        int temp = array[left];  // 取首个下标元素为基准
        int i = left; // 记录首个元素的下标,方便后面 left与right 相遇时进行交换
        while (left < right){
            while (left < right && array[right] >= temp){  // right 一直向左边 -- ,找到比 temp 小的值
                right--;
            }
            while (left < right && array[left] <= temp){   left 一直向右边 ++ ,找到比 temp 大的值
                left++;
            }
            // 将 left 与 right 下标的值进行交换
            swap(array,left,right);
        }
        // 即 left 和 right相遇
        swap(array,left,i);
        return left;
    }
    private void swap(int[] array,int i,int j){
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    public static void main(String[] args) {  // Hoare法测试
        QuickSort sort = new QuickSort();
        int[] array = {1,4,3,6,8,2,9,0,5,7};
        sort.quickSort2(array);
        System.out.println(Arrays.toString(array));
    }

运行结果:
在这里插入图片描述

时间复杂度:最好情况:O(N*logN) 最坏情况:O(N^2)
稳定性:不稳定

归并排序

算法描述:直接看图解和代码注释更清晰.
逐步图解:
在这里插入图片描述
代码实现:

    public void mergeSort(int[] array){
        int grp = 1;  // 先
        while (grp < array.length){  // grp 若等于数组大小,即证明数组此时已经有序了,就不需要再次进行排序了
            for (int i = 0; i < array.length; i = i + grp*2) {
                int left = i;
                int mid = left + grp-1;
                if (mid >= array.length){  // mid 有可能会越界,进行修正
                    mid = array.length - 1;
                }
                int right = mid + grp;
                if (right >= array.length){  // right 有可能会越界,进行修正
                    right = array.length-1;
                }
                mergeSum(array,left,right,mid); // 进行合并
            }
            grp = grp * 2;  // 每次扩大2倍分组
        }
    }
    private void mergeSum(int[] array,int start,int end,int mid){   // 将排好序的数组进行合并
        int s1= start;
        int s2 = mid+1;
        int[] temp = new int[end-start+1];  // 定义一个新的数组,将比较过的元素放到该数组,即最终这个数组就是两个数组合并的有序数组了
        int k = 0; // temp数组下标
        while (s1 <= mid && s2 <= end){ // 对分开的两个数组进行比较
            if (array[s1] <= array[s2]){  // 第一个数组的第一个元素的值小于第二个数组的第一个元素的值
                temp[k] = array[s1];   // 将小的元素放到新的数组中. 那个数组元素小,那个数组的下标就向后面移动
                s1++;
                k++;
            }else {
                temp[k] = array[s2];
                s2++;
                k++;
            }
        }
        while (s1 <= mid){  // 左边数组还有元素
            temp[k] = array[s1];
            s1++;
            k++;
        }
        while (s2 <= end){  // 右边数组还有元素
            temp[k] = array[s2];
            s2++;
            k++;
        }
        for (int i = 0; i < temp.length; i++) {   // 进行数组合并
            array[i+start] = temp[i];
        }
    }
	public static void main(String[] args) {
        MergeSort sort = new MergeSort();
        int[] array = {1,43,21,3,0,9,11,8};
        sort.mergeSort(array);
        System.out.println(Arrays.toString(array));
    }

运行结果:
在这里插入图片描述

时间复杂度:O(n*logn)
稳定性:稳定

总结

算法的分类:

在这里插入图片描述

补充:
分治法,字面意思是“分而治之”,就是把一个复杂的问题分成两个或多个相同或相似的子问题,再把子问题分成更小的子问题直到最后子问题可以简单地直接解决,原问题的解就是子问题解的合并。
分治法的基本思想:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。

稳定性

稳定:

  • 归并排序
  • 直接插入排序
  • 冒泡排序

不稳定:

  • 堆排序
  • 快速排序
  • 希尔排序
  • 选择排序

时间复杂度

  1. 直接插入排序:O(n^2)
  2. 希尔排序:O(n^1.3)
  3. 选择排序:O(n^2)
  4. 堆排序:O(n*logn)
  5. 冒泡排序:O(n^2)
  6. 快速排序:O(n*logn)
  7. 归并排序:O(n*logn)
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值