算法

快排开场(快速排序)

原理:

    1. 定义一个标杆,初始标杆为数组第0个位置,把标杆取出来放到外面。标杆作用:比标杆小的数字放到标杆左边,比标杆大的数字放到标杆右边。
    2. 涉及两个循环,一个从左往右的循环,称为i循环;一个从右往左的循环,称为j循环。
    3. j先开始往左走,发现比标识小的数,抛给i,这时j就站住不动,然后i开始往右走,发现比标识大的数,抛给j,这时i就站住不动,让j走,就这样像抛绣球一样抛来抛去,小数抛到左边,大数抛到右边,当i和j越走越近,走到最后i和j重复的时候就是标识所在的地方。此时的结果并不是排好序的,只是把数组分成了两部分,左边的数比5小,右边的数比5大。
    4. 把标识的左右两边又看成是完整的两个数组,不断的劈开劈开,当劈开越小,到3个数的时候,小的在左边,大的在右边,肯定是有序的。多个3个数的时候,组合到一起就是完整的有序的数组。

代码:

public static void main(String[] args) {
    //play(new File("D:\\yy"));

    int[] ints = {5,4,6,2,7,3,9,8};
    quickSort(ints,0,ints.length-1);
    for (int anInt : ints) {
        System.out.print(anInt +" ");
    }
}

/**
 * 快速排序 第二步 递归方法,不断调用第一步找中间位置
 * @param ints  数组
 * @param i     开始位置
 * @param j     结束位置
 * @return
 */
public static void quickSort(int[] ints,int i,int j) {
    if(i < j){
        int index = sortUnit(ints, i, j); // 找到中间位置
        quickSort(ints,i,index-1);        // 左边 把5左边当成一个小的数组继续找
        quickSort(ints,index+1,j);        // 右边 把5右边当成一个小的数组继续找
    }

}

/**
 * 快速排序 第一步  小数在标杆左边,大数在标杆右边,此时未排序
 * @param ints  数组
 * @param i     开始位置
 * @param j     结束位置
 * @return
 */
static int sortUnit(int[] ints,int i,int j){
    int num = ints[i];              // 标杆 第一次时为数组[0]
    while (i < j){                  // j和i开始不断找,直到中间位置
        while (i < j){
            if(ints[j] < num){      // j负责找小的,扔给i
                ints[i] = ints[j];
                break;              // 找到就不能动了,让i开始找大的
            }
            j--;                    // 没找到就继续往前走
        }
        while (i < j){
            if(ints[i] >= num) {    // i负责找大的,扔给j
                ints[j] = ints[i];
                break;              // 找到就不能动了,让j开始找小的
            }
            i++;                    // 没找到就继续往前走
        }
    }
    // 循环结束后,说明标杆在i和j碰面的地方
    ints[i] = num;
    return i;
}

/**
 * 获取当前文件夹下所有子文件夹/文件  递归调用
 * @param file
 */
static void play(File file){
    File[] files = file.listFiles();
    for (File f : files) {
        if(f.isFile()){
            System.out.println(f.getName());
        }else {
            play(f);
        }
    }
}

字符串相关

/**
 * 1. 找出字符串中出现次数最多的字符
 */
@Test
public void test(){
    String str = "sfasjlfaskfjlsajflakjaafadslfjsdlk";
    char res = str.charAt(0);
    int max = 0;
    Map<Character,Integer> map = new HashMap<>();
    for (int i = 0; i < str.length(); i++) {
        char c = str.charAt(i);
        Integer count = map.get(c);
        if(count == null){ // 字符没有出现过
            count = 1;
        }else {
            count++;
        }
        map.put(c,count);
        if(count > max){
            res = c;
            max = count;
        }
    }
    System.out.println(res+" 出现次数最多,出现:"+max+" 次");
}

/**
 * 2. 找出字符串中第一次重复出现的字符
 */
