九种常见排序算法

package mysort;

import org.apache.commons.lang.math.RandomUtils;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;

/**
 * 列举常用排序算法
 */
public class MySort {

    /**
     * 共列举7+2中排序算法
     *    按平均时间复杂度分:
     *       O(n*n)   插入排序,冒泡排序,选择排序
     *       O(nlogn) 堆排序,归并排序,快速排序
     *       O(n)     桶排序
     *       不好说    基数排序,希尔排序
     *   按算法思想来分:
     *      分治:        归并排序,快速排序
     *      有点类似贪心: 堆排序,选择排序,插入排序
     *      Hash映射思想: 桶排序
     *   需要借鉴的算法思想和数据结构:
     *      分治思想:分+合
     *      贪心:总是选择当前局部最优
     *      Hash映射
     *      堆(二叉树)
     *      二分查找
     */

    /**
     * 1.插入排序:遍历数组,包装遍历到的地方之前已经排好序,对第i个数字二分搜索插入的位置
     * 当然也可以把要插入的那个元素遍历找到它应该在的位置
     * 如果二分+用链表存储,时间复杂度降为O(nlogn)
     */
    public static void insertBinarySort(int[] arr){
        int len = arr.length;
        for (int i = 1; i < len; i++) {
            // 将第i个数放到已经拍好序的前i-1的有序数组中
            int l = 0;
            int r = i - 1;
            while (l <= r){
                int mid = l + ((r - l) >> 2);   //不加括号的号似乎是先算加号再算 >>
                if(arr[i] < arr[mid]){
                    r = mid - 1;
                }else {
                    l = mid + 1;
                }
            }
            // 至此,找到了第i个数位于第l和第r个数之间,如果用链表的话,明显不用遍历,插入复杂度为O(1)
            int temp = arr[i];
            for(int j = i; j > l; j --){
                arr[j] = arr[j - 1];
            }
            arr[l] = temp;
            System.out.println(Arrays.toString(arr));
        }
    }

    /**
     * 2.冒泡排序:不断遍历数组,每次遍历中,只保证遍历的元素和它前一个是排好序的,这种冒泡只保证较小数字会发生一次前移,最坏情况是
     * 从数组最后移动到数组最前面
     * 时间复杂度:O(n*n)
     */
    public static void bubbleSort(int[] arr){
        int len = arr.length;
        for (int i = 0; i < len; i++) {
            boolean earlyStop = true;
            for(int j = 1; j < len; j ++){
                if(arr[j] < arr[j - 1]){
                    earlyStop = false;
                    int temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
                }
            }
            System.out.println(Arrays.toString(arr));
            if(earlyStop)   break;
        }
    }

    /**
     * 3.桶排序:有点hash的感觉,把数组元素的数值映射到新数组的索引,如果数值超大,好像复杂度就上去了
     * 时间复杂度:O(n)
     */
    public static void bucketSort(int[] arr) {
        int len = arr.length;
        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        // 求最小值和最大值
        for (int i : arr) {
            if(i < min)    min = i;
            if(i > max)    max = i;
        }
        int[] bucket = new int[max - min + 1];
        for (int i : arr) {
            bucket[i - min] ++;
        }
        int index = 0;
        for (int i = 0; i < bucket.length; i++) {
            while (bucket[i] -- != 0){
                arr[index ++] = i + min;
            }
        }
    }

    /**
     * 4.堆排序:数组表示一颗完全二叉数,然后从数的下到上找到最大值,拿出后再重复上述步骤找到最大值
     * 一般的堆排序要求构建号最大堆或者最小堆,实际上排序只需取出最大值即可,无需满足最大堆
     * 时间复杂度:O(nlogn)
     */
    public static void heapSort(int[] arr) {
        int len = arr.length;
        for (int i = 0; i < len - 1; i++) {
            int last = (len - i - 2) / 2;   // 需要开始处理的非叶子节点
            for(int j = last; j >= 0; j --){
                int childMaxIndex = 2*j + 1;
                if(2*j + 2 < len - i && arr[2*j + 1] < arr[2*j +2]){
                    childMaxIndex = 2*j + 2;
                }
                if(arr[j] < arr[childMaxIndex]){
                    swap(arr,j,childMaxIndex);
                }
            }
            swap(arr,0, len - i - 1);
            System.out.println(Arrays.toString(arr));
        }
    }
    // 交换data数组中i、j两个索引处的元素
    private static void swap(int[] data, int i, int j) {
        int temp = data[i];
        data[i] = data[j];
        data[j] = temp;
    }

    /**
     * 5.归并排序  分治思想
     * 时间复杂度:O(nlogn)
     */
    public static void mergeSort(int[] arr) {
        mergeSortRecDiv(arr, 0, arr.length - 1);
    }

