/**
* 冒泡排序
* 原理:从前往后,依次比较相邻两个数大小,如果arr[i]大于arr[i+1],则交换他们的位置
* 即将比较大的数往后放,小的数往前走
*/
private static void bubbleSort(int[] arr) {
// 临时变量
int temp;
// 数组长度
int len = arr.length;
// 数据交换标记:循环开始时置为true
// 如果有数据交换(有排序行为),则置为false
// 如果无数据交换(无排序行为),说明当前数组已经是有序的,则跳出循环
Boolean flag;
for (int i = 0; i < len - 1; i++) {
flag = true;
for (int j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// 交换前后位置
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
// 数据交换标记
flag = false;
}
}
// 没有发生交换(表示已经是有序的了)则退出循环;
if (flag) {
break;
}
}
}
/**
* 插入排序
* 原理:在保证arr[i]前面的元素都是有序的前提下,将temp = arr[i]依次与前面的元素比较大小
* 如果arr[i-1]大于temp则将arr[i-1]后移一位,直到arr[i-n]不大于temp为止
* 然后将temp插入到(i-n+1)这个为止
*/
private static void insertSort(int[] arr) {
int i, j, temp;
int len = arr.length;
// 从arr[1]开始
for (i = 1; i < len; i++) {
j = i;
// 将目标元素放入临时变量
temp = arr[i];
// 将temp依次与前面的元素进行比较
// 如果temp小于arr[i-1]则将arr[i-1]后移一位,如果temp小于arr[i-2]则将arr[i-2]后移一位。。。
// 最终将所有大于temp的元素都后移了一位,然后将temp插入当前空位置
while (j > 0 && arr[j - 1] > temp) {
arr[j] = arr[j - 1];
j--;
}
// 将temp插入当前空位置
arr[j] = temp;
}
}
注:此代码还可以优化
/**
* 二分插入排序
* 原理:在保证arr[i]前面的元素都是有序的前提下
* 利用二分法找到arr[i]前面数组中第一个大于temp(待插入元素)的元素的索引位置index
* 然后将所有大于temp的元素全部后移一位
* 将temp插入index位置
*/
private static void binaryInsertSort(int[] arr) {
int i, j, L, R, M,index,temp;
int len = arr.length;
for (i = 1; i < len; i++) {
// 将目标元素放入临时变量
temp = arr[i];
// 二分法查找第一个大于当前元素temp的值 start
L = 0;
R = i - 1;
index = i;
while (L <= R) {
M = (L + R) / 2;
if(L == R){
index = M;
}
if (arr[M] <= temp) {
L = M +1;
continue;
}
if (arr[M] > temp) {
R = M;
}
}
// 二分法查找第一个大于当前元素的值 end
// 将满足条件的从index到i-1位置的元素全部后移一位
for (j = i - 1; j >= index; j--){
arr[j + 1] = arr[j];
}
// 将目标元素的值插入index位置
arr[index] = temp;
}
}
// 附:二分法查找第一个大于目标值得索引位置
public static int searchFirstLargeThanThisValue(int[] arr, int value) {
int L = 0,
R = arr.length - 1,
M = -1;
while (L <= R) {
M = (L + R) / 2;
if(L == R){
return M;
}
if (arr[M] <= value) {
L = M +1;
continue;
}
if (arr[M] > value) {
R = M;
}
}
return M;
}
/**
* 快速排序
* 原理:利用三数取中法,选择一个合适的数作为基数,将基数放到数组最左边(位置L)
* 先从后往前查找,找到比基数小的数(位置j)停止
* 再从前往后查找,找到比基数大的数(位置i)停止,如果i=j时还没找到则停止
* 直到 i = j 时,交换arr[i]和基数的位置,此时完成一次比较,保证基数左边的数都比基数小,右边的数都比基数大;
* 然后分别递归基数左边数组和右边数组
*/
private static void quickSort(int[] arr, int L, int R) {
// 当左边大于右边时,退出迭代
if (L > R) {
return;
}
// 临时变量
int temp;
// 三数取中法,取一个合适的数(中间值)作为排序的基数,将基数放到数组最左边
// 比较 L,R,M 三个位置元素的大小,将最大的数放到最右边,将最小的数放到中间,将中间的数放到最左边
int M = (L + R)/2;
if (arr[L] > arr[R]) {
temp = arr[L];
arr[L] = arr[R];
arr[R] = temp;
}
if (arr[M] > arr[R]) {
temp = arr[M];
arr[M] = arr[R];
arr[R] = temp;
}
if (arr[L] < arr[M]) {
temp = arr[L];
arr[L] = arr[M];
arr[M] = temp;
}
// 选取数组第一个元素作为基数
int base = arr[L];
int i = L;
int j = R;
while (i < j) {
// 先从后往前查找,找到第一个比基数小的数(位置 j)停止
while (i < j && arr[j] >= base ) {
j--;
}
// 再从前往后查找,找到第一个比基数大的数停止,如果i=j时还没找到则停止
while (i < j && arr[i] <= base) {
i++;
}
// 如果此时 i<j,则交换arr[i] 和 arr[j] 的位置
if (i < j) {
temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
// 走到这里说明已跳出while循环,即i=j了,则交换arr[i] 和 基数 的位置
arr[L] = arr[i];
arr[i] = base;
// 走到这里基数的位置已经交换,此时满足基数左边的元素都小于等于基数,基数右边的元素都大于等于基数
// 以当前基数的位置将数组分治,分别递归基数两边的数组
quickSort(arr, L, i - 1);// 递归左半数组
quickSort(arr, i + 1, R);// 递归右半数组
}

/**
* 归并排序
* 原理:
* 首先创建一个与待排序数组大小相等的临时数组 temp ,用来存放合并后的序列;
* 采用分治法
*/
private static void mergeSort(int[] arr, int L, int R, int[] temp) {
if (L < R) {
int mid = (L + R) / 2;
//左边归并排序,使得左子序列有序
mergeSort(arr, L, mid, temp);
//右边归并排序,使得右子序列有序
mergeSort(arr, mid + 1, R, temp);
//将两个有序子数组合并操作
merge(arr, L, mid, R, temp);
}
}
private static void merge(int[] arr, int L, int mid, int R, int[] temp) {
int i = L;//左序列指针
int j = mid + 1;//右序列指针
int t = 0;//临时数组指针
while (i <= mid && j <= R) {
if (arr[i] <= arr[j]) {
temp[t++] = arr[i++];
} else {
temp[t++] = arr[j++];
}
}
while (i <= mid) {//将左边剩余元素填充进temp中
temp[t++] = arr[i++];
}
while (j <= R) {//将右序列剩余元素填充进temp中
temp[t++] = arr[j++];
}
t = 0;
//将temp中的元素全部拷贝到原数组中
while (L <= R) {
arr[L++] = temp[t++];
}
}