排序一览
插入
- 直接插入
- 希尔
交换
- 冒泡
- 快速
选择
- 直接选择
- 堆
归并
分配
基数
箱
1. 奇数放在前面 排序
-
或 偶数放在前面 排序
-
如果 偶数放在前面,内层 0 1 交换即可
第一种:前后两个指针 各自扫描 交换
public static void oddAndEvenSort(int[] arr) {
//最小索引
int i = 0;
//最大索引
int j = arr.length - 1;
//循环 i < j。如果是 1,2。那 第一个 i++,会执行。 下次循环 1<1 跳出循环。
//不会变成死循环
while (i < j) {
//数组中 遇见奇数 i就加1。遇见偶数,就退出循环。保证下个为偶数。
// 如0, 1, 2, 3, 4。arr[0] % 2 余数为2 。跳出循环。
while (arr[i] % 2 == 1 && i < j) {
i++;
}
//走到这里的, i 就是 偶数。第一次i 为 0
//数组中 遇见偶数,j就 -1。
// 如0, 1, 2, 3, 4。arr[4] % 2 余数为0 。j变成3 。a[3]再次循环,跳出 循环。
while (arr[j] % 2 == 0 && i < j) {
j--;
}
//走到这里的, i 就是 奇数。
//如果 i < j 。 就把 a[i]现在是偶数的。 和 a[j]现在是奇数的。 交换。
if (i < j) {
//i 赋值给 temp
int temp = arr[i];
// j 赋值给 i
arr[i] = arr[j];
// temp 赋值给 j
arr[j] = temp;
//交换后,i j 各自 移动 1
i++;
j--;
}//判断结束
}//外层循环
}//方法结束
第二种:第一个偶 和 下一个奇交换
public static void oddAndEvenSort2(int[] arr) {
//最小索引
int i = 0;
//最大长度,下面都是 小于< length ,那就是 最大为 最大索引了。
int length = arr.length;
//循环 i < lengthx
while (i < length) {
//如果是 偶数
if (arr[i] % 2 == 0) {
//进入循环。 从 i + 1 的位置扫描。 扫描到 最大-1。
for (int x = i + 1; x < length; x++) {
//从这里 开始找 奇数。如果找到了 奇数,就交换。
// 第一个偶数 和 第一 偶数后的奇数 交换。
//如:0, 3,7 。第一次0 和 3交换。 第二次 3 和 7交换。
if (arr[x] % 2 == 1) {
int temp = arr[i];
arr[i] = arr[x];
arr[x] = temp;
//交换后,就跳出内循环
break;
}//if交换
}//内存for
}//偶数的判断
//每次循环i自增1
i++;
}//循环的结束
}
2. 冒泡排序 (交换之一)
-
交换排序:有冒泡 和 快排
-
第一次排序 把最大的值 放在 最后边。第二次把 剩下最大的值 放在 倒数第二个索引。
-
第一次排序 把最小的值 放在 最前边。
第一种:简单 正循环 正序(最大的放最后)
- 如若 逆序,请调整交换 判断的 > 调成 <
public static void bubbleSort1(int arr[]) {
//最大索引
int maxIndex = arr.length - 1;
//外层循环 循环到 最大索引 -1。如 0 1 2,那就循环到1。
// 因为冒泡到 结尾的前一个。那最后一个 肯定是最大的,无需冒泡。
for (int i = 0; i < maxIndex; i++) {
//定义标志,0 代表,本次排序没有交换过。 可以直接返回。 1 表示交换过。
//本次未交换过。 这里定义到 外层最好。
int flag = 0;
//这是冒泡 正循环,好理解,逆循环是 最大索引 到 j>=i+1。
//这里 j循环到 最大索引 -i -1。如:0 3 2。
//第一次都没有排好。i = 0。 j< maxIndex。最大为 最大索引 -1 。下面 j+1 为 最大索引。
//第二次 i 为 1。
//j < maxIndex - 1。 最大为 最大索引 - 2 。 下面 j+1 为 最大索引-1。因为上次循环 后 最大索引已经放入最大值了。
for (int j = 0; j < maxIndex - i; j++) {
//如果前一个 比后一个大,就交换。这里是正序。 逆序就写 <
//保证 后一个 一直是最大的。到最后 最后一个肯定为最大的。
if (arr[j] > arr[j + 1]) {
//t = j
int t = arr[j];
//j = j+ 1 索引
arr[j] = arr[j + 1];
//j+1 = t
arr[j + 1] = t;
//本次交换过
flag = 1;
}//if判断的
}//内层for
//如果 本次一直未交换过
if (flag == 0) {
//结束方法
return;
}
}//外层for
}
第二种 正循环+倒循环 (最小的放最前面)
public static void bubbleSort2(int[] arr) {
//标志,如果交换了 赋值为1
int flag;
//最大索引
int maxIndex = arr.length - 1;
//i 从1 到 最大索引。与 上个相反,第一个 在第一次循环后,放最小的。外层无需循环。
for (int i = 1; i <= maxIndex; i++) {
//赋值为 从未交换过
flag = 0;
//j初值为 最大索引。
//j >= i。 j初值为maxIndex 到 j < i时 循环结束
//第一次 i为 1。 j为0时,结束(j为0 不进循环)。j为1下面:j - 1 为 0,为最小索引。
//第二次 i为2。 j为 j>=i。 最大索引 到 j<2 退出 循环,就是1 不进入循环。下面 j-1 。j为2,2-1=1 为1。因0位置已经排序完毕
for (int j = maxIndex; j >= i; j--) {
//如果 小于前一个 索引的值
if (arr[j] < arr[j - 1]) {
//存中间值
int t = arr[j - 1];
//j赋值给 前面的值
arr[j - 1] = arr[j];
// j= t
arr[j] = t;
//交换过
flag = 1;
}
}//内层for
if (flag == 0) {
return;
}
}//外层for
}
3. 二分查找
顺序表查找
- 顺序
- 二分
- 索引顺序
非递归
public static int binSearch(int[] arr, int k) {
//低索引是 0
int low = 0;
//高索引是 数组的最大索引
int high = arr.length - 1;
//如果low <= high 结束循环。 低 > 高 循环结束
while (low <= high) {
//中间值, 为 相加 整除 2
int mid = (low + high) / 2;
//如果中间的索引 相同
if (arr[mid] == k) {
//返回这个中间的值
return mid;
}
//如果 中间的 > k,即 k 在左边。1 2 3 4 5 ,mi为3 ,k为2
if (arr[mid] > k) {
//高索引,为中间 -1
high = mid - 1;
} else {
//反之 为 k在右边,低索引为:中间+1
low = mid + 1;
}
}
return 0;
}
递归
int[] arr = new int[]{1, 2, 3, 4, 5};
int i = rBinSearch(arr, 4, 0, 4);
public static int rBinSearch(int[] arr, int k, int low, int high) {
//下标底部 <= high。如果 低索引 > 高索,就走 else返回 0
if (low <= high) {
//中间 为 高低相加 /2
int mid = (low + high) / 2;
//如果 中间 查询到,就返回
if (arr[mid] == k) {
return mid;
}
//1 2 3 4 5 ,k在 左边。中间为3,k为2
if (arr[mid] > k) {
//高索引 为 中间索引 -1
return rBinSearch(arr, k, low, mid - 1);
} else {
//1 2 3 4 5 ,k在 右边中间为3,k为4,最低点为 mid+1
return rBinSearch(arr, k, mid + 1, high);
}
} else {
return 0;
}
}
4. 插入排序
- 直接插入:每次将一个 待排序的 ,插入到 前面已经排序好的
- 原来: 3 4 1。从1开始。比如3,4 已经排好,1插入的位置是0位置。
- 希尔
直接插入排序
public static void insertSort() {
//数组
int[] arr = new int[]{44, 66, 77, 33, 10};
//内层循环 变量。temp是临时 交换用的变量
int j;
//进行循环,1 到 最大索引 。0 位置作为第一个 无需排序
for (int i = 1; i < arr.length; i++) {
//当前的值,第一次为0索引。
int temp = arr[i];
//如果 当前的值 < 前一个值,移动 44,66,77,33 那33肯定是要移动的
if (temp < arr[i - 1]) {
//从 i-1索引开始,往前找位置,没毛病。
//找到第j是索引,如果>-1 (不为0也可以),才能循环 没毛病。
//temp < arr[j],循环到 当前位置 < arr[j] 就停止,没毛病。
for (j = i - 1; j > -1 && temp < arr[j]; j--) {
//44,66,77,33 那33肯定是要移动的。j从 77开始,77给33,66给77....
//当前值,往后一个索引移动
arr[j + 1] = arr[j];
}//内存for
//第一次过了这个循环后,44给66(33数的那次比较)。变成了:44,44,66,77
//插入正确的位置。j+1 。如33数那次,j此时在-1时跳出了循环。 -1 + 1 =0
//原来:44,44,66,77 。 把33插入了 arr[0]位置
arr[j + 1] = temp;
}//if选择
}//外层for
System.out.println(Arrays.toString(arr));
}
希尔排序
public static void shellInsert(int[] arr) {
//排序 2次
int d[] = new int[]{3, 1};
//遍历 d 进行调用
for (int i = 0; i < d.length; i++) {
shellInsertCore(arr, d[i]);
}
}
public static void shellInsertCore(int[] arr, int d) {
//外层,内存 循环变量
int j;
//如传递的是1,就从1开始。0位置,默认是排序好的。
for (int i = d; i < arr.length; i++) {
//当前的值
int temp = arr[i];
//{1, 3, 7, 2, 1,4} d=3。 0 1 2。从3开始。j第一次为0
j = i - d;
//如果 2 小于<= arr[0] 就交换。防止2个数一样,不交换 排序异常
if (temp <= arr[j]) {
//寻找插入位置
while (j > -1 && temp <= arr[j]) {
//当前值,往后移动D 个单位
arr[j + d] = arr[j];
//当前索引缩小 d
j = j - d;
}
//插入到 正确位置
arr[j + d] = temp;
}//if选择
}//外层for
System.out.println(Arrays.toString(arr));
}
5. 快速排序(交换之二)
-
45 53 18 49 36 76 13 97 36 32 i j 32 53 18 49 36 76 13 97 36 32 i j 32 53 18 49 36 76 13 97 36 53 i j 32 36 18 49 36 76 13 97 36 53 i j 第一次排序后: [32 36 18 13 36] 46 [76 97 49 32] ,即 中间位置是正确的,把x的值赋入
public static int partition(int[] arr, int i, int j) {
//先取出 低索引的值
int x = arr[i];
//如果 i< j,进行循环
while (i < j) {
//内层循环, 从高索引 开始,>=x 往前走
while (i < j && arr[j] >= x) {
j--;
}
//循环过后,第一个出现的值是 arr[j] < x
if (i < j) {
//arr[j] < arr[i] 后 j 赋值给 i
arr[i] = arr[j];
//赋值后 i++
i++;
}
//正向 行进。如:如果 当前<= x,一直往前扫描
while (i < j && arr[i] <= x) {
i++;
}
//到这里 出现的是 arr[i] > x 的
if (i < j) {
//arr[i] > a[j] 后,j是小的,往前赋值
//i索引 赋值给 j
arr[j] = arr[i];
//赋值后
j--;
}
}//while
//x赋值 给 低索引
arr[i] = x;
//返回低索引,此时i已经变成中间的的索引了。
return i;
}
static void quickSort(int[] arr, int low, int high) {
int p;
if (low < high) {//如果 低索引 < 高索引 继续循环
//首次排序,用中间的值
p = partition(arr, low, high);
//高位 -1 递归
quickSort(arr, low, p - 1);
//低位 +1 递归
quickSort(arr, p + 1, high);
}
}
quickSort(arr, 0, arr.length - 1);
6. 选择排序
- 直接选择排序:每一趟都选一个最小的,放在已经排序好的,最后面。
- 堆排序
public static void selectSort(int[] arr) {
//索引为 下标 -1
int maxIndex = arr.length - 1;
//外层循环 1 到 最大索引-1 (最后一个 无需在排了,肯定为最大)
for (int i = 0; i < maxIndex; i++) {
//设k为 最小位置i
int k = i;
//内层循环,从 i+1,循环到 最大索引。每次循环 都是找 最小索引
for (int j = i + 1; j <= maxIndex; j++) {
//如果 内层循环的 任意只要 小于 最小位置
if (arr[j] < arr[k]) {
//就把 当前位置 赋值给j
k = j;
}
}//内层for
//如果 最小位置 已经改变
if (k != i) {
//i 给 t
int t = arr[i];
//k 给 i
arr[i] = arr[k];
//t 给 k
arr[k] = t;
}//if
}//外层 for
}