前段时间被人问到排序算法,今天特此总结一下,冒泡,选择,快排,归并,插入这五种排序算法。
1.选择排序
选择排序是整体对比,每次选出你最需要的那个值,比如以下代码,首先选出最小的值,从小实现从小到大排序,外循环一次,内部循环记录下最小的坐标,只发生一次交换,它是一种稳定的排序算法,时间复杂度为o(n2),核心代码如下:
int[] numberArray = { 22, 32, 12, 1, 5, 66 };
int arraylength = numberArray.length;
int temp = 0;
for (int i = 0; i < arraylength - 1; i++) {
int k = i;
for (int j = i + 1; j < arraylength; j++) {
if (numberArray[k] > numberArray[j]) {
k = j;
}
}
if (i != k) {
temp = numberArray[i];
numberArray[i] = numberArray[k];
numberArray[k] = temp;
}
}
System.out.println(Arrays.toString(numberArray));
2.冒泡排序
冒泡排序的核心思路是相邻元素进行对比,把大的数往后移,外循环一次,内部循环可能会发生很多次交换,它是一种稳定的算法,时间复杂度为o(n2),核心代码如下:
int[] numberArray = { 22, 32, 12, 1, 5, 66 }; int arraylength = numberArray.length; int temp = 0; for (int i = 0; i < arraylength - 1; i++) { for (int j = i + 1; j < arraylength; j++) { if (numberArray[i] > numberArray[j]) { temp = numberArray[i]; numberArray[i] = numberArray[j]; numberArray[j] = temp; } } } System.out.println(Arrays.toString(numberArray));
3.插入排序
插入排序通过默认一个正确的位置,然后寻找插入位置,有点像我们完斗地主时,会把连牌挨着大小放着,它也是一种稳定的排序算法,时间复杂度为o(n2),核心代码如下:
int[] numberArray = { 22, 32, 12, 1, 5, 66 };
for (int i = 1; i < numberArray.length; i++) {
把j看作一个游标
int j = i;
int target = numberArray[i];
while (j > 0 && target < numberArray[j - 1]) {
说明有更大的,往后移
numberArray[j] = numberArray[j - 1];
j--;
}
numberArray[j] = target;
}
System.out.println(Arrays.toString(numberArray));
4.快速排序
快速排序的核心是冒泡+二分+递归分治,实际应用中算是最好的排序算法了,但它是一种不稳定的排序算法,平均时间复杂度为o(nlgn),最坏的情况是o(n2),它和冒泡算法的区别是同时查找大的数和小的数,核心代码如下:
public static void main(String[] args) {
try {
int[] numberArray = new int[] { 4, 3, 6, 1, 2, 5 };
recursionSort(numberArray, 0, numberArray.length - 1);
System.out.println(Arrays.toString(numberArray));
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
private static void recursionSort(int[] numberArray, int low, int high) {
if (low < high) {
int basevalueIndex = partitionGroup(numberArray, low, high);
左区间递归
recursionSort(numberArray, low, basevalueIndex - 1);
右区间递归
recursionSort(numberArray, basevalueIndex + 1, high);
}
}
private static int partitionGroup(int[] numberArray, int low, int high) {
int basevalue = numberArray[low];
while (low < high) {
先从右向左
while (low < high && numberArray[high] >= basevalue) {
--high;
}
交换比基准值小的到左边
numberArray[low] = numberArray[high];
while (low < high && numberArray[low] <= basevalue) {
++low;
}
交互比基准值大的到右边
numberArray[high] = numberArray[low];
}
扫描完成,左右下标,即low=high
numberArray[low] = basevalue;
返回基准值的下标
return low;
}
5.归并排序
理论上归并排序的效率应该高于快速排序,但是由于赋值次数较多以及分配临时数组等,所以和快排的效率应该不相上下。它的思路就是把原始数组序列不断两两分块,直到每一个块只剩下一个元素,然后利用递归的原理合并即可,它是一种稳定的排序算法,时间复杂度为o(n2),核心代码如下:
public static void main(String[] args) {
try {
int[] numberArray = new int[] { 4, 3, 6, 1, 2, 5 };
partition(numberArray, 0, numberArray.length - 1);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
public static void partition(int[] a, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
// 左边
partition(a, low, mid);
// 右边
partition(a, mid + 1, high);
// 左右归并
merge(a, low, mid, high);
System.out.println(Arrays.toString(a));
}
}
public static void merge(int[] numberArray, int low, int mid, int high) {
int[] temp = new int[high - low + 1];
左指针
int i = low;
// 右指针
int j = mid + 1;
int k = 0;
// 把较小的数先移到新数组中
while (i <= mid && j <= high) {
if (numberArray[i] < numberArray[j]) {
temp[k++] = numberArray[i++];
} else {
temp[k++] = numberArray[j++];
}
}
// 把左边剩余的数移入数组
while (i <= mid) {
temp[k++] = numberArray[i++];
}
// 把右边边剩余的数移入数组
while (j <= high) {
temp[k++] = numberArray[j++];
}
// 把新数组中的数覆盖nums数组
for (int k2 = 0; k2 < temp.length; k2++) {
numberArray[k2 + low] = temp[k2];
}
}