Class001

一、选择排序

思路:每一次找到剩下元素中最小元素的位置与开始查找位置进行交换

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)有序数组
2L ... R 范围查找 TL < R
3)找中点:M = (L + R)/2 ==> L + (R - L) / 2 ==> L + ((R - L) >> 1)
4T 小于中点值,则在左边查找,R = M - 1T 大于中点值,在右边查找 L = M + 1T等于中点值则返回

编码:

  • 有序数组中查找一个元素是否存在

    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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值