java 数据结构 排序算法

news2024/11/24 8:36:58

目录

排序

插入排序

直接插入排序

希尔排序( 缩小增量排序 ):

直接选择排序

堆排序

交换排序

冒泡排序

快速排序递归

Hoare法

挖坑法

前后指针法

快速排序优化

快速排序非递归

归并排序

归并排序非递归

排序算法复杂度及稳定性分析

计数排序


排序(Sort)

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来

的操作,所有的排序默认都是从小到大排序

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录

的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]

之前,则称这种排序算法是稳定的;否则称为不稳定的。

内部排序:例如定义了一个数组,在哪开辟的呢?当程序运行起来在内存上开辟的,在内存中存储

的,那我们叫内部排序

外部排序:例如你要排序的数据在磁盘上存储着,那叫外部排序,例如如果有10个G数据,你的运行

内存只有8个G,只能借助外部来进行排序

常见的排序算法


插入排序

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的

记录插入完为止,得到一个新的有序序列 实际中我们玩扑克牌时,就用了插入排序的思想

直接插入排序

思路:设置两个变量记录,设置一个temp变量存储i下标的元素,j从下标为i-1的开始,i从下标为1

的开始,i递增,j递减,每次temp跟j下标的进行比较,如果小于,j+1下标的位置放入temp,如果大于

就不变还是放在i下标的位置

代码实现:

    //直接插入排序
    //适用于:带排序已经基本趋于有序
    //稳定性:稳定的,如果是本身就是稳定的排序,一定可以实现不稳定的排序
    public static void insertSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int temp = array[i];
            int j = i - 1;
            for (; j >= 0; j--) {
                //这里加不加等号 和稳定有关系
                if (temp < array[j]) {
                    array[j + 1] = array[j];
                } else {
                    //array[j + 1] = temp;
                    break;
                }
            }
            array[j + 1] = temp;
        }
    }

疑问:

1.为什么array[j + 1] = array[j];j+1不能写i?当i=5,j=4,循环一次后,如果满足条件,这时候i还是5我们要改的是j+1下标

2.为什么array[j + 1] = temp;j+1不能写i?因为内部循环j结束后会递减,会到-1下标

直接插入排序的特性总结:

1. 元素集合越接近有序,直接插入排序算法的时间效率越高

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1),它是一种稳定的排序算法

4. 稳定性:稳定


希尔排序( 缩小增量排序 ):

先进行分组,然后进行插入排序,希尔排序,gap就是组数

图解

思路:先选定一个整数,把待排序文件中所有记录分成多个组,所有距离为gap的记录分在同一组

内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有

记录在统一组内排好序。

代码实现:

    //希尔排序
    //稳定性:不稳定
    public static void shellSort(int[] array) {
        int gap = array.length;
        while (gap > 1) {
            gap /= 2;
            shell(array, gap);
        }
    }

    /**
     * 对每组进行插入排序
     *
     * @param array
     * @param gap
     */
    public static void shell(int[] array, int gap) {
        //为什么不是i+=gap,因为图中有红色的线要进行排序,蓝色的线也要进行排序
        for (int i = gap; i < array.length; i++) {
            int temp = array[i];
            int j = i - gap;
            for (; j >= 0; j -= gap) {
                if (array[j] > temp) {
                    array[j + gap] = array[j];
                } else {
                    break;
                }
            }
            array[j + gap] = temp;
        }
    }

希尔排序的特性总结:

1. 希尔排序是对直接插入排序的优化

2. 当gap > 1时都是预排序,目的是让数组更接近于有序。

当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比

3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定

小结:希尔排序的速度比直接插入排序的速度快


直接选择排序

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部

待排序的数据元素排完 

图解

思路:设置一个变量minIndex用来记录i元素的下标,一开始存放的是i下标,然后跟j比较,j小的话

就更新里面的下标,内部循环结束后交换元素,因为内部比完了才知道哪个最小,i++,以此类推

代码实现:

   /**
     * 选择排序
     * 时间复杂度:O(n^2)
     * 空间复杂度:
     * 稳定性:
     *
     * @param array
     */
    public static void selectSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            //记录i元素的下标
            int minIndex = i;
            for (int j = i + 1; j < array.length; j++) {
                if (array[j] < array[minIndex]) {
                    //如果j元素比i元素小,更新minIndex里面的下标
                    minIndex = j;
                }
            }
            swap(array, i, minIndex);
        }
    }

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

第二种方法实现

