既然容易忘记,那就记录一下,偶尔回头看看当初的起跑点
数据来源来极客时间王争哥的《数据结构与算法之美》
1.冒泡排序:通过每一次遍历获取最大/最小值,将最大值/最小值放在尾部/头部,然后除开最大值/最小值,剩下的数据在进行遍历获取最大/最小值
int[] arr = {9, 5, 8, 1, 2, 6};
int len = arr.length;
for (int i = 0; i < len; i++) {
//内层循环一次,获取一个最大值
for (int j = 0; j < len - i -1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
/** 过程
5 8 1 2 6 9
5 1 2 6 8 9
1 2 5 6 8 9
1 2 5 6 8 9
1 2 5 6 8 9
1 2 5 6 8 9
*/
- 选择排序:将第一个元素当作最小值,遍历后面的元素,若小于前面的最小值,则记录最小值和下标,遍历结束后查记录的下标与当前下标是否一致,不一致则交换最小值。
for (int i = 0; i < len; i++) {
int min = arr[i];// 默认当前最小
int index = i;// 记录下标
for (int j = i + 1; j < len; j++) {
// 若最小值大于遍历到的元素,则记录下标
if (min > arr[j]) {
min = arr[j];
index = j;
}
}
// 判断下标是否改变,改变则交换
if (index != i) {
int temp = arr[i];
arr[i] = min;
arr[index] = temp;
}
}
/** 排序过程:
1 5 8 9 2 6
1 2 8 9 5 6
1 2 5 9 8 6
1 2 5 6 8 9
1 2 5 6 8 9
1 2 5 6 8 9
*/
- 插入排序:将前面的数据看作是一个有序列表,从第二个元素开始,若比前面的数据小,则交换,否则退出
for (int i = 1; i < len; i++) {
for (int j = i; j > 0; j--) {
if (arr[j] < arr[j - 1]) {
int temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
} else {
break;
}
}
}
/** 排序过程:
5 9 8 1 2 6
5 8 9 1 2 6
1 5 8 9 2 6
1 2 5 8 9 6
1 2 5 6 8 9
*/
- 希尔排序:基本上和插入排序一样的道理,不一样的地方在于,每次循环的步长,通过减半的方式来实现
//希尔排序(插入排序变种版)
for (int i = arr.length / 2; i > 0; i /= 2) {
//i层循环控制步长
for (int j = i; j < arr.length; j++) {
//j控制无序端的起始位置
for (int k = j; k > 0 && k - i >= 0; k -= i) {
if (arr[k] < arr[k - i]) {
int temp = arr[k - i];
arr[k - i] = arr[k];
arr[k] = temp;
} else {
break;
}
}
}
//j,k为插入排序,不过步长为i
}
/** 排序过程:
9 5 1 8 2 6
9 5 1 2 8 6
9 5 1 2 6 8
5 9 1 2 6 8
1 5 9 2 6 8
1 2 5 9 6 8
1 2 5 6 9 8
1 2 5 6 8 9
*/
- 快速排序:选择一个中间值,可以是第一个也可以是最后一个,然后把数组里的元素以中间值进行划分,小的放左边,大的放右边,再递归的对左右两边的进行快速排序。
public void quickSort() {
doQuickSort(arr, 0, len - 1);
for (int m : arr) {
System.out.print(m + "\t");
}
}
public static void quickSort(int[] arr, int low, int high) {
//如果指针在同一位置(只有一个数据时),退出
if (high - low < 1) {
return;
}
//标记,从高指针开始,还是低指针(默认高指针)
boolean flag = true;
//记录指针的起始位置
int start = low;
int end = high;
//默认中间值为低指针的第一个值
int midValue = arr[low];
while (true) {
//高指针移动
if (flag) {
//如果列表右方的数据大于中间值,则向左移动
if (arr[high] > midValue) {
high--;
} else if (arr[high] < midValue) {
//如果小于,则覆盖最开始的低指针值,并且移动低指针,标志位改成从低指针开始移动
arr[low] = arr[high];
low++;
flag = false;
}
} else {
//如果低指针数据小于中间值,则低指针向右移动
if (arr[low] < midValue) {
low++;
} else if (arr[low] > midValue) {
//如果低指针的值大于中间值,则覆盖高指针停留时的数据,并向左移动高指针。切换为高指针移动
arr[high] = arr[low];
high--;
flag = true;
}
}
//当两个指针的位置相同时,则找到了中间值的位置,并退出循环
if (low == high) {
arr[low] = midValue;
break;
}
}
//然后出现有,中间值左边的小于中间值。右边的大于中间值。
//然后在对左右两边的列表在进行快速排序
quickSort(arr, start, low -1);
quickSort(arr, low + 1, end);
}
- 归并排序:将一个数组平均拆分成两个数组,然后再递归拆分,再将拆分的数组左边与右边进行比较进行排序放入一个临时数组(大小为两个数组之和),最后将排好序的临时数组按下标赋值给原数组并返回。需要额外空间
public void mergeSort() {
doMergeSort(arr, 0, len - 1);
for (int m : arr) {
System.out.print(m + "\t");
}
}
public void doMergeSort(int[] arr, int start, int end) {
//判断拆分的不为最小单位
if (end - start > 0) {
int mid = (start + end) / 2;
//再一次拆分,直到拆成一个一个的数据
doMergeSort(arr, start, mid);
doMergeSort(arr, mid + 1, end);
//记录开始/结束位置
int left = start;
int right = mid + 1;
//记录每个小单位的排序结果
int index = 0;
int[] result = new int[end - start + 1];
//如果拆分后的两块数据,都还存在
while (left <= mid && right <= end) {
//比较两块数据的大小,然后赋值,并且移动下标
if (arr[left] <= arr[right]) {
result[index] = arr[left];
left++;
} else {
result[index] = arr[right];
right++;
}
//移动单位记录的下标
index++;
}
//当某一块数据不存在了时
while (left <= mid || right <= end) {
//直接赋值到记录下标
if (left <= mid) {
result[index] = arr[left];
left++;
} else {
result[index] = arr[right];
right++;
}
index++;
}
//最后将新的数据赋值给原来的列表,并且是对应分块后的下标。
for (int i = start; i <= end; i++) {
arr[i] = result[i - start];
}
}
}