@Test
public void test2(){
    String str = "abccba";
    Set<Character> set = new HashSet<>();
    for (int i = 0; i < str.length(); i++) {
        // 添加失败说明已经存在
        if(!set.add(str.charAt(i))){
            System.out.println("第一次重复出现的字符是:"+str.charAt(i));
            break;
        }
    }
}

/**
 * 3. 在字符串中找出第一个只出现一次的字符
 */
@Test
public void test3_1(){
    String str = "abcabddsc";
    Map<Character, Integer> map = new HashMap<>();
    for (int i = 0; i < str.length(); i++) {
        Integer count = map.get(str.charAt(i));
        if(count == null){
            count = 1;
        }else{
            count++;
        }
        map.put(str.charAt(i),count);
    }
    for (int i = 0; i < str.length(); i++) {
        if(map.get(str.charAt(i))==1){
            System.out.println("第一个只出现一次的字符是:"+str.charAt(i));
            break;
        }
    }

}

/**
 * 3. 在字符串中找出第一个只出现一次的字符
 */
@Test
public void test3_2(){
    String str = "abcabddsc";
    for (int i = 0; i < str.length(); i++) {
        char c = str.charAt(i);
        if(str.indexOf(c) == str.lastIndexOf(c)){
            System.out.println("第一个只出现一次的字符是:"+str.charAt(i));
            break;
        }
    }
}

/**
 * 4. 统计手机号各个数字个数,按照升序输出
 */
@Test
public void test4(){
    int[] count = new int[10];
    String mobile = "13894937387";
    for (int i = 0; i < mobile.length(); i++) {
        char c = mobile.charAt(i);
        count[c-'0']++;// 统计每个字符出现的次数,char-'0'是一个整数 a[0] = 5; a[0]++; a[0] = 6;
    }
    for (int i = 0; i < mobile.length(); i++) {
        if(count[i]>0){
            System.out.println(i+"出现了"+count[i]+" 次");
        }
    }

}

/**
 * 5. 输入一个字符串,输出为按字节截取字符串,要保证汉字不能被截半个
 *    注意:汉字占两个字节 GBK、汉字占三个字节 UTF-8
 */
@Test
public void test5(){
    // int len = String.valueOf("人").getBytes().length; // 获取字符的字节数
    // System.out.println(len);                          // 人 的字节数:3
    String str = "人ABC们DEF";
    int count = 4;                 // 截取4个字节
    int sum = 0;                   // 已经截取了多少
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < str.length(); i++) {
        int len = String.valueOf(str.charAt(i)).getBytes().length;
        if(sum + len <= count){
            sum += len;
            sb.append(str.charAt(i));
        }else {
            break;
        }
    }
    System.out.println("截取"+count+"个字节后字符串为:"+sb.toString());
}

/**
 * 6. 写出如下代码中截取efg的代码
 *    <p id="test">abcdefg</p>
 */
@Test
public void test6(){
    String str = "<p id=\"test\">abcdefg</p>";

    /*** 使用substring截取 ***/
    String reg = "efg";                         // 要匹配的字符串
    int index  = str.indexOf(reg);              // 在整个字符串中出现索引的位置
    String target = str.substring(index, index + reg.length()); // 从索引位置开始截取,截取字符串的长度
    System.out.println("截取的字符串为:"+target);

    /*** 使用正则截取 ***/
    reg = ".*(efg).*";
    Pattern pattern = Pattern.compile(reg);
    Matcher matcher = pattern.matcher(str);
    if(matcher.find()){
        System.out.println("截取的字符串为:"+matcher.group(1));
    }
}

/**
 * 7. 设计一种反转字符串的算法,例如字符串为src="abddefg",反转后字符串src="gfeddba"
 */
