一.插入排序
直接插入排序
/**
* 直接插入排序 稳定算法
* 将待排序的数分为两类,一类为有序数列,一类为无序数列,每次从无序数列中去取一个数,
* 从有序数列尾端开始比较,若当前数比有序数小,将有序数往后移一位,不断重复该操作
* 直到找到第一个小于等于它的数,然后将带插入数插到该数后面.
* 时间复杂度为o(n^2) 空间复杂度为o(1)
*
* @param datas
* @param len
*/
public static void insertSort(int[] datas, int len) {
for (int i = 1; i < len; i++) {
int temp = datas[i];
//j为有序数组的最后一个下标
int j = i - 1;
while (j >= 0 && temp < datas[j]) {
datas[j + 1] = datas[j];
j--;
}
datas[j + 1] = temp;
}
}
二分插入排序
/**
* 二分插入排序 稳定算法
* 在直接插入排序的基础上,在有序队列中查找使用二分查找
* 时间复杂度为o(n^2) 空间复杂度o(n)
*
* @param datas
* @param len
*/
public static void binarySort(int[] datas, int len) {
int left = 0, right, mid;
for (int i = 1; i < len; i++) {
left = 0;
right = i - 1;
int temp = datas[i];
//二分搜索找出插入元素的位置
while (left <= right) {
mid = (left + right) >> 1;
if (temp < datas[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
//将有序数列该位置后面的值都右移一个位置
for (int j = i - 1; j >= left; j--) {
datas[j + 1] = datas[j];
}
datas[left] = temp;
}
}
shell排序
/**
* shell排序 不稳定排序
* 依据:在直接插入排序中,在待排序基本有序的情况下.时间复杂度为o(n)
* 将待排序的数分成d = len/2,以d间隔对每一组进行直接插入排序
* 不断使d = d/2,直到组变为1组
*
* @param nums
* @param len
*/
public static void shellSort(int[] nums, int len) {
int d = 1;
while (d >= 1) {
for (int i = d; i < len; i++) {
int temp = nums[i];
int j = 0;
for (j = i - d; j >= 0 && temp < nums[j]; j -= d) {
nums[j + d] = nums[j];
}
nums[j + d] = temp;
}
d /= 2;
}
}
交换排序
/**
* 交换排序
* 时间复杂度o(n^2) 空间复杂度o(1)
*
* @param nums
* @param len
*/
public static void swapSort(int[] nums, int len) {
for (int i = 0; i < len - 1; i++) {
for (int j = i + 1; j < len; j++) {
if (nums[i] > nums[j]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
}
冒泡排序
/**
* 冒泡排序
* n个数,总共比较n-1,每一次都是相邻两个数比较大小,大的数放到右边
* 时间复杂度 o(n^2) 空间复杂度o(1)
*
* @param nums
* @param len
*/
public static void bubbleSort(int[] nums, int len) {
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - i - 1; j++) {
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
}
快速排序
/**
* 快速排序 不稳定排序
* 始终将最左边一个最为排序码,每一趟排序结果是左边的数始终不大于排序码,右边的数始终不小于排序码
* 然后分别对排序码左边和右边的数进行同样的操作
* 时间复杂度 o(n*log n)
*
* @param nums
* @param left
* @param right
*/
public static void quickSort(int[] nums, int left, int right) {
int l = left, r = right;
if (left > right) return;
int key = nums[left];
do {
while (l < r && key < nums[r]) r--;
if (l < r) nums[l++] = nums[r];
while (l < r && key > nums[l]) l++;
if (l < r) nums[r--] = nums[l];
} while (l != r);
nums[l] = key;
quickSort(nums, left, r - 1);
quickSort(nums, l + 1, right);
}
归并排序
/**
* 归并排序 稳定排序
* 递归分治思想
* 时间复杂度 o(n*log n)
*
* @param nums
* @param low
* @param high
* @param sort
*/
public static void merge(int[] nums, int low, int high, int[] sort) {
if (low >= high) return;
int m = (low + high) >> 1;
merge(nums, low, m, sort);
merge(nums, m + 1, high, sort);
mergeArray(nums, low, m, high, sort);
}
/**
* 将两个有序的数组合并为一个有序的数组
*
* @param nums
* @param low
* @param m
* @param high
* @param sort
*/
private static void mergeArray(int[] nums, int low, int m, int high, int[] sort) {
int len = 0;
int i = low, j = m + 1;
while (i <= m && j <= high) {
if (nums[i] < nums[j]) {
sort[len++] = nums[i];
i++;
} else {
sort[len++] = nums[j];
j++;
}
}
if (i <= m) {
for (int k = i; k <= m; k++) sort[len++] = nums[k];
} else {
for (int k = j; k <= high; k++) sort[len++] = nums[k];
}
//将合并后的有序数赋值给原数组
for (int k = 0; k < len; k++) {
nums[low + k] = sort[k];
}
}
三.选择排序
直接选择排序
/**
* 选择排序 不稳定排序
* 在未排序的数中选择一个最小的放在第一个位置,然后在未排序的数中选出一个最小的放在第二个位置,
* 不断重复,直到未排序的只剩最后一个数
* 时间复杂度o(n^2) 空间复杂度o(1)
*
* @param nums
* @param len
*/
public static void selectSort(int[] nums, int len) {
for (int i = 0; i < len - 1; i++) {
int min = i;
for (int j = i + 1; j < len; j++) {
if (nums[min] > nums[j]) {
min = j;
}
}
if (i != min) {
int temp = nums[i];
nums[i] = nums[min];
nums[min] = temp;
}
}
}
堆排序
/**
* 堆排序 不稳定排序
* 从小到大排序利用最大堆,即保证每一个根节点的值都比两个儿子节点的值大
* 首先是建堆,利用完全二叉树的性质,左儿子节点的索引为父节点索引值的2两倍,
* 右儿子节点索引值为父节点索引值2倍加1
* 从完全二叉树最后一个非叶子节点的节点开始堆调整,然后是倒数第二个非叶子节点,
* 直到根节点,则根节点就是所有值中最大的节点
* 然后将根节点的值与完全二叉树最后一个节点得值进行交换,继续对前n-1个数进行建堆,
* 因为除根节点外,其他非叶子节点都满足最大堆的性质,所以只需要根节点进行堆调整
* 时间复杂度o(n*log n)
*
* @param nums
* @param len
*/
public static void heapSort(int[] nums, int len) {
for (int i = len / 2; i > 0; i--) {
//从len/2节点开始进行堆调整.直到调整根节点
sift(nums, i, len);
}
for (int i = len; i > 1; i--) {
//将根节点的值与数组最后一个节点的值交换
int temp = nums[1];
nums[1] = nums[i];
nums[i] = temp;
//待排序的减少最后一个元素,重新对第一个跟节点进行堆调整
sift(nums, 1, i - 1);
}
}
/**
* 对子树进行堆调整,使得子树的根节点的值为最大,并且使得每一个有儿子的节点值都比儿子的值大
* 从根节点开始从上往下调整
*
* @param nums
* @param i
* @param len
*/
public static void sift(int[] nums, int i, int len) {
//左儿子节点的索引
int j = i * 2;
//保存子树根节点的值
int temp = nums[i];
boolean isFinish = false;
while (j <= len && !isFinish) {
//在左右儿子节点存在时找到节点儿子值较大的节点
if (j < len && nums[j] < nums[j + 1]) j++;
//子树根节点的值比当前的节点i的儿子节点值最大值要大,则不用继续调整
if (temp >= nums[j]) {
isFinish = true;
} else {
//将大的节点值换到i节点
nums[i] = nums[j];
//继续往下进行调整
i = j;
j = 2 * j;
}
}
nums[i] = temp;
}