图解

思路:设置left和right变量,一个从第一个开始一个从最后一个开始,minIndex和maxIndex一开始

都是left,从第二个元素开始遍历,如果小于minIndex的值,我们就更新minIndex的下标,如果大于

的话我们更新maxIndex的下标,循环结束后,我们交换,把左边的元素都放小的,右边元素放大

注意:在交换右边元素的时候要注意如果一开始第一个是最大值,交换过后,如图中的9就到了

maxIndex的位置,28到了minIndex的位置,然后轮到maxIndex交换的时候这个9就跑到最后去了

代码实现:

    public static void selectSort2(int[] array) {
        int left = 0;
        int right = array.length - 1;
        while (left < right) {
            int minIndex = left;
            int maxIndex = left;
            for (int i = left + 1; i <= right; i++) {
                if (array[i] < array[minIndex]) {
                    minIndex = i;
                }
                if (array[i] > array[maxIndex]) {
                    maxIndex = i;
                }
            }
            swap(array, left, minIndex);
            //防止 第一个是最大值 如果和最小的一换 最大值就跑到了原来最小值的位置
            if (maxIndex == left) {
                maxIndex = minIndex;
            }
            swap(array, right, maxIndex);
            left++;
            right--;
        }
    }

直接选择排序的特性总结

1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1)

4. 稳定性:不稳定

小总结:直接插入排序和选择排序的区别,直插设置变量存的是元素,选择存的是下标

直插可以直接进行交换,而选择要更新变量存的下标,得出最小值下标进行交换


堆排序

我在上一篇文章有讲解 java 数据结构 优先级队列(PriorityQueue)-CSDN博客


交换排序

冒泡排序

优化版实现:

    //冒泡排序
    public static void bubbleSort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            boolean flg = false;
            for (int j = 0; j < array.length - i - 1; j++) {
                if (array[j] > array[j + 1]) {
                    swap(array, j, j + 1);
                    flg = true;
                }
            }
            if (flg == false) {
                break;
            }
        }
    }

冒泡排序的特性总结:

1. 冒泡排序是一种非常容易理解的排序

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1)

4. 稳定性:稳定


快速排序递归

任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序

列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,

直到所有元素都排列在相应位置上为止

缺点:数据多的时候会数据溢出,处理逆序不太好

Hoare法

图解

思路:Hoare法就是right从右边开始找比基准值小的,左边开始找比基准值大的,两个都满足就交

换,相遇了的时候就把相遇下标的元素跟基准值下标的元素进行交换

完整思路:这个做法先把最左边的作为基准值,然后尾巴找出比基准值小的元素然后停住,头找出

比基准值大的元素然后停住,两个进行交换,然后尾接着找比基准值小的元素,头接着找比基准值

大的元素,直到相遇,然后和基准值交换位置,这时候基准值的左边都是比它小的,右边都是比它

大的,然后递归,左边从头到基准值的位置-1开始,右边从基准值+1到尾开始,以此类推,直到,

头大于尾巴开始归,跟前序与中序的归一样,这里是大于等于就归

代码实现:

    //快速排序
    //Hoare版
    public static void quickSort(int[] array) {
        quick(array, 0, array.length - 1);
    }

    public static void quick(int[] array, int start, int end) {
        //如果大于等于,说明找完了
        if (start >= end) {
            return;
        }

        //找出基准值
        int div = quickNeedle(array, start, end);
        quick(array, start, div - 1);
        quick(array, div + 1, end);
    }

     public static int partitionHoare(int[] array, int left, int right) {
        int tmp = array[left];
        //这个i用来记录第一个下标元素
        //因为最后要跟第一个下标元素进行交换
        int i = left;
        while (left < right) {
            //这里要判断会不会越界
            //为什么要加=,因为不加会死循环
            while (left < right && array[right] >= tmp) {
                right--;
            }
            while (left < right && array[left] <= tmp) {
                left++;
            }
            //走到这说明左边找到比基准值大的,右边找到比基准值小的
            swap(array, left, right);
        }
        swap(array, i, left);
        //这里说明走到一起了,返回谁都行
        return left;
    }

挖坑法

图解

思路:先把第一个下标的元素挖出来存到一个变量里,然后开始循环,右边开始找如果找到比左边

小的,我们就把那个坑填上,然后更新一下坑的位置,然后开始左边如果找到比第一次存的元素大

的,我们去把刚才的坑填上,然后更新一下坑的位置,以此类推,最后左右相遇,把坑填上存一开

