选择排序
选择排序的基本思想:
每一轮选取未排定的部分中 最小的元素交换到未排定部分的最开头,经过若干个步骤,就能排定整个数组。
参考代码:
//选择排序
public class Selectionsort {
public int[] sortArray(int[] nums) {
int len = nums.length;
//当数组的长度小于2(即长度为0或者1)时,直接返回该数组;
if (len < 2) {
return nums;
}
for (int i = 0; i < len; i++) {
//在nums[i...len-1]中选出最小的元素
for (int j = i + 1; j < len; j++) {
if (nums[j] < nums[i]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
return nums;
}
}
冒泡排序
冒泡排序的基本思想
两两比较相邻两个位置的元素,把较大的元素交换到上方;
每一轮都会把当前最大的元素冒泡到数组的末尾。
「选择排序」和「冒泡排序」的区别:
「冒泡排序」每一轮的确是选出最值,但它是通过两两比较和交换,把最值元素渐渐地交换到数组的末尾,每一轮选出最值,需要交换多次;
「选择排序」每一轮选出最小值,交换到数组的前面,每一轮只交换一次。
参考代码:
//冒泡排序
public class BubbleSort {
public int[] sortArray(int[] nums) {
int len = nums.length;
for (int i = 0; i < len - 1; i++) {
for (int j = 1; j < len; j++) {
if (nums[j - 1] > nums[j]) {
int temp = nums[j - 1];
nums[j - 1] = nums[j];
nums[j] =temp;
}
}
}
return nums;
}
}
冒泡排序的优化
如果在一次循环中,都没有「冒泡」行为发生,整个排序任务就可以提前终止。
优化参考代码:
//冒泡排序优化
public class BubbleSort {
public int[] sortArray(int[] nums) {
int len = nums.length;
for (int i = 0; i < len - 1; i++) {
/*可以设置布尔变量 sorted,假设每一轮循环开始假设数组是有序的;
一旦在比较的过程中执行了交换,说明数组不是有序的,将 sorted 设置为 false;
如果在一次循环中,都没有「冒泡」行为发生,才可以认为剩下的部分是有序的.*/
boolean sorted = true;
for (int j = 1; j < len; j++) {
if (nums[j - 1] > nums[j]) {
sorted = false;
int temp = nums[j - 1];
nums[j - 1] = nums[j];
nums[j] = temp;
}
}
if (sorted) return nums;
}
return nums;
}
}
插入排序
插入排序的基本思想
插入排序每一次将一个元素插入到它前面的有序数组中。
参考代码:
//插入排序
public class Insertionsort {
public int[] sortArray(int[] nums) {
int len = nums.length;
//把 nums[i] 插入有序数组 nums[0...i-1]中
for (int i = 1; i < len; i++) {
for (int j = i; j > 0; j--) {
if (nums[j] < nums[j - 1]) {
int temp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = temp;
} else {
break;
}
}
}
return nums;
}
}
插入排序的意义
「插入排序」是稳定排序,在数组的值 接近有序 的情况下,表现优异。
在小区间内执行排序任务的时候,可以转向使用「插入排序」。
归并排序和快速排序是基于分治算法的排序算法;归并排序和快速排序拆分到较小区间的时候转而使用插入排序(在绝大多数情况下,插入排序应用长度为6到16之间的任意的排序任务上都能令人满意).
插入排序很多时候成为了高级排序算法的底层的算法.(高级排序算法的底层会转向使用插入排序)
插入排序的优化
//插入排序优化
public class Insertionsort {
public int[] sortArray(int[] nums) {
int len = nums.length;
// 循环不变量:将 nums[i] 插入到区间 [0..i) 使之成为有序数组
for (int i = 1; i < len; i++) {
// 先暂存这个元素,然后之前元素逐个后移,留出空位
int temp = nums[i];
int j = i;
// 注意边界 j > 0
while (j > 0 && nums[j - 1] > temp) {
nums[j] = nums[j - 1];
j--;
}
nums[j] = temp;
}
return nums;
}
}
希尔排序
希尔排序的基本思想
开始的时候逐渐让数组变得基本有序,最后使用一次使用「插入排序」就变得高效了。
希尔排序是 「分组插入排序」 或者 「带间隔的插入排序」。
好处是:让较小的元素一下子来到数组的前面。 每一轮完成一次分组插入排序以后,数组就朝着接近有序的方向前进了一步。最后一轮一定是一次标准的插入排序。
参考代码:
//希尔排序
public class Hillsort {
public int[] sortArray(int[] nums) {
int len = nums.length;
for (int detal = len / 2; detal > 0; detal /= 2) {
for (int start = 0; start < detal; start++) {
insertionSortForDetal(nums, len, detal, start);
}
}
return nums;
}
private void insertionSortForDetal(int[] nums, int len, int detal, int start) {
for (int i = start + detal; i < len; i += detal) {
int temp = nums[i];
int j = i;
for (; j - detal >= 0; j -= detal) {
if (nums[j - detal] > temp) {
nums[j] = nums[j - detal];
} else {
break;
}
}
// 此时 nums[j - 1] <= temp
// nums[j] 的值被赋值到了 nums[j + 1]
nums[j] = temp;
}
}
}