@Test
public void test7(){
    String src = "abddefg";
    /*** 使用StringBuilder.reverse()反转字符串,非算法 ***/
    StringBuilder builder = new StringBuilder(src);
    System.out.println("字符串"+src+"反转后为:"+builder.reverse()); // 使用StringBuilder反转

    /*** 使用数组反转字符串,首尾互换,换到中间位置 ***/
    char[] chars = src.toCharArray();
    for(int i=0;i<chars.length/2;i++){
        char temp = chars[i];
        chars[i] = chars[chars.length-i-1]; // 第i个元素换成末尾和它对应位置的那个元素
        chars[chars.length-i-1] = temp;
    }
    System.out.println("字符串"+src+"反转后为:"+new String(chars));

    /*** 使用倒排序遍历反转字符串 ***/
    StringBuilder sb = new StringBuilder();
    for (int i = src.length()-1; i >= 0; i--) {
        sb.append(src.charAt(i));
    }
    System.out.println("字符串"+src+"反转后为:"+sb.toString());
}

/**
 * 8. 将句子按照一定的分割符分割后反转返回
 *    举例: 输入"I love the game" 输出"game the love I"
 */
@Test
public void test8(){
    String src = "I love the game";
    String sep = " ";
    String[] arrs = src.split(sep);
    StringBuilder builder = new StringBuilder();
    for(int i= arrs.length-1;i>=0;i--){
        builder.append(arrs[i]);
        builder.append(sep);    // 将空格加进去
    }
    // 最后多余的分隔符要去掉
    String target = builder.substring(0, builder.length() - sep.length());
    System.out.println("句子"+src+"反转后为:"+target);
}

/**
 * 9. 给定一个句子,反转句子中每个单词的顺序,同时保留单词和空格的初始位置
 *    输入: "Let's take LeetCode contest"
 *    输出: "s'teL ekat edoCteeL tsetnoc"
 */
@Test
public void test9(){
    String src = "Let's take LeetCode contest";
    String[] arrs = src.split(" ");
    StringBuilder builder = new StringBuilder();
    for (String arr : arrs) {
        // 逆向遍历每一个单词
        for(int i= arr.length()-1;i>=0;i--){
            builder.append(arr.charAt(i));
        }
        builder.append(" ");
    }
    // 去掉最末尾的空格
    String target = builder.substring(0, builder.length() - 1);
    System.out.println("句子"+src+"单词反转后为:"+target);
}

/**
 * 10. 判断字符串是不是合法的ipv4地址
 * xxx.xxx.xxx.xxx 0~255
 */
@Test
public void test10(){
    System.out.println(checkIp("127.0.0.1"));
}

public boolean checkIp(String ip){
    String[] arrs = ip.split("\\.");
    if(arrs.length !=4){
        return false;
    }
    for (String arr : arrs) {
        // 对每个xxx进行转换为数字,转换失败表示不是数字
        try {
            Integer num = Integer.parseInt(arr);
            if(num>255 || num<0){
                return false;
            }
            // 两位不能以0开头
            if(!arr.equals("0") && arr.startsWith("0")){
                return false;
            }
        } catch (NumberFormatException e) {
            return false;
        }
    }
    return true;
}

大数相加、相乘

/**
 * 实现大数的加法
 * 例如:
 * String a="123456777..."; a.size 大于1000位
 * String b="345678999..."; b.size 大于1000位
 * 注意: 不是把字符串转数字类型再相加,1000位转换会直接内存溢出
 */
@Test
public void testLargeNumberSum(){
    String a = "10001";
    String b = "999999";
    System.out.println(10001+999999);
    char[] large = null; // 大 (位数)
    char[] small = null; // 小 (位数)
    if(a.length() >= b.length()){
        large = a.toCharArray();
        small = b.toCharArray();
    }else{
        large = b.toCharArray();
        small = a.toCharArray();
    }
    // 最终结果的位数为大的数长度加1 最高位可能是0
    int[] sums = new int[large.length+1];
    // 将大的数放进数组
    for (int i = 0; i < large.length; i++) {
        // char转数字 char -'0'
        sums[i] = large[large.length-i-1] -'0'; // 从个位开始放进去
    }
    // 将小的数加到数组
    for (int i = 0; i < small.length; i++) {
        sums[i] += small[small.length-i-1] -'0';
    }
    for (int i = 0; i < sums.length -1; i++) {
        // 从个位开始判断是否进位
        if(sums[i] >9){
            // 进位给上一位
            sums[i+1] += sums[i]/10;
            // 当前数就是对10取余
            sums[i] %= 10;
        }
    }
    StringBuilder builder = new StringBuilder();
    for (int i = sums.length -1; i > 0; i--) {
        builder.append(sums[i]);
    }
    // 判断最高位有没有进位
    String result = builder.toString();
    if(result.startsWith("0")){
        // 截掉最高位
        result = result.substring(1);
    }
    System.out.println(a+"+"+b+"结果为:"+result);
}

