一、选择排序
思路:每一次找到剩下元素中最小元素的位置与开始查找位置进行交换
0 ~ N-1 找到最小值,在哪,放到 0 位置上 1 ~ n-1 找到最小值,在哪,放到 1 位置上 2 ~ n-1 找到最小值,在哪,放到 2 位置上 ....
编码:
public void selectionSort(int[] arr) { if(arr == null || arr.length <2) { return; } // i 确定当前要放的位置,从 0 开始,最后一个元素可不用再处理(i < arr.length - 1) for(int i = 0; i < arr.length - 1; i++) { // 记录最小值位置,默认是当前存放的位置,依次与后面的元素进行比较 int minIndex = i; for(int j = i + 1; j < arr.length; j++) { // i ~ N-1 上找到最小值的下标 minIndex = arr[j] < arr[minIndex] ? j : minIndex; } // 交换当前要存放元素与最小值位置的元素 swap(arr, i, minIndex); } } private void swap(int[] arr, int i ,int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
二、冒泡排序
思路:依次比较相邻元素,小的往前排,大的往后排
0 ~ N-1 相邻元素依次进行比较,小的往前排,大的往后排,找到最大的元素 0 ~ N-2 相邻元素依次进行比较,小的往前排,大的往后排,找到第二大元素 0 ~ N-3 相邻元素依次进行比较,小的往前排,大的往后排,找到第三大元素 ....
编码:
public void bubbleSort(int[] arr) { if(arr == null || arr.length < 2) { return; } // i 决定还有多少个元素需要进行比较 for(int i = arr.length - 1; i > 0; i--) { // 从0开始到要比较的元素结尾,小的往前排,大的往后排 for(int j = 0; j < i; j++) { if(arr[j] > arr[j + 1]) { swap(arr, j, j + 1); } } } } private void swap(int[] arr, int i, int j) { arr[i] = arr[i] ^ arr[j]; arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j]; }
三、插入排序
思路:默认第一个元素已经有序,从第二个元素开始与前面已排序好的元素进行比较,小与前面的则交换
0 ~ 0 要有序,已经有序了 0 ~ 1 要有序,1位置往前看,比前面的小则交换,继续往前看,到0位置没数了或不再小于前面时停 0 ~ 2 要有序,2位置往前看,比前面的小则交换,继续往前看,到0位置没数了或不再小于前面时停 ....
编码:
public void insertSort(int[] arr) { if(arr == null || arr.length < 2) { return; } // 0 ~ 0 一个元素默认有序了,从第二个元素开始 // i 记录开始查看的元素位置,i-1位置则是有序元素的最后一个位置 for(int i = 1; i < arr.length; i++) { // 查看当前位置的前面一个元素开始 j = i-1,j >= 0 for(int j = i - 1; j >= 0; j--) { // 比前面的数小 arr[j] > arr[j+1] 则交换 if(arr[j] > arr[j + 1]) { swap(arr ,j, j + 1); } } } } public void swap(int[] arr, int i, int j) { arr[i] = arr[i] ^ arr[j]; arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j]; }
四、二分查找
思路:
1)有序数组 2)L ... R 范围查找 T,L < R 3)找中点:M = (L + R)/2 ==> L + (R - L) / 2 ==> L + ((R - L) >> 1) 4)T 小于中点值,则在左边查找,R = M - 1;T 大于中点值,在右边查找 L = M + 1;T等于中点值则返回
编码:
有序数组中查找一个元素是否存在
public boolean exist(int[] sortedArr, int value) { if(sortedArr == null || sortedArr.length == 0) { return false; } int L = 0; // 最左下标 int R = sortedArr.length - 1; // 最右下标 int M; // 中点下标 while(L <= R) { // L == R 时为最后一个元素 M = L + ((R - L) >> 1); if(sortedArr[M] == value) { return true; } else if(sortedArr[M] > value) { // 中点大于要找的值,取左边找 R = M - 1; } else{ // 中点值小于要找的值,取右边找 L = M +1; } } return false; // 最终没找到 }
在一个有序数组,找 >= 某个数最左侧的位置
public int nearestIndex(int[] arr, int value) { int L = 0; int R = arr.length - 1; int M; int index = -1; // 记录最左的下标 while(L <= R) { M = L + ((R - L) >> 1); if(arr[M] >= value) { // 中点大于等于要找的值,记录中点位置,继续往左找 index = M; R = M - 1; } else { // 否则往右找 L = M + 1; } } return index; }
在一个有序数组中,找<= 某个数最右侧的位置
public int nearestIndex(int[] arr, int value) { int L = 0; int R = arr.length - 1; int M; int index = -1; // 记录最左的下标 while(L <= R) { M = L + ((R - L) >> 1); if(arr[M] <= value) { // 中点小于等于要找的值,记录中点位置,继续往右找 index = M; L = M + 1; } else { // 否则往左找 R = M - 1; } } return index; }
思考:是否一定要是有序数组才能使用二分查找?
局部最小值问题:无序数组,正负0,任意相邻的数不相等,找一个局部最小值
public int getLessIndex(int[] arr) { if(arr == null || arr.length == 0) { return -1; } // 最左侧有局部小值 if(arr.length == 1 || arr[0] < arr[1]) { return arr[0]; } // 最右侧有局部小值 if(arr[arr.length - 1] < arr[arr.length - 2]) { return arr.length - 1; } // 中间可能有局部小值 int L = 1; int R = arr.length - 2; int M; while(L < R) { M = L + ((R - L) >> 1); if(arr[M] > arr[M - 1]) { // 中点大于左边,在左侧找 R = M - 1; } else if(arr[M] > arr[M + 1]) { // 中点大于右边,在右边找 L = M + 1; } else { return M; } } return L; }