这里默认大家已经了解这些算法
本文参考b站黑马视频
二分查找
先定义二分查找方法
/**
* a: 待排序的数组
* t: 需要查找的数字
* return:数组中与t匹配的元素的索引
*/
public void int binarySearch(int[] a, int t){
// 左索引 右索引 中间索引
int l = 0, r = a.length - 1, m;
while(l <= r) {
// 这样写可以防止整数溢出现象
m = (l + r)>>>1;
if(a[m] == t) {
return m;
}else if(a[m] > t) {
r = m - 1;
}else{
l = m + 1;
}
}
// 如果没有找到则返回-1
return -1;
}
冒泡排序(1:普通版 2:加强版 3:最终版)
// 首先先定义一个给定数组和两个索引,交换两个索引位置的方法
public static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
- 普通版
public static void bubbleOne(int[] a) {
for(int j = 0; j < a.length - 1; j++) {
for(int i = 0; i < a.length - 1 -j; i++) {
if(a[i] > a[i + 1]) {
swap(a, i, i + 1);
}
}
}
System.out.println(Arrays.toString(a));
}
- 加强版
public static void bubble_two(int[] a) {
// 判断是否发生交换 减少冒泡次数
boolean swapped = false;
for (int j = 0; j < a.length - 1; j++) {
// 一次冒泡
for (int i = 0; i < a.length - 1 - j; i++) {
if (a[i] > a[i + 1]) {
swap(a, i, i + 1);
// 如果发生交换
swapped = true;
}
}
// 如果冒泡一波下来没有发生任何交换,说明数组已经成了有序数组,不必进行后面的冒泡操作了
if (!swapped) {
break;
}
}
System.out.println(Arrays.toString(a));
}
- 最终版
public static void bubble_three(int[] a) {
int n = a.length - 1;
while (true){
int last = 0; // 表示最后一次交换索引位置
for (int i = 0; i < n; i++) {
if (a[i] > a[i + 1]) {
swap(a, i, i + 1);
// 每次交换记录交换的位置i
last = i;
}
}
n = last;
if (n == 0) {
break;
}
}
System.out.println(Arrays.toString(a));
}
选择排序
// 首先先定义一个给定数组和两个索引,交换两个索引位置的方法
public static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
public void selection(int[] a) {
for(int i = 0; i < a.length - 1; i++){
int s = i;
for(int j = s + 1; j < a,length; j++) {
if(a[s] > a[j]) {
s = j;
}
}
// 这里交换其实也是做了优化的,不建议在上面的if外进行交换,浪费性能,等上面的for循环结束直接找到最小的进行最后交换就行了
if(s != i) {
swap(a, s, j);
}
}
System.out.println(Arrays.toString(a));
}
插入排序
public static void insert(int[] a) {
// i 代表待插入元素的索引
for(int i = 1; i < a.length; i++) {
// 代表待插入的元素值
int t = a[i];
// 代表已排序区域的元素索引
int j = i - 1;
while(j >= 0) {
if(a[j] > t){
// 向后移动一位
a[j + 1] = a[j];
}else {
break;
}
j--;
}
a[j + 1] = t;
}
System.out.println(Arrays.toString(a));
}
public static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
快速排序(1:单边循环 2:双边循环)
- 单边循环
/**
* 实现分区
*
* @param a 待分区的数组
* @param l 下边界
* @param h 上边界
* return 基准点元素所在的正确索引
*/
private static int partition(int[] a, int l, int h) {
// 基准点元素
int pv = a[h];
// 比基准点小的元素都交换到i的左侧
int i = l;
for (int j = l; j < h; j++) {
if (a[j] < pv) {
if (i != j) {
swap(a, i, j);
}
i++;
}
}
// 最后基准点与i交换,i即为分区位置
if (i != h) {
swap(a, h, i);
}
// 返回值代表了基准点元素所在的正确索引,用它确定下一轮分区的边界
return i;
}
// 通过递归不断缩小分区范围,最终实现
public static void quick(int[] a, int l, int h) {
if (l >= h) { // 表示区间内没有元素或者只有一个元素
System.out.println(Arrays.toString(a));
return;
}
// 第一次分区后的基准点的正确索引值
int p = partition(a, l, h);
// 左边分区的范围确定
quick(a, l, p - 1);
// 右边分区的范围确定
quick(a, p + 1, h);
}
public static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
- 双边循环
/**
* 实现分区
*
* @param a 待分区的数组
* @param l 下边界
* @param h 上边界
* return 基准点元素所在的正确索引
*/
private static int partition(int[] a, int l, int h) {
// 双边循环大多以左边界为基准点
// 基准点
int pv = a[l];
// 左边界
int i = l;
// 右边界
int j = h;
while (i < j) {
// j 从右向左找比基准点小的元素
while (i < j && a[j] > pv) {
j--;
}
// i 从左向右找比基准点大的元素
while (i < j && a[i] <= pv) {
i++;
}
swap(a, i, j);
}
swap(a, l, j);
System.out.println(Arrays.toString(a) + " j=" + j);
return j;
}
// 通过递归不断缩小分区范围,最终实现
public static void quick(int[] a, int l, int h) {
if (l >= h) { // 表示区间内没有元素或者只有一个元素
return;
}
// 第一次分区后的基准点的正确索引值
int p = partition(a, l, h);
// 左边分区的范围确定
quick(a, l, p - 1);
// 右边分区的范围确定
quick(a, p + 1, h);
}
public static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}