/**
 * 实现大数的乘法
 * 例如:
 * String a="123456777..."; a.size 大于1000位
 * String b="345678999..."; b.size 大于1000位
 */
@Test
public void testLargeNumberMultiply(){
    String a = "689";
    String b = "33";
    System.out.println(689*33);
    char[] large = null; // 大 (位数)
    char[] small = null; // 小 (位数)
    if(a.length() >= b.length()){
        large = a.toCharArray();
        small = b.toCharArray();
    }else{
        large = b.toCharArray();
        small = a.toCharArray();
    }
    // 结果集最高位数为两数位数和
    int[] multi = new int[a.length() + b.length()];
    for (int j = small.length-1; j >= 0; j--) {    // 个位对齐
        for (int i = large.length-1; i >= 0; i--) {
            int num1 = small[j] - '0';
            int num2 = large[i] - '0';
            multi[large.length-1-i + small.length-1-j] += num1*num2;
        }
    }
    // 统一处理进位
    for (int i = 0; i < multi.length-1; i++) {
        // 从个位开始判断是否进位
        if(multi[i] >9){
            // 进位给上一位
            multi[i+1] += multi[i]/10;
            // 当前数就是对10取余
            multi[i] %= 10;
        }
    }
    StringBuilder builder = new StringBuilder();
    for (int i = multi.length-1; i >= 0; i--) {
        builder.append(multi[i]);
    }
    String result = builder.toString();
    if(result.startsWith("0")){
        // 截掉最高位
        result = result.substring(1);
    }
    System.out.println(a+"*"+b+"结果为:"+result);
}

 相乘数组结构:

数组相关

/**
 * 1. 求和 最大的子序列
 *    给定一个整数序列,A1,A2,...An(可能是负数),求A1~An的一个子序列Ai~Aj,使得Ai到Aj的和最大,并输出子序列的内容
 *    暴利破解法: 三层循环,在数据量比较大的情况下,性能不友好
 */
@Test
public void test1_1(){
    int[] nums = {-1,-2,1,6,4,1,-10,3};
    int step   = 1; // 参与求和的元素个数
    int maxSum = nums[0];
    int start  = 0;
    int end    = 0;
    while (step <= nums.length){
        // 从第0个开始计算
        for (int i = 0; i <= nums.length - step; i++) {
            int tempSum = nums[i];
            for (int j = i+1; j < i+step; j++) {
                tempSum += nums[j];
            }
            if(tempSum >= maxSum){
                start = i;
                end = i + step - 1;
                maxSum = tempSum;
            }
        }
        step++;
    }
    StringBuilder builder = new StringBuilder();
    for (int i = start; i <= end; i++) {
        builder.append(nums[i]).append(",");
    }
    // 最大的和:12 子序列:1,6,4,1
    System.out.println("最大的和:"+maxSum+" 子序列:"+ builder.deleteCharAt(builder.length()-1).toString());
}

/**
 * 1. 求和 最大的子序列
 *    给定一个整数序列,A1,A2,...An(可能是负数),求A1~An的一个子序列Ai~Aj,使得Ai到Aj的和最大,并输出子序列的内容
 *    一层循环,性能友好
 */
