以下算法假设数组长度都为 n
冒泡排序
冒泡排序需要比较的轮次为n-1轮。
需要比较的次数为 n-1到1的等差数列求和 次(如果n为5,则为1+2+3+4次)。
原理为:从前两个数开始两两比较,如果前一个数大于后一个数则交换位置,一直比较到最后两个数时,就会将此数组中最大的一个数交换至最后。
然后进行第二轮比较,第二轮比较时不包含数组中最后一个数(下标n-1位置的数),因为最后一个数已经是最大的了,不需要再进行比较。第二轮比较完后下标n-2位置的数也已经是数组中第二大的数了,以此类推比较完n-1轮后,就已经是有序的数组了。
提前断开: 如果某轮比较中,没有进行任何交换,说明数组已经是有序的了,那可以直接停止所有循环,输出数组。
时间复杂度:O(N^2)
空间复杂度:O(1)
原地排序算法:是
稳定:是
冒泡排序算法如下:
package com.example.demo;
public class SortTest {
public static void main(String[] args) {
int[] arr = {7,4,1,5,2,8};
mpSort(arr);
}
/**
* 冒泡排序
* 6位数比较5次,
* 依次使用数组中相邻的两个数比较,把大的数往后移。
* 如果某次没有移动,说明比较下来已经全部按顺序排列好了,要不然比较肯定会有数的移动。
* @param arr
*/
public static void mpSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
// 每轮是否有交换的记录,默认true为没有交换
boolean flag = true;
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = false;
}
}
// 此轮没有数的交换则直接断开
if (flag) {
break;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
插入排序
插入排序,
原理:默认将数组中的下标为0个数当成第一个已经被插入的数。
排序时从下标i=1的数开始,将i=1的数记录到temp,依次与下标<i的数比较,如果小于i的数大于下标为i的数,则将<i的数向前移动一位,然后继续和再前一位数比较。
下标<i的数一定是有序的(所以如果i-1大于temp才有可能i-2也大于temp,如果i-1小于temp那么更前面的数肯定也小于temp,因为i前面的数都是有序的)。
如果小于i的数小于temp,那么终止比较,然后将temp插入到当前比较数的后一位(下标+1位)。
例如:3 2 1 4 5
temp=2;
下标为0的3>2 所以将下标为0的3后移一位,移动后 3 3 1 4 5
然后继续走循环后下标减减,得到下标为-1,然后-1是小于0的,所以断开循环,
然后再将temp插入到下标-1+1的位置,也就是下标为0的位置。得到2 3 1 4 5
这样前2位2 3就排序好了,后面的以此类推就可以了。类推后的数组如下
temp=1;
3>1,移动后如下:
2 3 3 4 5
2>1,移动后如下:
2 2 3 4 5
将temp插入后如下:
1 2 3 4 5
时间复杂度:O(N^2)
空间复杂度:O(1)
原地排序算法:是
稳定:是
/**
* 插入排序
* @param arr
*/
public static void crSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
int temp = arr[i];
int j = i - 1;
for (; j >= 0; j--) {
if (arr[j] > temp) {
arr[j + 1] = arr[j];
} else {
break;
}
}
arr[j + 1] = temp;
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
选择排序
选择排序
原理:
选择排序第一次优先将数组最小的数插入到下标为i=0的数组下标中。
第二次将除开i=0的数中找出最小的数插入i=1的下标中。
第三次将除开i=0、i=1的数中找出最小的数插入到i=2的下标中。
依次类推,一直到数组长度的最后一个数。
逻辑:
先默认将当前循环下标的数值使用temp记录起来,因为它需要与后续最小的数交换位置。
然后默认当前循环下标的数为最小的数,记录他的下标min。
然后依次用下标最小的数与后面的数比较(注意这里是从数组最后的一个数开始与最小的数比较),
如果遇到比此数更小的数则将其替代min的下标值。
此次外围循环结束后就能找到当前数中的最小的数,然后与当前外围循环的下标位置交换,则已经排好一轮。
时间复杂度:O(N^2)
空间复杂度:O(1)
原地排序算法:是
稳定:否
/**
* 选择排序
* @param arr
*/
public static void xzSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int temp = arr[i];
int min = i;
int j = arr.length - 1;
for (; j > i; j--) {
if (arr[j] < arr[min]) {
min = j;
}
}
arr[i] = arr[min];
arr[min] = temp;
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}