始存的第一个下标的元素,也就是我们的基准值

代码实现:

    //挖坑法
    public static int partitionHole(int[] array, int left, int right) {
        int tmp = array[left];
        while (left < right) {
            while (left < right && array[right] >= tmp) {
                right--;
            }
            //把坑填上
            array[left] = array[right];
            while (left < right && array[left] <= tmp) {
                left++;
            }
            array[right] = array[left];
        }
        //走到一起的时候这个坑空着 把坑填上我们的基准值
        array[left] = tmp;
        return tmp;
    }

疑问:

这两个问题,第一个问题如果少了等于(<=tmp)如果第一个元素和最后一个元素一样的话,会

死循环。

第二个为什么不能从左边开始,下图和上图对比一下,上图可以看出左边开始的话left

和right会停留在6这个位置,9出现在第一个位置这就不符合左边的都是小于基准值

的,排序也不能变有序。

小总结:

Hoare法就是right从右边开始找比基准值小的,左边开始找比基准值大的,两个都满足就交换,相

遇了的时候就把相遇下标的元素跟基准值下标的元素进行交换

挖坑法就是先把基准值挖掉,然后从右边开始找比基准值小的,找到就填入一开始基准值的坑,填

了这个坑那右边这个位置不就空了,然后左边找比基准值大的,找到就填刚才右边空的坑,以此类

推,然后相遇了的时候,这个位置的坑填入基准值


前后指针法

图解

思路:设置一个变量prev记录left下标也就是上面图中key的位置,然后设置一个变量cur记录left+1

的下标,while循环当cur走到比数组长度长就停止,然后每次cur下标的元素跟left下标也就是最左

边的元素进行比较,如果小于并且prev走到下一步所对应的下标元素跟cur的元素相同,cur和prev

元素就进行交换,否则cur往前走,循环结束后,prev停留的位置的元素跟最左边也就是left的元素

进行交换

代码实现:

   //前后指针法
    public static int quickNeedle(int[] array, int left, int right) {
        int prev = left;
        //cur从头下标+1开始走
        int cur = left + 1;
        //当cur走出right结束
        while (cur <= right) {
            //cur下标元素要小于头下标元素 并且
            if (array[cur] < array[left] && array[++prev] != array[cur]) {
                swap(array, prev, cur);
            }
            //没有cur就往前走
            cur++;
        }
        //走完了 prev下标的元素和头下标的元素进行交换 这个就是我们的基准值
        swap(array, prev, left);
        return prev;
    }


快速排序优化

1. 三数取中法选key

2. 递归到小的子区间时,可以考虑使用插入排序

思路:就比如说1-10这个有序的数组,把头和尾拿出来,中间的下标等于头尾相加/2,然后求中间

值,然后把求出的中间值的下标的元素跟头下标的元素进行交换,这时候头就是我们的基准值了

找出中间值下标

代码实现:

    public static void quick(int[] array, int start, int end) {
        //如果大于等于,说明找完了
        if (start >= end) {
            return;
        }

        //优化
        if (end - start + 1 <= 15) {
            //使用直接插入排序
            insertSort(array, start, end);
        }

        //优化,三数求中法
        int mid = middle(array, start, end);
        //找出中间值下标和头下标的元素进行交换
        swap(array, start, mid);

        //找出基准值
        int div = quickNeedle(array, start, end);
        quick(array, start, div - 1);
        quick(array, div + 1, end);
    }

    //方法的重载
    public static void insertSort(int[] array, int left, int right) {
        for (int i = left + 1; i <= right; i++) {
            int temp = array[i];
            int j = i - 1;
            for (; j >= left; j--) {
                //这里加不加等号 和稳定有关系
                if (temp < array[j]) {
                    array[j + 1] = array[j];
                } else {
                    //array[j + 1] = temp;
                    break;
                }
            }
            array[j + 1] = temp;
        }
    }

    //找出中间值的下标
    public static int middle(int[] array, int left, int right) {
        //求中间的下标
        int mid = (left + right) / 2;
        //找中间值
        if (array[left] < array[right]) {
            if (array[mid] < array[left]) {
                return left;
            } else if (array[mid] > array[right]) {
                return right;
            } else {
                return mid;
            }
        } else {
            //array[left] > array[right]
            if (array[mid] < array[right]) {
                return right;
            } else if (array[mid] > array[left]) {
                return left;
            } else {
                return mid;
            }
        }
    }