@Test
public void test1_2() {
    int[] nums = {-1, -2, 1, 6, 4, 1, -10, 3};
    int max = nums[0];
    // 以第i个元素结尾的最大的子序列的和
    int[] sums = new int[nums.length];
    sums[0] = nums[0];
    int end = 0;
    // 以第i个元素结尾的最大的子序列的和 从几开始的
    int[] starts = new int[nums.length];
    for(int i=1;i<nums.length;i++){
        // 它前面的子序列和大于0
        if(sums[i-1]>0){
            sums[i] = sums[i-1] + nums[i];
            starts[i] = starts[i-1];
        }else{
            sums[i] = nums[i];
            starts[i] = i;
        }
        if(sums[i] >max){
            max = sums[i];
            end = i;
        }
    }
    StringBuilder builder = new StringBuilder();
    for (int i = starts[end]; i <= end; i++) {
        builder.append(nums[i]).append(",");
    }
    // 最大的和:12 子序列:1,6,4,1
    System.out.println("最大的和:"+max+" 子序列:"+ builder.deleteCharAt(builder.length()-1).toString());
}

/**
 * 2. 数组去重排序
 */
@Test
public void test2_1(){
    int[] nums = {1,3,4,6,4,8,5,3,2,4,0,7,4,4};
    for (int i = 0; i < nums.length; i++) {
        for (int j = i+1; j < nums.length; j++) {
            if(nums[i] > nums[j]){
                int temp = nums[i];
                nums[i]  = nums[j];
                nums[j]  = temp;
            }
        }
    }
    System.out.println("排序:"+Arrays.toString(nums));
    StringBuilder builder = new StringBuilder();
    // 去重
    for (int i = 0; i < nums.length - 1; i++) {
        // 当前数不等于下一个数
        if(nums[i] != nums[i+1]){
            builder.append(nums[i]).append(",");
        }
    }
    builder.append(nums[nums.length -1]);
    System.out.println("去重:"+builder.toString());
}

/**
 * 2. 数组去重排序 使用TreeSet
 */
@Test
public void test2_2() {
    int[] nums = {1, 3, 4, 6, 4, 8, 5, 3, 2, 4, 0, 7, 4, 4};
    Set<Integer> set = new TreeSet<>();
    for (Integer num : nums) {
        set.add(num);
    }
    System.out.println("去重并排序:"+ Arrays.toString(set.toArray()));
}

/**
 * 3. 有一个正整数数组,存在重复元素,并降序排列,要求满足以下条件并输出:
 *      a. 按升序输出数组元素
 *      b. 重复元素仅打印一次
 *      c. 时间复杂度o(n)  o(n):用一个for循环,不要用for循环嵌套
 *    示例: 原始数据[2,3,3,6,6,9,10,10,16,18,18] 输出: 2,3,6,9,10,16,18
 */
@Test
public void test3(){
    int[] nums = {2,3,3,6,6,9,10,10,16,18,18};
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < nums.length - 1; i++) {
        // 当前数不等于下一个数
        if(nums[i] != nums[i+1]){
            builder.append(nums[i]).append(",");
        }
    }
    builder.append(nums[nums.length -1]);
    System.out.println("去重:"+builder.toString());
}

/**
 * 4. 奇偶调换
 *    调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有的偶数位于数组的后半部分,
 *    并保证奇数和奇数,偶数和偶数之间的相对位置不变
 */
@Test
public void test4_1(){
    int[] nums = {7,6,4,8,9,0,2,1,3,5,4,3};
    List<Integer> oddList = new ArrayList<>();  // 奇数
    List<Integer> evenList = new ArrayList<>(); // 偶数
    for (int num : nums) {
        if(num %2 ==0){
            evenList.add(num);
        }else {
            oddList.add(num);
        }
    }
    oddList.addAll(evenList);
    System.out.println(oddList.toString()); // [7, 9, 1, 3, 5, 3, 6, 4, 8, 0, 2, 4]
}

