2022.04.06_数据结构—左程云01

【心情篇】:
记得上一次学习算法是在大学的时候,那个时候大概看到了冒泡排序,是在一本C语言书里——《C语言从入门到精通》,清晰的记得那一系列的精通书都对新手不太友好,印象很深的是那一本书的第一个示例程序就用上了自定义方法,然而当时我printf函数都没搞太清楚,<#include>什么意思,int main(){} ,retun 0 之类的;
又打开了一年前学习Java的笔记,这一次心中五味杂陈;

【一些基础概念】:

常数操作;非常数操作;常数项时间;大O表示法;额外空间复杂度;位运算基操;对数器。

【选择排序】:

import java.util.Arrays;

public class Code01_选择排序 {
    public static void main(String[] args) {
        int[] aaa={4,5,7,8,1,2,3,4};
        selectionSort(aaa);
        Arrays.stream(aaa).forEach(System.out::print);

        System.out.println();

        int[] bbb={4,5,7,8,1,99,66,2,3,4};
        comparator(bbb);
        Arrays.stream(bbb).forEach(System.out::print);
    }

    public  static  void selectionSort(int[] arr){
        if ( arr==null || arr.length<2 ){  //去除一些没有必要排序的情况!!!
            return;
        }

        for ( int i = 0 ; i< arr.length-1 ; i++ ){  // i ~ N-1
            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);
        }
    }

    public static  void swap(int[] arr , int i , int j ){
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    //for test
    public static  void comparator(int[] arr){
        Arrays.sort(arr);
    }
}

【冒泡排序】:

import java.util.Arrays;

public class Code01_冒泡排序 {

    public static void main(String[] args) {
        int[] aaa={5,44,6,3,2,1,99};
        bubbleSort(aaa);
        Arrays.stream(aaa).forEach( e -> { System.out.print(" "+e);});
    }

    public static void bubbleSort( int[] arr ){
        if ( arr==null || arr.length < 2 ){
            return;
        }

        for ( int e = arr.length ; e > 0 ;  e-- ) {    // 0 ~ i
            for (int i = 0; i < e-1; i++) {
                if ( arr[i] > arr[i+1]){
                    swap(arr, i, i+1);
                }
            }
        }
    }

    public static 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];
    }
}

【插入排序】:

import java.util.Arrays;

public class Code01_插入排序 {
    public static void insertionSort( int[] arr ){
        if ( arr==null || arr.length<2 ){
            return;
        }
        // 0 ~ i 想要保持有序状态
        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);
            }
        }
    }

    public static 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];
    }

    public static  void comparator(int[] arr){
        Arrays.sort(arr);
    }

    public static int[] generateRandomArray( int maxSize , int maxValue ){
        // Math.random() ->  [0,1) 所有的小数 , 等概率返回一个;
        // Math.ramdom() * N   ->   [0,N)所有小数,等概率返回一个;
        // (int)(Math.ramdom() * N)  ->  [ 0,N-1 ] 所有的整数,等概率返回一个。

        int[] arr = new int[ (int)((maxSize+1)*Math.random()) ];  //长度随机;
        for (int i = 0; i < arr.length ; i++) {
            arr[i] = (int)(  (maxValue+1)*Math.random()  ) - (int) ( maxValue * Math.random() );
        }
        return  arr;
    }

    public static int[] copyArray(int[] arr){
        if (arr == null){
            return null;
        }
        int[] res = new int[arr.length];
        for (int i=0;i< arr.length;i++){
            res[i]=arr[i];
        }
        return res;
    }

    public static boolean isEqual(int[] arr1 , int[] arr2){
        boolean flag = true;

        if (arr1.length != arr2.length ){
            return false;
        }

        //走到这里说明数组长度相同
        for (int i = 0; i < arr1.length; i++) {
                if (arr1[i] != arr2[i]){
                    return false;
                }
        }
        return flag;
    }

    public static void main(String[] args) {
        int[] a = {5,4,2,3,6,77,1};
        insertionSort(a);
        Arrays.stream(a).forEach(System.out::println);

        System.out.println("$$$$$$$$$$$$$$$$$$$$$$$");

        int testTime = 50;    //测试的次数~
        int maxSize = 100;
        int maxValue = 100;
        boolean succed = true;
        for (int i=0 ; i<testTime ; i++ ){
            int[] arr1 = generateRandomArray(maxSize, maxValue);
            int[] arr2 = copyArray(arr1);

            insertionSort(arr1);
            comparator(arr2);

            if (!isEqual(arr1, arr2)){    //isEqual()方法是检验两个数组是否每一个位置都一样???
                succed = false;
                break;
            }

            Arrays.stream(arr1).forEach(e->{
                System.out.print("--  ");
            });
            System.out.println();
            Arrays.stream(arr1).forEach( e -> { System.out.print(" "+e);});
            System.out.println();
            Arrays.stream(arr2).forEach( e -> { System.out.print(" "+e);});
            System.out.println();
        }
        System.out.println(succed?"成功~~~":"失败!!!");
        System.out.println(succed?"成功~~~":"失败!!!");
        System.out.println(succed?"成功~~~":"失败!!!");
    }
}