快速排序非递归

思路:需要用到栈,首先设置头和尾的下标,然后找基准值调用Hoare法或者挖坑法都行,然后判

断左边元素有几个,如果基准值下标-1大于我们的头下标,就push进栈要push头下标和基准值下

标,如果相等说明左边就一个元素,然后判断右边也是一个道理如果基准值下标+1小于我们的尾

下标,就push进栈要push基准值下标和尾下标,然后while循环判断我们的栈空不空,不空就出右

边下标和左边下标,然后找基准值再调用我Hoare法或者挖坑法,然后再次判断左右元素有几个,

以此为循环

代码实现:

    //快速排序非递归
    public static void quickSort2(int[] array) {
        int start = 0;
        int end = array.length - 1;
        Stack<Integer> stack = new Stack<>();
        int div = partitionHoare(array, start, end);
        if (div - 1 > start) {
            stack.push(start);
            stack.push(div - 1);
        }
        if (div + 1 < end) {
            stack.push(div + 1);
            stack.push(end);
        }
        //栈不为空,弹出两个下标
        while (!stack.isEmpty()) {
            end = stack.pop();
            start = stack.pop();
            //接着整理
            div = partitionHoare(array, start, end);
            if (div - 1 > start) {
                stack.push(start);
                stack.push(div - 1);
            }
            if (div + 1 < end) {
                stack.push(div + 1);
                stack.push(end);
            }
        }
    }

快速排序总结:

1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)

4. 稳定性:不稳定


归并排序

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若

将两个有序表合并成一个有序表,称为二路归并

图解

分解思路:先设置头和尾,然后找出中间下标,然后递归左边以头和中间下标开始递归,右边以中

间下标+1和尾开始递归,当递归到头和尾下标一样,走到一起了开始返回,计算出mid后,传入第

一个式子的end就是mid,然后递归,mid更新,以此类推

怎么递?怎么归?怎么合并?

递归到只有单个元素的时候归,然后合并,合并完归到上一个式子的(mid+1,end)方法接着分

解到只有单个元素,然后合并以此类推

合并思路:写一个方法,记录刚才分解的元素的下标,也可以不记录,记录下来好理解一点,然后创建一个数组,长度是最右边下标-最左边下标+1,然后开始合并

代码实现:

    //归并排序
    public static void mergeSort(int[] array) {
        mergeSort(array, 0, array.length - 1);
    }

    private static void mergeSort(int[] array, int start, int end) {
        if (start >= end) {
            return;
        }
        //递归分解
        int mid = (start + end) / 2;
        mergeSort(array, start, mid);
        mergeSort(array, mid + 1, end);
        //合并
        merge(array, start, mid, end);
    }

    //合并
    private static void merge(int[] array, int left, int mid, int right) {
        //这些都可以不定义,方便理解
        int s1 = left;
        int e1 = mid;
        int s2 = mid + 1;
        int e2 = right;

        //创建一个新的数组
        int[] tmpArr = new int[right - left + 1];
        //从0下标开始存
        int k = 0;
        while (s1 <= e1 && s2 <= e2) {
            //比较元素大小
            if (array[s1] <= array[s2]) {
                tmpArr[k++] = array[s1++];
            } else {
                tmpArr[k++] = array[s2++];
            }
        }

        //走到这 说明还有数据没存完
        while (s1 <= e1) {
            tmpArr[k++] = array[s1++];
        }
        while (s2 <= e2) {
            tmpArr[k++] = array[s2++];
        }

        //拷贝给原来的数组
        for (int i = 0; i < tmpArr.length; i++) {
            //为什么+left? 不然右边也是从0下标拷贝 会覆盖掉原来的
            array[i + left] = tmpArr[i];
        }
    }


归并排序非递归

思路:先从1个开始调整有序,然后2个,然后4个,然后8个,但其实1个就是有序的

设置变量gap从1开始,代表每组几个数据,就像上面说的从1个开始逐渐到8个

设置for循环i从0下标开始,每次递增i+=gap*2,表示每次调整数据每一组2个,随着gap的增加,

每组4个,然后每组8个,就是每次分2个一组,然后合并成有序的,然后2个2个都合并并且有序

了,然后gap增加,然后每组4个4个合并并且有序,以此类推

注意:如果是偶数个这样写没什么问题,但是如果奇数个这样写,mid和right可能会越界,所以当

mid和right越界的时候,把它调整到数组长度-1的下标,然后调整合并

