排序算法
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 思想
快速排序的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序使用分治法将一个序列分成两个序列,一趟快排的过程如下:
- 设置两个变量i、j,排序开始的时候:i=0,j=length-1;
- 从序列中选出一个元素作为“基准”(pivot),一般选择序列的第一个元素作为基准,即pivot = nums[0]
- 从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于pivot 的值nums[j],交换nums[j]和nums[i]的值;
- 从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于pivot的nums[i],交换nums[i]和nums[j]的值;
- 重复3、4步骤,直到i==j,该趟排序结束,pivot值的位置固定,左侧的值均小于等于pivot,右侧的值均大于等于pivot。
1.2.2 图片演示
一趟快速排序的过程(图片来源https://blog.csdn.net/donglynn/article/details/49758003)
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)。
是一种不稳定的排序算法。
暂时写到这,后面的下次补上。