【评价算法优劣的标准】:

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

【经典面试题】:

在一个int[ ] 中,只有一种数出现了奇数次 , 其余的数均出现了偶数次;
(1)如何找到出现奇数次的数 ?
(2)已知有两种数出现了奇数次 , 其余的数均出现偶数次,怎么找到这两种数呢 ?

【1】:

全都异或一次,最后得到的一定是那个奇数!!!

【2】:
  • 两个数在二进制上的特点——一定在某一位上不同

将这个数组分拨;(按照两个奇数的不同位数(看a^b的最高位))

一波全异或一遍会得到一个奇数数;用这个奇数去和已经得到的【a^b】来比较即可~

package class01;

public class Code01_两个奇数 {
    public static void printOddTimesnum1(int[] arr){
        int eor=0;
        for (int cur : arr){
            eor^=cur;
        }
        System.out.println(eor);
    }

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

        int rightOne = eor & (~eor + 1) ;
        int onlyOne  = 0;    // eor'

        for ( int cur:arr
             ) {
            if ( (cur & rightOne)==0 ){   //这里不管写 0/1 都是一样的,把数组划成了两波;
                onlyOne^=cur;
            }

        }
        System.out.println(onlyOne + " " + (eor ^ onlyOne));
    }

    public static void main(String[] args) {
        int[] a={22,44,5,6,6,5,5,8,8,2,2,22,44};
        int[] b={1,2,1,1,2,3,3,3,4,4};

        printOddTimesnum1 ( a );
        printOddTimesnum2( b );
    }
}

【局部最小值问题】:

  • 让我想起了《高数》中的罗尔中值定理;
    局部最小值问题;

数组arr无序,但是任何两个相邻的数一定不相等 , 然后定义一个东西叫——《局部最小》, 局部最小:首位,末位只要比邻位小即可,但对于中间位置必须是谷底才行!!!

在这样的一个数组中,我只要求出一个局部最小就可以了~ ~ ~

【问】:

能否设计一个算法 , 时间复杂度优于 O( N ) ???
在这里插入图片描述
下为自己写的一个算法(不一定为最简的):

public class Code01_局部最小_相邻的数不相等 {
    public static void main(String[] args) {
        int[] a={4,6,7};
        int[] b={9,7,6,3,8,9,6,5,1,4,5,6,7,7,8};
        int[] c={5,2,3,4,5,6,7,8,9,11,12,22,33,44,55,66,77,88,99};

        printJu(a);
        printJu(b);
        printJu(c);
    }

    public static void printJu(int[] arr ){
        int start = liangDuan(arr);
        if (start!=-1){
            System.out.println("局部最小为"+start);
            return;
        }

        int erNum = forMin(arr,0, arr.length);
        if (erNum!=-1){
            System.out.println("局部最小为"+erNum);
            return;
        }

        System.out.println("所输入的数组没有局部最小值~");
        return;
    }

    public static int liangDuan( int[] arr  ){
        int L=0;
        int R= arr.length-1;

        if (arr[L]<arr[L+1]  ){
            return arr[L];
        }
        if ( arr[R] < arr[R-1] ){
            return arr[R];
        }

        return -1;
    }

    public static int forMin( int[] arr , int L , int R ){
        int M=L+( (R-L) >>1 );

        if ( (M-1)< 0  || (M+1)> arr.length-1 ){     //数组首元素另写了一个方法来判断,这里就不管了。
            return -1;
        }

        if (arr[M-1]>arr[M] && arr[M]<arr[M+1]  ){
            return arr[M];
        }

        return (arr[M]<arr[M+1]) ?  forMin(arr, L, M-1) : forMin(arr, M+1 , R) ;
    }
}

【值得一提的是】:
题目中的——任何两相邻的数一定不相等,这一点非常重要!!!
因为如果出现相同数字紧挨着的情况的话,往哪一侧二分呢?没有数学规律表明一定在一侧有解。
所以存在相等数字紧挨的话,就不能使用二分法来计算。

【算法优化方向】:

  • 数据状况
  • 问题标准
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值