一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)

认识时间复杂度和简单排序算法

文章目录

    • 认识时间复杂度和简单排序算法
      • ==1、常数时间的操作==
      • ==2、选择排序==
      • ==3、冒泡排序==
      • ==4、关于异或位运算(a^b=?)==
      • ==5、 插入排序==
      • ==6、简单描述二分 --> O(log n)==

1、常数时间的操作

  • 一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作

  • 时间复杂度为一个算法流程中,常数操作数量的一个指标。常用0(读作big 0)来表示。

  • 具体来说,先要对一个算法流程非常熟悉,然后去写出这个算法流程中,发生了多少常数操作,进而总结出常数操作数量的表达式。

  • 在表达式中,只要高阶项,不要低阶项,也不要高阶项的系数,剩下的部分如果为f(N),那么时间复杂度为0(f(N))。

  • 评价一个算法流程的好坏,先看时间复杂度的指标,然后再分析不同数据样本下的实际运行时间,也就是“常数项时间”。

    • int a = arr[i];
      //这就是一个常数操作的时间复杂度
      //加减乘除、位运算都是常数操作
      
      int b = list.get(i);
      //这就不是一个常熟操作,在链表中拿到i位置的值,只能从左往右遍历,与数据量息息相关
      

2、选择排序

  • 假设有一个 int 类型的一维数组 arr[] = {4,6,2,5,9,7,1,8,3};

  • 一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)_第1张图片

  • 代码实现

  • //时间复杂度O(n^2),空间复杂度O(1)
    for (int i = 0; i < arr.length; i++) {
        //从i开始找最小的数
         int min = i;
         for (int j = i; j < arr.length; j++) {
              if (num[j]<arr[minIndex]){
                   min = j;
              }
         }
         //交换
        int temp = arr[i];
        arr[i] = arr[min];
        arr[min] = temp;     
    }
    

3、冒泡排序

  • 一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)_第2张图片

  • 代码实现

  • for(int i = arr.length-1 ; i > 0 ; i--){
    	for(int j = 0 ; j < i; j++){
            if(arr[j]>arr[j+1]){
                int temp = arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
        }
    }
    

4、关于异或位运算(a^b=?)

  • 异或位运算(无进位相加1+1=0,0+1=1) --> 相同为0,不同为1

a : 10110 b : 00111 − − − − − − − = : 10001 a:10110\\ b:00111\\ -------\\ =:10 0 0 1 a:10110b:00111=:10001

  • 异或运算的三条公式

    • 0^N=N N^N=0
    • 异或运算满足交换率和结合律
    • 一堆数进行异或运算,谁先谁后对结果不会有影响
  • //如何使用异或交换a,b这两个数
    int a = 17;
    int b = 23;
    //answer:
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
    
    • 过程详解
    • 一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)_第3张图片
  • 例题

  • 力扣 136.只出现一次的数字
    除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只给你一个非空整数数组 nums出现了一次的元素。
    你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

  • //使用异或位运算进行解答
    public static void main(){
        int ans = 0;
        //将数组中的元素全部异或一遍,最终出现偶数次的数全部被异或掉
        //最后只剩下一个出现奇数次的那个元素
        for(int i=0;i<nums.length;i++){
            ans = ans ^ nums[i];
        }
        System.out.println(ans);
    }
    
  • 一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)_第4张图片

  • 进阶

  • 有两个出现奇数次的元素,一个出现偶数次的元素

  • public static void main(){
        int eor = 0;
        //首先整个数组进行异或
        for(int i=0;i<nums.length;i++){
            eor = eor ^ nums[i];
        }
        //此时eor = a ^ b  
        //(ab必不箱相等,即必然有在某一位上 a = 0 ,b = 1 ,eor在该位上为1)
        int rigthOne = eor & (~eor +1);   //取出最右边的那一个一
        for(int i=0;i<nums.length;i++){
            if(num[i] & rightOne == 0){
                onlyOne = onlyOne^ arr[i];
            }
        }
        //最后onlyOne的结果为a 或者 b
        //再将eor与onlyOne进行异或运算,即可得到另一个
        System.out.println(onlyOne + " " + (eor^onlyOne));
    }
    
  • 代码详解

    • 一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)_第5张图片

5、 插入排序

  • 插入排序是时间复杂度为O(n2)中最重要的一个排序方法,他的最坏情况是O(n2),最好情况是O(n),与选择排序和冒泡排序不同的是,插入排序的时间复杂度受数据的复杂量影响

  • 一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)_第6张图片

  • public static void InsertSort(int[] arr){
        if(arr==null||arr.length<2) return ;
        for(int i=1;i<arr.length;i++){
            //如果从i位置往前,比j位置小的话,就交换
            for(int j = i-1;j>=0&&arr[j]>arr[j+1];j--){
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    

6、简单描述二分 --> O(log n)

一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)_第7张图片

  • 在一个有序数组中,找某个数是否存在

    • 一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)_第8张图片
  • 在某个有序数组中,找>=某个数最左侧的位置

  • 一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)_第9张图片

  • 无序数组的局部最小值问题

  • 一、认识时间复杂度和简单的排序算法(选择排序,冒泡排序,插入排序,异或运算,二分思想)_第10张图片

你可能感兴趣的:(杂七杂八的算法,排序算法,算法,java,数据结构,leetcode)