冒泡排序
将最大的每一轮放到最右边
/**
* 冒泡排序
*O(n^2)
* @param arr
* @return
*/
public static void bubbleSort(int[] arr) {
int count = 0;//交换次数
for (int i = 0; i < arr.length - 1; i++) {
boolean flag = false;//一趟下来是否进行过交换,如果没有就说明前面的都是有序的就退出,{1,2,3,4,5}
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
count++;
flag = true;
swap(arr, j);
}
}
if (!flag) {
System.out.println(count);
return ;
}
}
System.out.println(count);
}
private static void swap(int[] arr, int i) {
int tem = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tem;
}
- 稍微优化就是判断一下前面几个是否是已经是有序的,用一个flag变量来判断;
选择排序
找出最小或者最大的放到它应该放的位置;
/**
* 选择排序
*找出最大或者最小的数,放到应该放的位置
*给每个元素找到合适的位置
*O(n^2)
* @param arr
*/
private static void selectSort(int[] arr) {
for (int j = 0; j < arr.length - 1; j++) {
int minIndex = j;
int min = arr[j];
for (int i = j + 1; i < arr.length; i++) {
if (min > arr[i]) {
//修改上面的符号可以修改排序顺序
min = arr[i];
minIndex = i;
}
}
if (minIndex != j) {
//一轮后,将最小值交换
arr[minIndex] = arr[j];
arr[j] = min;
}
}
}
插入排序
上来将第一个数当作有序,将其后的每一个无序插入前面已经整理了有序的适当位置;
/**
* 插入排序 ,将右边无序的插入左边有序的
*
* @param arr
*/
private static void insertSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
//从第二个元素起
int insertVal = arr[i];
//val的值
int insertIndex = i - 1;
while (insertIndex >= 0 && insertVal < arr[insertIndex]) {
//假如前面的比要当前插入值大,就把前面的值往后挪,这样挪的目的是,要插入的元素已经保存了,然后继续往前比较
//直到存在一个比他小的为止或者要插入的位置头部索引
arr[insertIndex + 1] = arr[insertIndex];
insertIndex--;
}
//最后将插入值放入索引位置
arr[insertIndex + 1] = insertVal;
}
}
希尔排序
/**
* 希尔排序,分组交换,逐渐将分组的个数增加直到分的组到最后只有一个
* * 交换法
*
* @param arr
*/
private static void shellSort(int[] arr) {
// 假设 length 为8 ,第一次 分组gps/2 每个组长度为2 第二次gps/2/2 每个组长度为4 gps为组的长度
for (int gps = arr.length / 2; gps > 0; gps /= 2) {
//得出有多少组,直到分为一个组
for (int j = gps; j < arr.length; j++) {
//对所有得到的组进行排序
for (int i = j - gps; i >= 0; i -= gps) {
//对单一的一个组排序
if (arr[i] > arr[i + gps]) {
int temp = arr[i];
arr[i] = arr[i + gps];
arr[i + gps] = temp;
}
}
}
}
}
/**
* 希尔排序 移位法
*
* @param arr
*/
private static void shellSortByMove(int[] arr) {
// 假设 length 为8 ,第一次 分组gps/2 每个组长度为2 第二次gps/2/2 每个组长度为4 gps为组的长度
for (int gps = arr.length / 2; gps > 0; gps /= 2) {
for (int i = gps; i < arr.length; i++) {
int j = i;
int temp = arr[j];
while (j - gps >= 0 && temp < arr[j - gps]) {
arr[j] = arr[j - gps];
j -= gps;
}
//退出while 找到插入位置
arr[j] = temp;
}
}
}
快速排序 *
/**
* 快速排序
* @param arr
* @param left 左指针
* @param right 右指针
*/
//left=0;right=arr.length;
private static void quickSort(int[] arr, int left, int right) {
int l = left;
int r = right;
int pivot = arr[(left + right) / 2];
int temp;
while (l < r) {
//在左边找到一个比中值大的
while (arr[l] < pivot) {
l += 1;
}
//在右边找到一个比中值小的
while (arr[r] > pivot) {
r -= 1;
}
if (l >= r) {
break;
}
//交换
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
if (arr[l] == pivot) {
r--;
}
if (arr[r] == pivot) {
l++;
}
}
if (l == r) {
l++;
r--;
}
//向左递归
if (left < r) {
quickSort(arr, left, r);
}
//向右递归
if (right > l) {
quickSort(arr, l, right);
}
}
归并排序
//分+合方法
public static void mergeSort(int[] arr, int left, int right, int[] temp) {
if(left < right) {
int mid = (left + right) / 2; //中间索引
//向左递归进行分解
mergeSort(arr, left, mid, temp);
//向右递归进行分解
mergeSort(arr, mid + 1, right, temp);
//合并
merge(arr, left, mid, right, temp);
}
}
/**
* 归并排序
*
* @param arr
*/
private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left; // 初始化i, 左边有序序列的初始索引
int j = mid + 1; //初始化j, 右边有序序列的初始索引
int t = 0; // 指向temp数组的当前索引
//(一)
//先把左右两边(有序)的数据按照规则填充到temp数组
//直到左右两边的有序序列,有一边处理完毕为止
while (i <= mid && j <= right) {//继续
//如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
//即将左边的当前元素,填充到 temp数组
//然后 t++, i++
if (arr[i] <= arr[j]) {
temp[t] = arr[i];
t += 1;
i += 1;
} else { //反之,将右边有序序列的当前元素,填充到temp数组
temp[t] = arr[j];
t += 1;
j += 1;
}
}
//(二)
//把有剩余数据的一边的数据依次全部填充到temp
while (i <= mid) { //左边的有序序列还有剩余的元素,就全部填充到temp
temp[t] = arr[i];
t += 1;
i += 1;
}
while (j <= right) { //右边的有序序列还有剩余的元素,就全部填充到temp
temp[t] = arr[j];
t += 1;
j += 1;
}
//(三)
//将temp数组的元素拷贝到arr
//注意,并不是每次都拷贝所有
t = 0;
int tempLeft = left; //
//第一次合并 tempLeft = 0 , right = 1 // tempLeft = 2 right = 3 // tL=0 ri=3
//最后一次 tempLeft = 0 right = 7
while (tempLeft <= right) {
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}
基数排序
//基数排序方法
public static void radixSort(int[] arr) {
//根据前面的推导过程,我们可以得到最终的基数排序代码
//1. 得到数组中最大的数的位数
int max = arr[0]; //假设第一数就是最大数
for(int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
//得到最大数是几位数
int maxLength = (max + "").length();
//定义一个二维数组,表示10个桶, 每个桶就是一个一维数组
//说明
//1. 二维数组包含10个一维数组
//2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arr.length
//3. 名明确,基数排序是使用空间换时间的经典算法
int[][] bucket = new int[10][arr.length];
//为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数
//可以这里理解
//比如:bucketElementCounts[0] , 记录的就是 bucket[0] 桶的放入数据个数
int[] bucketElementCounts = new int[10];
//这里我们使用循环将代码处理
for(int i = 0 , n = 1; i < maxLength; i++, n *= 10) {
//(针对每个元素的对应位进行排序处理), 第一次是个位,第二次是十位,第三次是百位..
for(int j = 0; j < arr.length; j++) {
//取出每个元素的对应位的值
int digitOfElement = arr[j] / n % 10;
//放入到对应的桶中
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
bucketElementCounts[digitOfElement]++;
}
//按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
int index = 0;
//遍历每一桶,并将桶中是数据,放入到原数组
for(int k = 0; k < bucketElementCounts.length; k++) {
//如果桶中,有数据,我们才放入到原数组
if(bucketElementCounts[k] != 0) {
//循环该桶即第k个桶(即第k个一维数组), 放入
for(int l = 0; l < bucketElementCounts[k]; l++) {
//取出元素放入到arr
arr[index++] = bucket[k][l];
}
}
//第i+1轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!
bucketElementCounts[k] = 0;
}
//System.out.println("第"+(i+1)+"轮,对个位的排序处理 arr =" + Arrays.toString(arr));
}
}
线性查找
/**
* 直接查找,遍历逐一比对,不需要查找序列有序
*/
private static int seqSearch(int[] arr,int d){
for (int i : arr) {
if (arr[i]==d){
return i;
}
}
return -1;
}
二分查找
/**
* 要求数组有序 ,二分法
*
* @param arr
* @param
* @return
*/
private static int binarySearch(int[] arr, int left, int right, int findVal) {
//给一个出口
if (left >= right) {
return -1;
}
int mid = (left + right) / 2;
int midV = arr[mid];
if (midV < findVal) {
return binarySearch(arr, mid + 1, right, findVal);
} else if (midV > findVal) {
return binarySearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
/**
* 要求数组有序 ,二分法,找出查找值的所有索引
*
* @param arr
* @param
* @return
*/
private static int[] binarySearchAll(int[] arr, int left, int right, int findVal) {
int[] result;
//给一个出口
if (left >= right) {
return result = new int[]{-1};
}
int mid = (left + right) / 2;
int midV = arr[mid];
if (midV < findVal) {
return binarySearchAll(arr, mid + 1, right, findVal);
} else if (midV > findVal) {
return binarySearchAll(arr, left, mid - 1, findVal);
} else {
//遍历一下 左边或者右边
result = new int[arr.length];
result[0] = mid;
int i = 0;
int b = mid - 1;
while (b > 0 || arr[mid] != findVal) {
i++;
result[i] = b;
b--;
break;
}
//右遍历
int a = mid + 1;
while (a < arr.length || arr[mid] != findVal) {
i++;
result[i] = a;
a++;
break;
}
return result;
}
}
插值查找
/**
* 插值 二分
*
* @param arr
* @param left
* @param right
* @param findVal
* @return
*/
private static int binaryInsertValueSearch(int[] arr, int left, int right, int findVal) {
//给一个出口
if (left >= right || findVal < arr[0] || findVal > arr[arr.length - 1]) {
return -1;
}
//mid 通过插值近似求出来,数值分析
int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]);
int midV = arr[mid];
if (midV < findVal) {
return binarySearch(arr, mid + 1, right, findVal);
} else if (midV > findVal) {
return binarySearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
斐波那契查找
根据斐波那契公式的特性:
F(k)=F(k-1)+F(k-2)
=> F(k)-1 = F(k-1) -1 +F(k-2)-1 + 1 最后一个 1 是留给mid 的
即
/**
* 斐波那契查找 mid的值为黄金分割点附近
mid=low+F(k-1)+1
* @param arr
* @param key
* @return
*/
private static int FabonacciSearch(int[] arr, int key) {
int low = 0;
int high = arr.length - 1;
int k = 0;//表示斐波那契分割数值下标
int mid = 0;
int f[] = fib();
//获取斐波那契飞割下标
while (high > f[k] - 1) {
k++;
}
int[] temp = Arrays.copyOf(arr, f[k]);
for (int i = high + 1; i < temp.length; i++) {
temp[i] = arr[high];
}
while (low <= high) {
mid = low + f[k - 1] - 1;
if (key < temp[mid]) {
high = mid - 1;
k--;
} else if (key > temp[mid]) {
low = mid + 1;
k -= 2;
} else {
if (mid <= high) {
return mid;
} else {
return high;
}
}
}
return -1;
}
/**
* 创建一个斐波那契数列
* 20可以修改
* @return
*/
public static int[] fib() {
int[] f = new int[20];
f[0] = 1;
f[1] = 1;
for (int i = 2; i < 20; i++) {
f[i] = f[i - 1] + f[i - 2];
}
return f;
}