选择、冒泡、插入排序、二分法、异或应用

本文探讨了选择排序、冒泡排序、插入排序以及二分查找在不同数据初始状态下的时间复杂度,重点讲解了它们如何不受数据顺序影响。还介绍了插入排序在正序和逆序情况下的性能差异,以及二分法在查找特定数值和位置的应用。
摘要由CSDN通过智能技术生成

1、选择排序和冒泡排序的时间复杂度(O(N^2))和数据初始状态无关,无论逆序,正序,或其他此序,操作流程相同

package learn;

public class Demo {
    public static void main(String args[]){
        int arr[]={9,8,7,6,5};
        //selectionSort(arr);
        bubbleSort(arr);
        print(arr);
    }

    //选择排序
    public static void selectionSort(int arr[]){
        if(arr==null || arr.length<2)return;//数组arr不指向任何对象和长度为0/1的数组无需排序
        for(int i=0;i<arr.length-1;i++){
            int minIndex=i;
            for(int j=i+1;j<arr.length;j++){//j=i+1<arr.length ->i<arr.length-1
                if(arr[j]<arr[minIndex]){//minIndex=arr[j]<arr[minIndex]?j:minIndex
                    minIndex=j;
                }
            }
            //if(min!=i)swap(arr[i],arr[minIndex]); 这样写有错,只是单纯交换了两个数的值,数组中的元素未变
            //可以直接在selectionSort函数中交换arr[i],arr[minIndex]。若要用另一个函数,应把arr数组也传过去
            if(i!=minIndex)swap(arr,i,minIndex);
        }
    }

    //冒泡排序
    public static void bubbleSort(int arr[]){
        if(arr==null || arr.length<2)return;
        for(int i=arr.length-1;i>0;i--){
            for(int j=0;j<i;j++){
                if(arr[j]>arr[j+1])swap(arr,j,j+1);
            }
        }
    }

    public static void swap(int arr[],int a,int b) {
//        int x=arr[a];
//        arr[a]=arr[b];
//        arr[b]=x;
        arr[a]=arr[a]^arr[b];
        arr[b]=arr[a]^arr[b];
        arr[a]=arr[a]^arr[b];
    }

    public static void print(int []arr) {
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]+" ");
        }
    }
}

2、插入排序:
正序:O(n)
逆序:O(n^2)

    public static void insertionSort(int arr[]) {
        if(arr==null || arr.length<2)return;
        for(int i=1;i<arr.length;i++){
            for(int j=i-1;j>=0 && arr[j]>arr[j+1];j--){
                swap(arr,j,j+1);
            }
        }
    }

3、二分法:

(1)在一个有序数组中,找某个数是否存在
注意事项:位运算优先级低于加减 注意加不加括号

    public static boolean exist (int[] arr,int num) {
        if (arr == null || arr.length == 0) return false;
        int left = 0;
        int right = arr.length - 1;
        while (left < right) {
            int mid=left+((right-left)>>1);//mid=(left+right)/2 left+right可能超出范围 -> mid=left+(right-left)/2
            //位运算比除运算快
            if(arr[mid]==num){
                return true;//找到即返回,无需再循环
            }else if(arr[mid]>num){
                right=mid-1;
            }else {
                left=mid+1;
            }
        }
        //找到返回,循环结束 或者 left==right 只有一个元素了
        return num==arr[left];//最后一个元素是否等于num
    }

循环条件可以变一下

    public static boolean exist (int[] arr,int num) {
        if (arr == null || arr.length == 0) return false;
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {
            int mid=left+((right-left)>>1);

            //位运算比除运算快
            if(arr[mid]==num){
                return true;//找到即返回,无需再循环
            }else if(arr[mid]>num){
                right=mid-1;
            }else {
                left=mid+1;
            }
        }
        return false;//最后一个数都不等,退出循环
    }

(2)在一个有序数组中,找>=某个数最左侧的位置
(3)在一个有序数组中,找<=某个数最右侧的位置

package learn;

public class Demo {
    public static void main(String args[]){
		int arr[]={2,2,3,3,3,4,5,5,6,6,6,6,7,7,7};
        System.out.println(arr.length);
        System.out.println(nearestIndex(arr,3));
    }

    public static int nearestIndex(int[] arr,int num) {
        int left = 0;
        int right = arr.length - 1;
        int index=-1;//记录最左
        while (left <= right) {//等号别漏了,最后一个元素也要判断是否大于等于num,它也有可能是那个最左的
            int mid=left+((right-left)>>1);

            if(arr[mid]>=num){
                index=mid;
                right=mid-1;
            }else {
                left=mid+1;
            }
        }
        return index;
    }
}

(4)局部最小值问题

    public static int getLessIndex(int[] arr,int num) {
        if(arr==null || arr.length==0)return -1;
        if(arr.length==1 || arr[0]<arr[1]){
            return 0;//第0位为局部最小值
        }
        if(arr[arr.length-1]<arr[arr.length-2]){
            return arr.length-1;//最后一位为局部最小值
        }
        
        //前面都没有返回的话,说明中间有数比两边都小
        int left=1;
        int right = arr.length - 2;
        int mid=0;
        while (left <right) {
            //循环条件 可以假设只有3个数 left==right 这个数在前面的比较中并未大于第一个数和第三个数 无需在循环中在比较一次 故不用取等
            mid=left+((right-left)>>1);

            if(arr[mid]>arr[mid-1]){
                right=mid-1;
            }else if(arr[mid]>arr[mid+1]){
                left=mid+1;
            }else {
                return mid;
            }
        }
        return left;
    }

5、利用异或:
题目:一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数

    public static void findOne(int[] arr) {
        int eor=0;
        for(int i=0;i<arr.length;i++){
            eor^=arr[i];
        }
        System.out.println(eor);
    }

题目:一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数

    public static void findOne(int[] arr) {
        int eor=0;
        for(int i=0;i<arr.length;i++){
            eor^=arr[i];
        }
        //eor==a^b;
        //a!=b -> eor至少有一个1
        int rightOne=eor&(~eor+1);//提取eor最右侧的1
        //说明此位 要么a为0,b为1 要么a为1,b为0
        int x=0;
        for(int i=0;i<arr.length;i++){
            if((rightOne & arr[i])!=0){//找到和eor最右侧1 同一位置为1的arr中的数
                x^=arr[i];//因为arr中同一位置为1的其他数都出现偶数次,异或结果为0 故x最终值不是a 就是b
            }
        }
        System.out.println(x+" "+(x^eor));//假设x为a,则a^a^b=b
    }

题目:一个数 二进制中 1的个数

    public static void countOne(int n) {
        int rightOne,count=0;
        while(n!=0){
            rightOne=n&((~n)+1);
            count++;
            n^=rightOne;//n-=rightOne 正数可以 负数不行
        }
        System.out.println(count);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值