算法之希尔排序、快速排序、二分查找
1
希尔排序:其时间复杂度为O(nlog n)
原理:希尔排序是插入排序的升级版本。插入排序的思想是(以从小到大排序为例):假设某个元素是最小的,然后在数列中找出该元素需要插入的位置。插入排序在数列基本有序的时候比较高效。那么,希尔排序比插入排序多哪个步骤呢?其实,希尔排序就是将插入排序跳跃的间距变成一个从大递减的数,那么一层一层的使数组接近有序,为插入排序提供一个好的条件。因此,希尔排序实现代码基本思想和插入排序一致,只是间距有所改变。我们来看希尔排序的实现代码:
Java实现:
import java.util.Arrays;/*** @Author junkle* @Date 2020/4/26 - 22:19* @Version 1.0**/public class shellSort {public static void shell_Sort(int[] array){if (array == null){throw new RuntimeException("array is null");}int size = array.length;int insertVal = 0;int insertIndex = 0;int jump = size >> 1;while (jump != 0) {for (int i = jump; i < size; i++) {insertVal = array[i];insertIndex = i - jump;while (insertIndex >= 0 && insertVal < array[insertIndex]) {array[insertIndex + jump] = array[insertIndex];insertIndex-=jump;}if (insertIndex != i - jump) {array[insertIndex + jump] = insertVal;}}jump = jump >> 1;}}public static void main(String[] args) {int[] array = new int[]{7,6,8,2,0,12,3};shell_Sort(array);System.out.println(Arrays.toString(array));}}
C++实现:
using namespace std;/*1、先判断传进来的参数是不是合适2、然后再进行别的操作*/void shellSort(int* array, int size){//这个用来对两个变量进行限制assert(array != nullptr && size != 0,"array is prohibit null");int insertVal = 0;int insertIndex = 0;int jump = size >> 1;while (jump){for (int i = jump; i < size; i++){insertVal = array[i];insertIndex = i - jump;while (insertIndex >= 0 && insertVal < array[insertIndex]){array[insertIndex + jump] = array[insertIndex];insertIndex-=jump;}if (insertIndex != i - jump){array[insertIndex + jump] = insertVal;}}jump = jump >> 1;}}int main(){int* array = new int[5]{9,1,2,3,4};shellSort(array, 5);for (int i = 0; i < 5; i++){cout << array[i] << " ";}cout << endl;return 0;}
2
快速排序(冒泡排序的升级版):其时间复杂度为O(nlog n)
快速排序原理分析:先选出一个基准元素(pivot),将数组变为基准元素左边的元素都比基准元素小,基准元素右边的元素都比基准元素大。我们下面将基准元素选择为数组最左边的元素。
为了容易理解:我们可以认为是将基准元素进行挖空的操作,然后找到该位置适合填入的元素,从最右边开始往左找找出一个小于基准元素。然后将该元素填入到基准元素的位置,现在基准元素空出来,多了一个相同元素的较大值,那么我们再从左往右进行查找,看是否能找到一个大于基准元素的值来填补到空缺的那个位置上。这样一个循环,循环结束条件是左边的索引大于右边的索引了。一次这样进行递归,遇到结束条件的时候,终止操作。
下图是经历过一次转移之后的结果,快速排序是分治思想的一种体现。
参考博客https://blog.csdn.net/zxd8080666/article/details/97395765
下面我们来看具体代码实现:
Java实现:
public static void quicklySort(int[] array, int left, int right){int i = left, j = right, x = array[left];while (i < j){while (i < j && array[j] > x) {j--;}if (i < j) {array[i++] = array[j];}while (i < j && array[i] < x) {i++;}if (i < j) {array[j--] = array[i];};}array[j] = x;if (left < i) quicklySort(array,left,i - 1);if (j < right) quicklySort(array,j + 1,right);}
C++实现:
void quicklySort(int* array, int left, int right){int i = left, j = right, x = array[left];while (i < j){while (i < j && array[j] > x) j--;if (i < j) array[i++] = array[j];while (i < j && array[i] < x) i++;if (i < j) array[j--] = array[i];}array[i] = x;if (left < i){quicklySort(array, left, i - 1);}if (j < right){quicklySort(array, j + 1, right);}}
3
查找算法有线性查找(比较简单)、二分查找(递归思想)、斐波那契查找(二分查找的升级版)
二分查找:需要注意的是,二分查找必须保证数组是连续的。就像我们找自己期末考试的卷子一样,假设试卷是按学号进行排列的,需要找到学号为20的试卷。在找到 30 号的试卷时,我们绝对不会再向40的方向找。这就是二分查找法的经典体现。
我们很容易想到了用递归进行实现,那么,我们需要查找的条件是什么呢?
只有当传入的左边索引大于右边索引的时候,停止查找。注意:相等的时候有可能就是要找到的对象。
Java实现:
package FindAlgorithm;import java.util.ArrayList;public class TwoDivideFind {public static ArrayList<Integer> find(int[] array, int low, int high, int findValue){if (low > high){return new ArrayList<Integer>();}int l = low, h = high, mid = ((l + h) >> 1), x = array[mid];if (findValue < x){return find(array, low, mid - 1, findValue);}else if(findValue > x){return find(array, mid + 1, high, findValue);}else{// return mid;ArrayList<Integer> integers = new ArrayList<>();integers.add(mid);int tmp = mid - 1;while (tmp >= low && array[tmp] == findValue){integers.add(tmp);tmp--;}tmp = mid + 1;while (tmp <= high && array[tmp] == findValue){integers.add(tmp);tmp++;}return integers;}}public static void main(String[] args) {//如果此时想要查找一个连续出现的数字的个数的int[] array = new int[]{1,1,1,1,1,1,1,2,3,4,5,6,20};System.out.println(find(array, 0, 6, 1));}}
C++实现:
int twoDivideFind(int* array, int left, int right, int findVal){if (left > right) return -1;int mid = ((left + right) >> 1);int tmp = array[mid];if (findVal > tmp){twoDivideFind(array, mid + 1, right,findVal);}else if (findVal < tmp){twoDivideFind(array, left, mid - 1, findVal);}else{return mid;}}