/**
 * 4. 奇偶调换
 *    调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有的偶数位于数组的后半部分,
 *    并保证奇数和奇数,偶数和偶数之间的相对位置不变
 */
@Test
public void test4_2(){
    int[] nums = {7,6,4,8,9,0,2,1,3,5,4,3};
    // 不使用List, 找奇数往前挪,挪到第一个偶数前面就可以了
    for (int i = 0; i < nums.length; i++) {
        if(nums[i] %2 ==0){ // 偶数
            for (int j = i+1; j < nums.length; j++) {
                if(nums[j] %2 ==1){ // 奇数
                    int temp = nums[j];
                    for(;j>i;j--){
                        nums[j] = nums[j-1]; // 第一次找到奇数9,6、4、8依次往后挪
                    }
                    nums[i] = temp;
                    break;
                }
            }
        }
    }
    System.out.println(Arrays.toString(nums)); // [7, 9, 1, 3, 5, 3, 6, 4, 8, 0, 2, 4]
}

/**
 * 5. 给出随机的100个数,可能含重复,序号为1-100,按从小到大顺序输出,并输出相应序号
 */
@Test
public void test5_1(){
    int[] nums = {7,6,4,8,9,0,2,1,3,5,4,3}; // 随机数
    int[] orders = new int[nums.length];    // 序号
    for (int i = 0; i < nums.length; i++) {
        orders[i] = i+1;
    }
    // 随机数排序
    for (int i = 0; i < nums.length; i++) {
        for (int j = i+1; j < nums.length; j++) {
            if(nums[i] > nums[j]){
                int temp = nums[i];
                nums[i]  = nums[j];
                nums[j]  = temp;
                // 交换序号
                temp = orders[i];
                orders[i]  = orders[j];
                orders[j]  = temp;
            }
        }
    }
    for (int i = 0; i < nums.length; i++) {
        System.out.println(nums[i]+" 序号:"+orders[i]);
    }
}

 

标题“51单片机通过MPU6050-DMP获取姿态角例程”解析 “51单片机通过MPU6050-DMP获取姿态角例程”是一个基于51系列单片机(一种常见的8位微控制器)的程序示例,用于读取MPU6050传感器的数据,并通过其内置的数字运动处理器(DMP)计算设备的姿态角(如倾斜角度、旋转角度等)。MPU6050是一款集成三轴加速度计和三轴陀螺仪的六自由度传感器,广泛应用于运动控制和姿态检测领域。该例程利用MPU6050的DMP功能,由DMP处理复杂的运动学算法,例如姿态融合,将加速度计和陀螺仪的数据进行整合,从而提供稳定且实时的姿态估计,减轻主控MCU的计算负担。最终,姿态角数据通过LCD1602显示屏以字符形式可视化展示,为用户提供直观的反馈。 从标签“51单片机 6050”可知,该项目主要涉及51单片机和MPU6050传感器这两个关键硬件组件。51单片机基于8051内核,因编程简单、成本低而被广泛应用;MPU6050作为惯性测量单元(IMU),可测量设备的线性和角速度。文件名“51-DMP-NET”可能表示这是一个与51单片机及DMP相关的网络资源或代码库,其中可能包含C语言等适合51单片机的编程语言的源代码、配置文件、用户手册、示例程序,以及可能的调试工具或IDE项目文件。 实现该项目需以下步骤:首先是硬件连接,将51单片机与MPU6050通过I2C接口正确连接,同时将LCD1602连接到51单片机的串行数据线和控制线上;接着是初始化设置,配置51单片机的I/O端口,初始化I2C通信协议,设置MPU6050的工作模式和数据输出速率;然后是DMP配置,启用MPU6050的DMP功能,加载预编译的DMP固件,并设置DMP输出数据的中断;之后是数据读取,通过中断服务程序从DMP接收姿态角数据,数据通常以四元数或欧拉角形式呈现;再接着是数据显示,将姿态角数据转换为可读的度数格
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值