代码实现:

    //归并排序非递归
    public static void mergeSortNor(int[] array) {
        //每组(gap)几个数组
        int gap = 1;
        while (gap < array.length) {
            for (int i = 0; i < array.length; i += gap * 2) {
                int left = i;
                int mid = left + gap - 1;
                int right = mid + gap;

                //越界问题
                if (mid >= array.length) {
                    mid = array.length - 1;
                }
                if (right >= array.length) {
                    right = array.length - 1;
                }

                //合并
                merge(array, left, mid, right);
            }
            gap *= 2;
        }
    }

归并排序总结:

1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(N)

4. 稳定性:稳定


排序算法复杂度及稳定性分析


计数排序

不完全思路:比如0-9的数字乱序给它进行排序,创建一个数字,下标从0-9,这个数组也可以叫计

数数组,遍历0-9的数字,遍历到0,计数数0下标+1,还是0继续+1,此时0下标对应的就是2,代

表有2个,没有出现的话就标记0,以此类推,遍历完后,然后输出就变成有序的了

修改思路:但是这是0-9的数字,所以不行,得考虑大的数字,所以要设置一个最大最小值,通过

遍历array数值得出最大最小值,然后count数组的长度是大小值相减+1,然后遍历array数组,

count[array[i]-minval]++,通过这样对出现的数据,在count数组的i下标进行计数,然后还要重写 写

回到原来的数组,for遍历count数组,然后while循环判断count数组下标存的数字的次数是不是大于

0,大于0才有,小于等于都是没有的,然后还要设置一个index=0,array从0下标开始存,array[index]=i+minval,然后下标++,count[i]- -,count数组下标的次数--

代码实现:

   //计数排序 不用比较大小进行排序
    public static void countSort(int[] array) {
        int minVal = array[0];
        int maxVal = array[0];
        //获取array数组中的最大和最小值
        for (int i = 1; i < array.length; i++) {
            if (array[i] < minVal) {
                minVal = array[i];
            }
            if (array[i] > maxVal) {
                maxVal = array[i];
            }
        }

        //确定计数数组长度
        int len = maxVal - minVal + 1;
        int[] count = new int[len];

        //遍历array数组  array数组元素出现的次数存放到计数数组存放
        for (int i = 0; i < array.length; i++) {
            //array数组的元素-最小值
            //一开始count数组的每个下标存放的都是0
            count[array[i] - minVal]++;
        }
        int index = 0;
        for (int i = 0; i < count.length; i++) {
            //count数组i下标的元素要大于0
            while (count[i] > 0) {
                //重写 写回array数组 从0下标开始
                array[index] = i + minVal;
                index++;
                count[i]--;
            }
        }
    }

以上便是基本的排序算法,欢迎阅读

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1531758.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLO_you only look once

前言 计算机图形学的课程即将结束&#xff0c;我需要提交一份关于YOLO模型的学习报告。在这段时间里&#xff0c;我对YOLO进行了深入的学习和研究&#xff0c;并记录下了我的学习过程和心得体会。本文将详细介绍YOLO模型的原理、优缺点以及应用领域&#xff0c;希望能够为后续…

matlab 混沌系统李雅普洛夫指数谱相图分岔图和庞加莱界面

1、内容简介 略 65-可以交流、咨询、答疑 2、内容说明 matlab 混沌系统李雅普洛夫指数谱相图分岔图和庞加莱界面 混沌系统李雅普洛夫指数谱相图分岔图和庞加莱界面 李雅普洛夫指数谱、相图、分岔图、庞加莱界面 3、仿真分析 略 4、参考论文 略

UE4_调试工具_绘制调试球体

学习笔记&#xff0c;仅供参考&#xff01; 效果&#xff1a; 步骤&#xff1a; 睁开眼睛就是该变量在此蓝图的实例上可公开编辑。 勾选效果&#xff1a;

函数栈帧的创建和销毁 - 局部变量|函数传参|函数调用|函数返回|图文详解

目录 1.寄存器EBP和ESP 2.函数栈帧的创建 3.函数的调用 4. 函数栈帧的销毁 函数栈帧&#xff08;function stack frame&#xff09;是在函数调用期间在栈上分配的内存区域&#xff0c;用于存储函数的局部变量、参数、以及用于函数调用和返回的相关信息。每当函数被调用时&a…

