1. 冒泡排序
/**
* Title: 交换排序中的冒泡排序 ,一般情形下指的是优化后的冒泡排序,最多进行n-1次比较,依赖于初始序列
* Description:因为越大的元素会经由交换慢慢"浮"到数列的顶端(最后位置),最大的数最后才确定下来,所以称为冒泡排序
* 时间复杂度:最好情形O(n),平均情形O(n^2),最差情形O(n^2)
* 空间复杂度:O(1)
* 稳 定 性:稳定
* 内部排序(在排序过程中数据元素完全在内存)
*/
public class BubbleSort {
public static int[] bubbleSort(int[] target) {
if (target != null && target.length != 1) {
for (int i = 0; i < target.length; i++) {
for (int j = target.length - 1; j > i; j--) {
if (target[j] < target[j - 1]) {
swap(target, j, j - 1);
}
}
}
}
return target;
}
public static int[] optimizeBubbleSort(int[] target) {
int n = target.length;
if (target != null && n != 1) {
for (int i = 0; i < n - 1; i++) {
boolean exchange = false;
for (int j = n - 1; j > i; j--) {
if (target[j] < target[j - 1]) {
swap(target, j, j - 1);
exchange = true;
}
}
System.out.println(Arrays.toString(target));
if (!exchange) {
return target;
}
}
}
return target;
}
public static void swap(int[] target, int i, int j) {
int temp = target[i];
target[i] = target[j];
target[j] = temp;
}
}
2. 直接插入排序
/**
* Title: 插入排序中的直接插入排序,依赖于初始序列
* Description: 在有序序列中不断插入新的记录以达到扩大有序区到整个数组的目的
* 时间复杂度:最好情形O(n),平均情形O(n^2),最差情形O(n^2)
* 空间复杂度:O(1)
* 稳 定 性:稳定
* 内部排序(在排序过程中数据元素完全在内存)
*/
public class StraightInsertionSort {
public static int[] insertSort(int[] target) {
if (target != null && target.length != 1) {
for (int i = 0; i < target.length; i++) {
for (int j = i; j > 0; j--) {
if (target[j] < target[j - 1]) {
int temp = target[j];
target[j] = target[j - 1];
target[j - 1] = temp;
}
}
}
}
return target;
}
}
3. 直接选择排序
/**
* Title: 选择排序中的直接选择排序,依赖于初始序列
* Description: 每一趟 (例如第i趟,i = 0,1,...)在后面第n-i个待排序元素中选出最小元素作为有序序列的第i个元素
* 时间复杂度:最好情形O(n^2),平均情形O(n^2),最差情形O(n^2)
* 空间复杂度:O(1)
* 稳 定 性:不稳定
* 内部排序(在排序过程中数据元素完全在内存)
*/
public class StraightSelectSort {
public static int[] selectSort(int[] target) {
if (target != null && target.length != 1) {
for (int i = 0; i < target.length; i++) {
int min_index = i;
for (int j = i + 1; j < target.length; j++) {
if (target[min_index] > target[j]) {
min_index = j;
}
}
if (target[min_index] != target[i]) {
swap(target, min_index, i);
}
}
}
return target;
}
private static void swap(int[] target, int min_index, int i) {
int temp = target[min_index];
target[min_index] = target[i];
target[i] = temp;
}
}
4. 希尔排序
/**
* Title: 插入排序中的希尔排序,依赖于初始序列
* Description: 分别对间隔为gap的gap个子序列进行直接插入排序,不断缩小gap,直至为 1
* <p>
* 刚开始时,gap较大,每个子序列元素较少,排序速度较快;
* 待到排序后期,gap变小,每个子序列元素较多,但大部分元素基本有序,所以排序速度仍较快。
* <p>
* 时间复杂度:O(n) ~ O(n^2)
* 空间复杂度:O(1)
* 稳 定 性:不稳定
* 内部排序(在排序过程中数据元素完全在内存)
*/
public class ShellSort {
public static void shellSort(int[] target) {
if (target != null && target.length != 1) {
int gap = target.length;
while (gap > 1) {
gap = gap / 3 + 1;
for (int i = gap; i < target.length; i++) {
int j = i - gap;
while (j >= 0) {
if (target[j + gap] < target[j]) {
swap(target, j, j + gap);
j -= gap;
} else {
break;
}
}
}
}
}
}
public static void swap(int[] target, int i, int j) {
int temp = target[i];
target[i] = target[j];
target[j] = temp;
}
}
5. 折半插入排序
/**
* Title: 插入排序中的折半插入排序,依赖于初始序列
* Description: 折半搜索出插入位置,并直接插入;与直接插入搜索的区别是,后者的搜索要快于顺序搜索
* 时间复杂度:折半插入排序比直接插入排序明显减少了关键字之间的比较次数,但是移动次数是没有改变。所以,
* 折半插入排序和插入排序的时间复杂度相同都是O(N^2),在减少了比较次数方面它确实相当优秀,所以该算法仍然比直接插入排序好。
* 空间复杂度:O(1)
* 稳 定 性:稳定
* 内部排序(在排序过程中数据元素完全在内存)
*/
public class BinaryInsertSort {
public static int[] binaryInsertSort(int[] target) {
if (target != null && target.length != 1) {
for (int i = 1; i < target.length; i++) {
int left = 0;
int right = i - 1;
int mid;
int temp = target[i];
if (temp < target[right]) {
while (left <= right) {
mid = (left + right) / 2;
if (target[mid] < temp) {
left = mid + 1;
} else if (target[mid] > temp) {
right = mid - 1;
} else {
left = left + 1;
}
}
for (int j = i; j > 0; j--) {
target[j] = target[j - 1];
}
target[left] = temp;
}
}
}
return target;
}
}
6. 堆排序
/**
* Title: 堆排序(选择排序),升序排序(最大堆),依赖于初始序列
* Description: 现将给定序列调整为最大堆,然后每次将堆顶元素与堆尾元素交换并缩小堆的范围,直到将堆缩小至1
* 时间复杂度:O(nlgn)
* 空间复杂度:O(1)
* 稳 定 性:不稳定
* 内部排序(在排序过程中数据元素完全在内存)
*/
public class HeapSort {
public static int[] heapSort(int[] arr) {
if (arr != null && arr.length != 1) {
for (int i = arr.length / 2 - 1; i >= 0; i--) {
sift(arr, i, arr.length);
}
for (int j = arr.length - 1; j > 0; j--) {
swap(arr, 0, j);
sift(arr, 0, j);
}
}
return arr;
}
private static void sift(int[] arr, int i, int length) {
int temp = arr[i];
for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
if (k + 1 < length && arr[k] < arr[k + 1]) {
k++;
}
if (arr[k] > temp) {
arr[i] = arr[k];
i = k;
} else {
break;
}
}
arr[i] = temp;
}
public static void swap(int[] target, int i, int j) {
int temp = target[i];
target[i] = target[j];
target[j] = temp;
}
}
7. 归并排序
/**
* Title: 归并排序 ,概念上最为简单的排序算法,是一个递归算法 Description:归并排序包括两个过程:归 和 并
* "归"是指将原序列分成半子序列,分别对子序列进行递归排序 "并"是指将排好序的各子序列合并成原序列
* <p>
* 归并排序的主要问题是:需要一个与原待排序数组一样大的辅助数组空间
* <p>
* 归并排序不依赖于原始序列,因此其最好情形、平均情形和最差情形时间复杂度都一样 时间复杂度:最好情形O(n),平均情形O(n^2),最差情形O(n^2)
* 空间复杂度:O(n) 稳 定 性:稳定 内部排序(在排序过程中数据元素完全在内存)
*/
public class MergeSort {
public static void mergeSort(int[] target) {
int[] copy = Arrays.copyOf(target, target.length);
mergeSort(target, copy, 0, target.length - 1);
}
public static void mergeSort(int[] target, int[] copy, int left, int right) {
if (right > left) {
int mid = (left + right) / 2;
mergeSort(target, copy, left, mid);
mergeSort(target, copy, mid + 1, right);
merge(target, copy, left, mid, right);
}
}
/**
* @param target 用于存储归并结果
* @param left 第一个有序表的第一个元素所在位置
* @param mid 第一个有序表的最后一个元素所在位置
* @param right 第二个有序表的最后一个元素所在位置
* @return
* @description 两路归并算法
*/
public static void merge(int[] target, int[] copy, int left, int mid,
int right) {
int s1 = left;
int s2 = mid + 1;
int index = left;
while (s1 <= mid && s2 <= right) {
if (copy[s1] <= copy[s2]) {
target[index++] = copy[s1++];
} else {
target[index++] = copy[s2++];
}
}
while (s1 <= mid) {
target[index++] = copy[s1++];
}
while (s2 <= right) {
target[index++] = copy[s2++];
}
for (int i = left; i <= right; i++) {
copy[i] = target[i];
}
}
}
8. 快速排序
/**
* Title: 交换排序中的快速排序,目前应用最为广泛的排序算法,是一个递归算法,依赖于初始序列
* Description:快速排序包括两个过程:划分 和 快排
* "划分"是指将原序列按基准元素划分两个子序列
* "快排"是指分别对子序列进行快排
* <p>
* 就平均计算时间而言,快速排序是所有内部排序方法中最好的一个
* <p>
* 对大规模数据排序时,快排是快的;对小规模数据排序时,快排是慢的,甚至慢于简单选择排序等简单排序方法
* <p>
* 快速排序依赖于原始序列,因此其时间复杂度从O(nlgn)到O(n^2)不等
* 时间复杂度:最好情形O(nlgn),平均情形O(nlgn),最差情形O(n^2)
* <p>
* 递归所消耗的栈空间
* 空间复杂度:O(lgn)
* <p>
* 可选任一元素作为基准元素
* 稳 定 性:不稳定
* <p>
* <p>
* 内部排序(在排序过程中数据元素完全在内存)
*/
public class QuickSort {
public static void quickSort(int[] array, int left, int right) {
if (left >= right) {
return;
}
int index = partition(array, left, right);
quickSort(array, left, index - 1);
quickSort(array, index + 1, right);
}
/**
* 一次快速排序
*
* @param array 数组
* @param left 数组的前下标
* @param right 数组的后下标
* @return key的下标index,也就是分片的间隔点
*/
public static int partition(int[] array, int left, int right) {
/** 固定的切分方式 */
int key = array[left];
while (left < right) {
while (array[right] >= key && right > left) {
right--;
}
array[left] = array[right];
while (array[left] <= key && right > left) {
left++;
}
array[right] = array[left];
}
array[right] = key;
return right;
}
}