排序算法的原理与实现

1. 交换排序

交换排序,即交换元素在序列中的位置,利用这种方法进行排序。冒泡排序、快速排序均为交换排序法。

1.1 冒泡排序

1.1.1 思想

依次从序列的开头比较两个相邻的元素,如果第一个元素大于第二个元素,则交换它们的位置,第一趟比较下来最大的元素固定在序列的末尾,它在下一趟排序中不再参与比较。重复以上步骤,直到待排序序列长度为1,此时序列排序完成。

1.1.2 动图演示

图片来源:https://www.cnblogs.com/onepixel/articles/7674659.html
在这里插入图片描述

1.1.3 代码实现

public static void bubbleSort(int[] nums) {
    int length = nums.length;

    for (int i = 0; i < length - 1; ++i) {
        for (int j = 0; j < length - i - 1; ++j) {
            if (nums[j] > nums[j + 1]) {
                int temp = nums[j];
                nums[j] = nums[j + 1];
                nums[j + 1] = temp;
            }
        }
    }
}

1.1.4 算法优化

如果某一趟排序没有发生元素交换,则表明序列已经有序,无需再进行排序。可以设置一个标志位,若某一趟排序未发生交换,则退出排序。
代码如下:

public static void bubbleSort(int[] nums) {
    int length = nums.length;

    boolean isChange;
    for (int i = 0; i < length - 1; ++i) {
        isChange = false;

        for (int j = 0; j < length - i - 1; ++j) {
            if (nums[j] > nums[j + 1]) {
                int temp = nums[j];
                nums[j] = nums[j + 1];
                nums[j + 1] = temp;

                isChange = true;
            }
        }

        //未发生变换,则表明序列已经有序
        if (!isChange)
            break;
    }
}

1.1.5 复杂度分析

最坏情况:序列为逆序,则第一次需交换n-1次,第二次需交换n-2次…此时的时间复杂度为O(n2)
最好情况:使用优化后的算法,若序列已经是有序序列,则只需进行一次排序,时间复杂度为O(n)
平均时间复杂度为O(n2),空间复杂度为O(1)。
是一种稳定的排序算法。

1.2 快速排序

介绍快速排序之前,需要先介绍一下分治法,所谓分治,即“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并
在这里插入图片描述

1.2.1 思想

快速排序的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

快速排序使用分治法将一个序列分成两个序列,一趟快排的过程如下:

  1. 设置两个变量i、j,排序开始的时候:i=0,j=length-1;
  2. 从序列中选出一个元素作为“基准”(pivot),一般选择序列的第一个元素作为基准,即pivot = nums[0]
  3. 从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于pivot 的值nums[j],交换nums[j]和nums[i]的值;
  4. 从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于pivot的nums[i],交换nums[i]和nums[j]的值;
  5. 重复3、4步骤,直到i==j,该趟排序结束,pivot值的位置固定,左侧的值均小于等于pivot,右侧的值均大于等于pivot。

1.2.2 图片演示

一趟快速排序的过程(图片来源https://blog.csdn.net/donglynn/article/details/49758003)
在这里插入图片描述

扫描二维码关注公众号,回复: 5743729 查看本文章

1.2.3 代码实现

public static void quickSort(int[] nums, int left, int right) {
    int i = left;
    int j = right;
    int pivot = nums[left];

    while (i < j) {
        //从后往前比较
        while (i < j && nums[j] >= pivot) {
            --j;
        }
        if (nums[j] < pivot) {
            swap(nums, i, j);
        }

        //从前往后比较
        while (i < j && nums[i] <= pivot) {
            ++i;
        }
        if (nums[i] > pivot) {
            swap(nums, i, j);
        }
    }

    //对左分区进行快速排序
    if (left < i) {
        quickSort(nums, left, i - 1);
    }
    //对右分区进行快速排序
    if (j < right) {
        quickSort(nums, j + 1, right);
    }
}

public static void swap(int[] nums, int i, int j) {
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}

1.2.4 复杂度分析

最坏情况:整个序列已经有序或者倒序(每次划分区间,都导致其中一个区间为空),此时快速排序退化成冒泡排序,时间复杂度为O(n2);
最好情况:每次划分区间都将区间平分成两份,此时的时间复杂度为O(nlog2n);
平均时间复杂度为O(nlog2n),空间复杂度为O(log2n)。
是一种不稳定的排序算法。

暂时写到这,后面的下次补上。

猜你喜欢

转载自blog.csdn.net/xuxiang668/article/details/88807924