Redis 应用与原理(三)

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 Redis Cluster 解决方案 基础概念 首先&#xff0c;分析一下主从哨兵模式带来的问题&#xff1a; 在主从 哨兵的模式下&#xff0c;仍然只有一个 Master 节点&#xff0c;当并发请求较大时&#xff0c;哨兵…

config.properties的存放位置在Javaweb和Java工程中的区别

Java项目中&#xff1a;一般是与src平行的设置一个config目录&#xff0c;然后把配置文件放到config目录里面 Javaweb中&#xff1a;一般放到src目录下 顺便补习一下Properties的用法 package config;import java.io.FileInputStream; import java.io.FileOutputStream; impor…

JD商品详情原数据 API 返回值说明

一、应用场景 商品详情原数据API的应用场景广泛而多样。具体来说&#xff0c;它可以被用于以下方面&#xff1a; 1、电商平台数据分析&#xff1a;电商平台可以通过商品详情原数据API提取商品销售数据、质量评分、评论和反馈等信息&#xff0c;从而帮助用户更好地理解市场和竞…

QT charts模块画图

QT charts模块画图 在项目中使用Qt Charts模块,必须在项目的配置文件(.pro文件)添加行语句。 QT += core gui charts或者 QT += core gui QT += charts在需要使用QtCharts的类的头文件或源文件中,包含如下语句 #include <QWidget> #include &…

Java基础 学习笔记六

自增运算符 /* 自加1-- 自减11. 可以出现在变量前&#xff0c;也可以出现在变量后i 可以i 也可以像这种欲奴算符&#xff0c;只有一边有操作数&#xff0c;我们把这种运算符称为 一元运算符a b 这里的 两边有两个操作数&#xff0c;所以这种运算符被称为 二元运算符2. 无论出…

基于微信小程序的电影交流平台

技术&#xff1a;springbootmysqlvue 一、背景 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。所以各行业&#xff0c;尤其是规…

matlab中Signal Editor定义梯形信号输出矩形信号

matlab中Signal Editor定义梯形信号输出矩形信号&#xff0c;可以通过如下勾选差值数据实现梯形信号输出。

nginx学习记录-目录结构及基本配置

1. nginx目录结构 执行tree命令就可以看到nginx的目录结构了&#xff0c;主要有4个&#xff0c;分别是配置目录conf&#xff0c;还有界面目录html&#xff0c;日志目录logs以及程序sbin/nginx。 2. nignx基本配置 nginx的主要配置文件为/usr/local/nginx/conf/nginx.conf&…

网络协议与层次划分:探索计算机网络体系结构

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

关于继承是怎么样的?那当然是很好理解之

本文描述了关于继承的大部分知识&#xff0c;但是并不全&#xff0c;每篇博客之间的知识都有互串&#xff0c;所以需要把几篇文章合起来看&#xff0c;学会融会贯通&#xff01; 温馨提示&#xff1a;使用PC端观看&#xff0c;效果更佳&#xff01; 目录 1.继承是什么 2.什…

FREERTOS任务通知

从 v8.2.0 版本开始&#xff0c;FreeRTOS 新增了任务通知(Task Notifictions)这个功能&#xff0c;可以使用任务通知来代替信号量、消息队列、事件标志组等这些东西。使用任务通知的话效率会更高。 有个疑惑&#xff1a; 队列是两个互通消息的任务之外的一个特性&#xff0c;而…

基于springboot+vue的中山社区医疗综合服务平台

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Vue.js+SpringBoot开发创意工坊双创管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员端2.2 Web 端2.3 移动端 三、系统展示四、核心代码4.1 查询项目4.2 移动端新增团队4.3 查询讲座4.4 讲座收藏4.5 小程序登录 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的创意工坊双创管理…

【机器学习】科学库使用第2篇:机器学习概述,学习目标【附代码文档】

机器学习&#xff08;科学计算库&#xff09;完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;机器学习&#xff08;常用科学计算库的使用&#xff09;基础定位、目标&#xff0c;机器学习概述定位,目标,学习目标,学习目标。机器学习概述&#xff0c;1.3 人…

计算机设计大赛 题目: 基于深度学习的疲劳驾驶检测 深度学习

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 &#x1f525; 优…

初识HOOK框架frida

hook是什么 hook框架是一种技术&#xff0c;用于在运行时拦截和修改应用程序的行为&#xff0c;通过hook&#xff0c;可以劫持应用程序的方法调用、修改参数、篡改返回值等&#xff0c;以达到对应用程序的修改、增强或调试的目的。 常见的hook框架有哪些 Xposed Framework&am…