    private static void mergeSortRecDiv(int[] arr, int l, int r) {
        if(l >= r)  return;
        mergeSortRecDiv(arr,l,l + ((r - l) >> 2));
        mergeSortRecDiv(arr,l + ((r - l) >> 2) + 1,r);
        mergeSortRealMerge(arr, l, r);
    }

    private static void mergeSortRealMerge(int[] arr, int l, int r) {
        int mid = l + ((r - l) >> 2);
        // 对[l,mid]和[mid,r]进行归并排序
        int first = l;
        int second = mid + 1;
        int[] temp = new int[r - l + 1];
        int tempIndex = 0;
        while (tempIndex < r - l + 1){
            if(first > mid){
                temp[tempIndex ++] = arr[second ++];
                continue;
            }
            if(second > r) {
                temp[tempIndex ++] = arr[first ++];
                continue;
            }
            if(arr[first] > arr[second]){
                temp[tempIndex ++] = arr[second ++];
            }else {
                temp[tempIndex ++] = arr[first ++];
            }
        }
        System.arraycopy(temp,0,arr,l,r - l + 1);
    }

    /**
     * 6.快速排序   延伸问题:无序数组第k小元素
     * 选定一个基数,假如a[0],拿出来,从后找到第一个比它小的,填入a[0],此时刚刚的数又空出来,此时保证了空出来数的右边一定大于a[0],
     * 再从0之后开始寻找第一个大于a[0]的数字填入上一个坑,此时找到的这个数字索引之前一定是小于a[0],前后指针对撞后,保证了该指针指向
     * 之前小于a[0],之后大于a[0],再分治即可
     * 时间复杂度:O(nlogn)
     */
    public static void quickSort(int[] arr){
        subQuickSort(arr,0,arr.length-1);
    }

    private static void subQuickSort(int[] arr, int l, int r) {
        if(l >= r)  return;
        int lsave = l;
        int rsave = r;
        int base = RandomUtils.nextInt(r - l + 1) + l;
        int tempBase = arr[base];
        swap(arr,l,base);
        while (l < r){
            while (l < r && arr[r] >= tempBase) -- r;
            // 最坏情况是tempBase是最小值,此时r会减到l - 1
            arr[l] = arr[r];
            while (l < r && arr[l] <= tempBase) ++ l;
            arr[r] = arr[l];
        }
        arr[l] = tempBase;
        System.out.println(Arrays.toString(arr));
        subQuickSort(arr,lsave,l - 1);
        subQuickSort(arr,l + 1,rsave);
    }

    /**
     * 快排的重要应用
     * 无序数组第k小元素
     * 时间复杂度:O(n)
     */
    public static int kMinNumByquickSort(int[] arr, int k){
        int result = subKMinNumQuickSort(arr,0,arr.length-1,k);
        return result;
    }

    private static int subKMinNumQuickSort(int[] arr, int l, int r,int k) {
        if(l > r)  return Integer.MAX_VALUE;
        int result = Integer.MAX_VALUE;
        int lsave = l;
        int rsave = r;
        int base = RandomUtils.nextInt(r - l + 1) + l;
        int tempBase = arr[base];
        swap(arr,l,base);
        while (l < r){
            while (l < r && arr[r] >= tempBase) -- r;
            // 最坏情况是tempBase是最小值,此时r会减到l - 1
            arr[l] = arr[r];
            while (l < r && arr[l] <= tempBase) ++ l;
            arr[r] = arr[l];
        }
        arr[l] = tempBase;
        System.out.println(Arrays.toString(arr));
        if(l == k)  return arr[l];
        if(l > k){
            result = subKMinNumQuickSort(arr,lsave,l - 1,k);
        }else {
            result = subKMinNumQuickSort(arr,l + 1,rsave,k);
        }
        return result;
    }

    /**
     * 7.选择排序,有点堆排的意思,思想一样,运用的数据结构不同
     * 时间复杂度:O(n*n)
     */
    public static void selectSort(int[] arr) {
        int len = arr.length;
        for (int i = 0; i < len; i++) {
            int minTemp = arr[i];
            int minIndex = i;
            for (int j = i + 1; j < len; j ++){
                if(minTemp > arr[j]) {
                    minTemp = arr[j];
                    minIndex = j;
                }
            }
            swap(arr,i,minIndex);
        }
    }

    /**
     * 8.基数排序:对每一个元素,先按个位排,再按十位排,以此到最大值的最高位
     * 9.希尔排序:按间隔分组,每组逐渐包含更多元素,不断插入排序。总体上数据移动较少,复杂度优于O(n*n)
     */
    public static void main(String[] args) {
        int[] data = { 9, -16, 21, 23, -30, -49, 21, 30, 30 };
        System.out.println("排序之前:\n" + Arrays.toString(data));
        selectSort(data);
        System.out.println("排序之后:\n" + Arrays.toString(data));

    }
}

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了三轴陀螺仪和三轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值