六大排序详讲(直接插入排序+希尔排序+选择排序+堆排序+冒泡排序+快速排序)

文章目录

  • 排序
    • 一、 排序的概念
      • 1.排序:
      • 2.稳定性:
      • 3.内部排序:
      • 4.外部排序:
    • 二、插入排序
      • 1.直接插入排序
      • 2.希尔排序
    • 三、选择排序
      • 1.直接选择排序
          • 方法一
          • 方法二
          • 直接插入排序和直接排序的区别
      • 2.堆排序
    • 四、交换排序
      • 1.冒泡排序
      • 2.快速排序
          • 1.挖坑法
          • 2.Hoare法
          • 3.前后指针法
          • 4.快速排序的优化
            • 方法一:随机选取基准值
            • 方法二:三数取中法选基准值
            • 方法三:递归到最小区间时、用插入排序
          • 5.快速排序非递归实现

排序


一、 排序的概念

1.排序:

  • 一组数据按递增/递减排序

2.稳定性:

在这里插入图片描述

  • 待排序的序列中,存在多个相同的关键字,拍完序后,相对次序保持不变,就是稳定的

3.内部排序:

  • 数据元素全部放在内存中的排序

4.外部排序:

  • 数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序

二、插入排序

1.直接插入排序

在这里插入图片描述

和整理扑克牌类似,将乱序的牌,按值的大小,插入整理好的顺序当中

从头开始,比最后一个小的话依次向前挪,直到大于之前牌时,进行插入

在这里插入图片描述

1.如果只有一个值,则这个值有序,所以插入排序, i 从下标1开始,把后面的无序值插入到前面的有序当中

2.j = i-1,是i的前一个数,先用tmp将 i位置的值(要插入的值)先存起来,比较tmp和j位置的值

3.如果tmp的值比 j位置的值小,说明要向前插入到有序的值中,把 j位置的值后移,移动到 j+1的位置,覆盖掉 i 的值

4.j 下标向前移动一位,再次和 tmp 比较

5.如果tmp的值比 j 位置的值大,说明找到了要插入的位置就在当前j位置之后,把tmp存的值,放到 j+1的位置

6.如果tmp中存的值比有序的值都小,j位置的值依次向后移动一位,j不停减1,直到排到第一位的数移动到第二位,j的下标从0移动到-1,循环结束,最后将tmp中存的值,存放到 j+1的位置,也就是0下标

    public void insertSort(int[] array) {

        for (int i = 1; i < array.length; i++) {
            int tmp = array[i];//tmp存储i的值
            int j = i - 1;
            for (; j >= 0; j--) {
                if (tmp < array[j]) {
                    array[j + 1] = array[j];
                } else {
                    // array[j+1] = tmp;
                    break;
                }
            }
            array[j + 1] = tmp;
        }
    }

插入就是为了维护前面的有序

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

  • 时间复杂度O( N 2 )

  • 空间复杂度O ( 1 )

  • 稳定性:稳定

    如果一个排序是稳定的,可以改变实现为不稳定的

    如果是不稳定的排序,则没有办法改变

2.希尔排序

在这里插入图片描述

希尔排序shellSort 叫缩小增量排序,是对直接插入排序的优化,先分组,对每组插入排序,让整体逐渐有序

利用了插入排序元素越有序越快的特点

在这里插入图片描述

  • 先确定一个整数,把待排序数分成多个组,每个组中的数距离相同,
  • 对每一组进行排序,然后再次分组排序,减少分组数,组数多,每组数据就少
  • 找到分组数=1时,基本有序了,只需要再排一次插入排序即可

一开始组数多,每组数据少,可以保证效率

随着组数的减少,每组数据变多,数据越来越有序,同样保证了效率

到达1分组之前,前面的排序都是预排序

    public static void shellSort2(int[] array) {

        int gap = array.length;
        while (gap > 1) { //gap>1时缩小增量
            gap /= 2;//直接在循环内进行最后一次排序
            shell(array, gap);
        }

    }
    /**
     *
     * 希尔排序
     * 时间复杂度O(N^1.3---N^1.5)
     * @param array
     */

    public static void shellSort1(int[] array) {

        int gap = array.length;
        while (gap > 1) { //gap>1时缩小增量
            shell(array, gap);
            gap /= 2;//gap==1时不进入循环,再循环为再次排序
        }
        shell(array, gap);
        //组数为1时,进行插入排序
    }

    public static void shell(int[] arr, int gap) {
        //本质上还是插入排序,但是i和j的位置相差为组间距
        for (int i = gap ; i < arr.length; i++) {
            int tmp = arr[i];
            int j = i-gap;
            for (; j >=0; j -= gap) {
                if (tmp<arr[j]){
                    arr[j+gap] = arr[j];
                }else {
                    break;
                }
            }
            arr[j+gap] = tmp;
        }
    }

  • 时间复杂度:O( N^1.3 ^) ---- O( N^1.5 ^)
  • 空间复杂的:O(1)
  • 稳定性:不稳定

三、选择排序

在这里插入图片描述

  • 在待排序序列中,找到最小值(大)的下标,和排好序的末尾交换,放到待排序列的开头,直到全部待排序元素排完

1.直接选择排序

在这里插入图片描述

方法一

    /**
     * 选择排序
     *
     * @param array
     */
    public static void selectSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            for (int j = i + 1; j < array.length; j++) {//找最小值
                if (array[j] < array[minIndex]) {
                    minIndex = j;//只要比minIndex小,放进去
                }
            }//循环走完后,minIndex存的就是当前未排序的最小值

            //将当前i的值和找到的最小值进行交换
            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;
    }

1.遍历数组长度,i从0开始

2.每次循环,都由minIndex = i 来记录最小值的下标

3.j 从i+1开始遍历,只要比记录的最小值小,就让minIndex记录。找到未排序中的最小值,进行交换

4.如果遍历完后,未排序中没有比minIndex存的值小,i的值就是最小值,i++;

  • 效率低, 如果较为有序的序列,在交换时会破坏有序性
  • 时间复杂度:O ( N2 )
  • 空间复杂的:O ( 1 )
  • 稳定性:不稳定
方法二
  • 上面的方法,只是先选出最小的值,然后和i的位置交换,

  • 进行优化:在遍历时选出最大值和最小值,和收尾进行交换

在这里插入图片描述

   /**
     * 选择排序---选最大值和最小值
     *
     * @param array
     */
    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[maxIndex]) {
                    maxIndex = i;
                }
                if (array[i] < array[minIndex]) {
                    minIndex = i;
                }
            }
            //用最大值和最小值交换首位
            swap(array, left, minIndex);
            //把left和最小值交换
            //如果left恰好就是最大值,就有可能把最大值换到minIndex的位置
            if(left == maxIndex){
                maxIndex = minIndex;//最大值位置不是left了,而是换到了minIndex
            }
            swap(array, right, maxIndex);
            left++;
            right--;
        }
    }

1.在遍历的过程中,选出最大值的下标和最小值的下标

2.将left和最小值进行交换

3.如果left恰好为最大值,left和最小值交换完成后,最大值就在原来最小值的位置上,

4.maxIndex = minIndex,修正最大值的位置

4.将right和最大值进行交换

直接插入排序和直接排序的区别
  • 和插入排序不同的是,插入排序会持续对已排序的数进行比较,把合适的数放在合适的位置
  • 直接选择排序就是不断找到最小的值,依次放在排好序的末尾,不干预排好的序列

2.堆排序

  • 时间复杂度: O( N * log N)
  • 空间复杂的:O (1)
  • 升序:建大堆

  • 降序:建小堆

  • 在这里插入图片描述

将一组数据从小到大排序 ——> 建立大根堆

为什么不用小根堆:小根堆只能保证,根比左右小,不能保证左右孩子的大小顺序,并且要求对数组本身进行排序

  • 大根堆,保证堆顶元素是最大值,最大值跟最后一个元素交换,将最大的放在最后,usedSize–;
  • 向下调整:调整0下标的树,维护大根堆,最大值继续交换到最后一个有效元素的位置
  • 从后往前,从大到小依次排列,保证在原来数组本身进行排序
    /**
     * 堆排序
     * 时间复杂度: N*logN
     * 空间复杂的:o(1)
     *
     * @param array
     */
    public static void heapSort(int[] array) {
        createBigHeap(array);//创建大根堆
        int end = array.length-1;
        while (end>0){
            swap(array,0,end);//堆顶元素和末尾互换
            shiftDown(array,0,end);//维护大根堆
            end--;
        }
    }
    /**
     * 创建大根堆
     *
     * @param array
     */
    public static void createBigHeap(int[] array) {
        //最后一个结点的下标 = array.length - 1
        //它的父亲结点的下标就为array.length - 1 - 1) / 2
        for (int parent = (array.length - 1 - 1) / 2; parent >= 0; parent--) {
            shiftDown(array, parent, array.length);
        }

    }

    /**
     * 向下调整
     *
     * @param array
     * @param parent
     * @param len
     *///向下调整,每棵树从父结点向下走

    public static void shiftDown(int[] array, int parent, int len) {
        int child = parent * 2 + 1;
        while (child < len) {
            //child < len:最起码要有一个左孩子
            if (child + 1 < len && array[child] < array[child + 1]) {
                child++;
            }//child + 1<len:保证一定有右孩子的情况下,和右孩子比较
            //拿到子节点的最大值
            if (array[child] > array[parent]) {
                swap(array, child, parent);
                parent = child;//交换完成后,让parent结点等于等于当前child结点
                child = 2 * parent + 1;
                //重新求子节点的位置,再次进入循环交换
            } else {
                break;
                //比父结点小,结束循环
            }
        }
    }

  • 时间复杂度: O( N * log 2N)
  • 空间复杂的:O (1)
  • 稳定性:不稳定

四、交换排序

  • 根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置
  • 将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

1.冒泡排序

在这里插入图片描述

    /**
     * 冒泡排序
     * 时间复杂度 n^2
     * 空间复杂度  1
     * @param array
     */
    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-1-i; j++) {
                if (array[j]>array[j+1]){
                    swap(array,j,j+1);
                    flg = true;
                }
            }
            if (flg == false){
                return;
            }
        }
    }


1.遍历 i 代表交换的趟数,遍历 j 进行两两交换

2.j < array.length-1-i 是对于趟数的优化,每走一趟,交换就少一次

3.boolean flg =false;当两两交换时,flg变为true

4.进一步优化:如果遍历完,没发生交换,flg还是false,直接返回,排序结束

  • 时间复杂度:O ( N2 )
  • 空间复杂度:O ( 1 )
  • 稳定性:稳定

2.快速排序

  • 时间复杂度:

    最好情况:O (N*log2N) :树的高度为log2N,每一层都是N

    最坏情况:O (N2):有序、逆序的情况下,没有左树,只有右树,单分支树,树的高度是N,每一层都是N

  • 空间复杂的:

    最好情况:O (log2N):满二叉树(均匀分割待排序的序列,效率最高)树高为 log2N

    最坏情况:O(N):单分支树,树高为N

  • 稳定性:不稳定

  • 二叉树结构的交换排序方法

  • 任取一个待排序元素作为基准值,把序列一分为二,左子序都比基准值小,右子序都比基准值大,左右两边再重复进行

在这里插入图片描述

  • 左边找比基准值大的,右边找比基准值小的
1.挖坑法

在这里插入图片描述

  • 基准值位置挖一个坑,后面找一个比基准值小的把坑埋上
  • 前面找一个比基准值大的,埋后面的坑
  • 当l==r时,把基准值填入剩下的坑中

在这里插入图片描述

  • 左右两边重复进行上述步骤,直到排完为止
  • 左右两边都以同样的方法进行划分,运用递归来实现
    /**
     * 快速排序
     * 时间复杂度:N*log~2~N
     * 空间复杂度
     * 
     * @param array
     */

    public static void quickSort(int[] array) {
        quick(array, 0, array.length - 1);
    }

    private static void quick(int[] array, int start, int end) {
        if (start >= end) {
            return;//结束条件
            // start == end,说明只剩一个了,是有序的,返回
            //start > end ,说明此时的基准值在开头或者末尾
            //在开头:start不变,end=pivot-1,start > end ,end=-1 没有左树
            //在结尾:end不变,start = pivot+1,start > end,超出索引,没有右树
        }
        //不断递归quick
        int pivot = partition(array, start, end);// 进行排序,划分找到pivot
        //然后递归划分法左边,递归划分的右边
        quick(array, start, pivot - 1);
        quick(array, pivot + 1, end);
    }

    // ---挖坑法  划分,返回基准值
    private static int partition(int[] array, int left, int right) {
        int tmp = array[left];//挖一个坑,取left位置为基准值
        while (left < right) {
            //在右边找一个比基准值小的把坑填上
            while (left < right && array[right] >= tmp) {//防止越界
                right--;
            }
            array[left] = array[right];//找到比tmp小的数,填坑,

            //在左边找一个比tmp大的值,填到右边的坑
            while (left < right && array[left] <= tmp) {//防止越界
                left++;
            }
            array[right] = array[left];
        }//如果相遇了,退出循环
        array[left] = tmp;//填坑
        return left;
    }

  • 先划分序列,递归左边,然后再递归右边

  • 递归结束条件:

    start == end时,说明只剩一个了,是有序的,返回
    start > end 时 ,说明此时的基准值在开头或者末尾

    如果基准值在开头:start不变,end=pivot-1,start > end ,end=-1 没有左树
    如果基准值在结尾:end不变,start = pivot+1,start > end,超出索引,没有右树


2.Hoare法

在这里插入图片描述

  • 不同的方法,找出基准值,排的序列是不一样的

在这里插入图片描述

  • i记录基准值一开始在left位置的下标
  • r找到比基准值小的停下来,l找到比基准值大的停下来,互相交换
  • l和r相遇的时候,把i 记录基准值的初始下标和相遇位置交换

以左边为基准,先找右边再找左边,相遇的位置就是以右边为基准的值,要比基准小,才能交换

    /**
     * Hoare法 划分排序找基准值
     * @param array
     * @param left
     * @param right
     * @return
     */
    private static int partition2(int[] array, int left, int right) {
        int tmp = array[left];
        int i  = left;//记录基准值一开始在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;
    }
3.前后指针法

在这里插入图片描述

在这里插入图片描述

  • prev记录了比key小的最后一个位置
  • cur去找比key值小的,找到后,放到prev的下一个位置
  • 最后找到基准值,并且基准值的左边都比它小,右边都比他大
    /**
     * 前后指针法,划分排序找基准值
     *
     * @param array
     * @param left
     * @param right
     * @return
     */
    private static int partition3(int[] array, int left, int right) {
        int prev = left; //prev从left位置开始,left为当前的基准值
        int cur = left + 1;//cur在prev的后一个
        while (cur <= right) {//遍历完当前数组段
            if (array[cur] < array[left] && array[++prev] != array[cur]) {
                //只要cur指向的值小于left位置的基准值
                //并且prev++后不等于cur的值
                swap(array, cur, prev);//将cur和prev位置的值交换
                //cur++;
            }
            //如果cur的值大于基准值,或者prev下一位的值等于cur,cur后移
            cur++;
        }
        //cur越界,循环结束,最后,交换基准值和prev位置的值
        //prev记录的就是比基准值小的最后一个数
        swap(array, prev, left);
        return prev;//prev为基准值
    }

4.快速排序的优化
  • 时间复杂度:

    最好情况:O (N*log2N) :树的高度为log2N,每一层都是N

    最坏情况:O (N2):有序、逆序的情况下,没有左树,只有右树,单分支树,树的高度是N,每一层都是N

  • 空间复杂的:

    最好情况:O (log2N):满二叉树(均匀分割待排序的序列,效率最高)树高为 log2N

    最坏情况:O(N):单分支树,树高为N

  • 稳定性:不稳定

  • 快速排序有可能发生栈溢出异常,需要进行优化

  • 所以要能均匀分割待排序的序列

递归的次数多了,会导致栈溢出,所以优化的方向就是减少递归的次数

在最坏情况下,比如顺序,基准值都取自左边,本身没有左树

方法一:随机选取基准值

看人品,有概率

方法二:三数取中法选基准值

三数:第一个数、中间的数、最后一个数 ,在这三个数中,选出中等值

有可能会变成二分查找 ,避免了出现最坏情况,从中值来比较排序,左右树都有

    public static void quickSort(int[] array) {
        quick2(array, 0, array.length - 1);
    }


    private static void quick2(int[] array, int start, int end) {
        if (start >= end) {
            return;//结束条件
        }
        //三数取中法
        int index = midThree(array, start, end);
        //选出的数和开头交换
        swap(array,index,start);

         int pivot = partition(array, start, end);// 进行排序,划分找到pivot
        //然后递归划分法左边,递归划分的右边
        quick2(array, start, pivot - 1);
        quick2(array, pivot + 1, end);
    }


    /**
     * 三数取中
     * @param array
     * @param left
     * @param right
     * @return
     */
    private static int midThree(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 {
            if (array[mid] < array[right]) {
                return right;
            } else if (array[mid] > array[left]) {
                return left;
            } else {
                return mid;
            }
        }
    }
方法三:递归到最小区间时、用插入排序

进一步优化:减少递归的次数:

  • 把快排的递归想象成二叉树,最后两层包含了大部分数,我们要减少这部分的递归

  • 前几次的找基准值排序,导致后面几层趋于有序,用直接插入法来排序,进一步提高效率,有点像希尔排序

如果树的高度为h,最后一层就有 2 h-1 个结点 ,后两层占了绝大部分

设置条件:end-start+1 就是当前待排序列的长度,如果小于等于某个较小的值,直接采用插入排序来排剩下的

 private static void quick2(int[] array, int start, int end) {
        if (start >= end) {
            return;//结束条件
        }
        //优化----减少递归的次数
        if(end-start+1<=20){
            //如果当前数列的长度,小于=15的时候,
            // 用插入排序,然后退出
            insertSortQ(array,start,end);

            return;
        }

        //三数取中法
        int index = midThree(array, start, end);
        swap(array,index,start);

         int pivot = partition(array, start, end);// 进行排序,划分找到pivot
        //然后递归划分法左边,递归划分的右边
        quick2(array, start, pivot - 1);
        quick2(array, pivot + 1, end);
    }

    /**
     * 插入排序---来排剩下的待排部分,给定需要的区间
     */
    private static void insertSortQ(int[] array,int left,int right) {
        for (int i = left+1; i <= right; i++) {
            int tmp = array[i];
            int j = i - 1;
            for (; j >= left; j--) {
                if (array[j] > tmp) {
                    array[j + 1] = array[j];
                } else {
                    break;
                }
            }
            array[j + 1] = tmp;
        }
    }

5.快速排序非递归实现
  • 1.通过使用栈来实现
  • 2.每次找到基准值后,把两段序列的开头和末尾压栈
  • 3.从栈顶取出两个元素作为新序列的首尾,再次找基准值
  • 4.找到基准值后,如果右边有一个元素,不进栈,有两个元素的才能进栈
  • 5.pivot< end-1:证明右边有两个元素,pivot>s+1:证明左边有两个元素
  • 6.栈为空的时候,排完元素
      /**
     * 非递归实现快速排序
     *
     * @param array
     */
    public static void quickSortNonRecursive(int[] array) {
        Deque<Integer> stack = new LinkedList<>();//利用栈来实现
        int left = 0;
        int right = array.length - 1;
        //先找到基准值
        int pivot = partition(array, left, right);
        //左边有两个元素时,根据基准值进栈
        if (pivot > left + 1) {
            stack.push(left);
            stack.push(pivot - 1);
        }
        //有边有两个元素时,根据基准值进栈
        if (pivot < right - 1) {
            stack.push(pivot + 1);
            stack.push(right);
        }
        //栈不为空的时候,取两个栈顶元素做为区间
        //再次进栈出栈
        while (!stack.isEmpty()) {
            right = stack.pop();
            left = stack.pop();
            pivot = partition(array, left, right);
            //左边有两个元素时,根据基准值进栈
            if (pivot > left + 1) {
                stack.push(left);
                stack.push(pivot - 1);
            }
            //有边有两个元素时,根据基准值进栈
            if (pivot < right - 1) {
                stack.push(pivot + 1);
                stack.push(right);
            }
        }
    }

点击移步博客主页,欢迎光临~

偷cyk的图

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Threejs_07 环境、透明度、纹理、ao、光照等贴图的渲染

老陈打码 继续学习老陈threejs 支持&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 下面用到的所有图片、资源、hdr文件都是老陈打码的原资源 链接&#xff1a;https://pan.baidu.com/s/1WWWHgekCIH7OnjI7S_3ZtQ 提取码&#xff1a;6666 Thre…

新建模板,或组件自适应

1&#xff0c;***一定要改为固定布局&#xff08;才可以自适应&#xff09; 2&#xff0c; 3&#xff0c; 4&#xff0c;系统序号“1”就是第一根柱 5&#xff0c;系列-自动-配色这里1就是第一根柱颜色&#xff0c;2..... 6&#xff0c;坐标柱 标红的去掉&#xff0c;在那里设…

debian10 开启rdp安装firefox并解决firefox 中文乱码

debian10 开启rdp安装firefox apt -y install tigervnc-standalone-server apt -y install xrdp tigervnc-standalone-server systemctl enable xrdp --nowapt install firefox-esrmstsc连接 firefox-settings-general-fonts-advanced-Simplified Chinese

【vue+eltable】修改表格滚动条样式

<style lang"scss" scoped> ::v-deep .el-table__body-wrapper::-webkit-scrollbar {width: 10px; /*纵向滚动条的宽度*/height: 10px; /*横向滚动条的高度*/ } /*定义滚动条轨道 内阴影圆角*/ ::v-deep .el-table__body-wrapper::-webkit-scrollbar-track {bo…

以太网_底层

【实物图】 【网线接口】 MAC(媒体访问控制器)&#xff1a;控制数据的收发和管理&#xff0c;和用户层打交到&#xff1b;通过MII/RMII、SMI接口和PHY进行通信。 PHY(以太网物理层收发器)&#xff1a;中间体&#xff0c;负责收发信号的转换 常见PHY芯片有&#xff1a;LAN8720…

Docker上部署mysql(超简单!!!)

拉取mysql镜像 运行如下命令 docker pull mysql:5.7 拉取成功 查看镜像 运行容器 此处部署最新版本的mysql docker run -d --name mysql -p 3307:3306 -e TZAsia/Shanghai -e MYSQL_ROOT_PASSWORD111 mysql --name mysql&#xff1a;给容器起个名字&#xff08;唯一&#xff…

按照指定条件对数据进行分组并对每个分组内的全部数据应用自定义函数进行聚合计算groupby().apply()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 按照指定条件对数据进行分组 并对每个分组内的全部数据 应用自定义函数进行聚合计算 groupby().apply() [太阳]选择题 下列输出正确的是&#xff1a; import pandas as pd data {Name: [A, B,…

Spring Cloud实战 |分布式系统的流量控制、熔断降级组件Sentinel如何使用

专栏集锦&#xff0c;大佬们可以收藏以备不时之需 Spring Cloud实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏&#xff1a;https:/…

深度解析Python Melt函数的妙用技巧

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是涛哥&#xff0c;今天为大家分享 Python Melt函数的妙用技巧&#xff0c;文章4200字&#xff0c;阅读大约15分钟&#xff0c;大家enjoy~~ 在数据处理和清洗中&#xff0c;melt函数是Pandas库中一个强大而灵活…

squid代理服务器(传统代理、透明代理、反向代理、ACL、日志分析)

一、Squid 代理服务器 &#xff08;一&#xff09;代理的工作机制 1、代替客户机向网站请求数据&#xff0c;从而可以隐藏用户的真实IP地址。 2、将获得的网页数据&#xff08;静态 Web 元素&#xff09;保存到缓存中并发送给客户机&#xff0c;以便下次请求相同的数据时快速…

抖音本地生活服务商申请怎么做?无保证金的申请方法来了

想做抖音的本地生活服务项目&#xff0c;却不知道去哪里申请&#xff0c;或者如何申请&#xff0c;其实&#xff0c;官方的通道在今年上半年还是有的&#xff0c;自己去平台上提交资料申请就可以了&#xff0c;但需要缴纳高额的保证金。 而在今年下半年&#xff0c;平台已经关…

从0开始学习JavaScript--深入理解JavaScript的async/await

JavaScript的异步编程在过去经历了回调地狱、Promise的引入&#xff0c;而今&#xff0c;通过async/await&#xff0c;让我们获得了更加优雅、可读性更高的异步编程方式。本文将深入探讨async/await的概念、用法&#xff0c;并通过丰富的示例代码展示其在实际应用中的威力。 理…

Linux安装ErLang(亲测可用)

注&#xff08;我这里安装完成后显示的是中文&#xff0c;有的是显示的英文&#xff09; 1.下载er wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm2.安装er yum -y install epel-release截图截不全&#xff0c;就只截安装完成的部分了 rp…

在银行外包如何自我提升

作者&#xff1a;苍何&#xff0c;前大厂高级 Java 工程师&#xff0c;阿里云专家博主&#xff0c;CSDN 2023 年 实力新星&#xff0c;土木转码&#xff0c;现任部门技术 leader&#xff0c;专注于互联网技术分享&#xff0c;职场经验分享。 &#x1f525;热门文章推荐&#xf…

基于单片机公交安全预警系统仿真设计

**单片机设计介绍&#xff0c; 基于单片机公交安全预警系统仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的公交安全预警系统可以被设计成能够实时监测公交车辆的行驶状态&#xff0c;并在发生异常情况时进行…

使用Pytorch实现linear_regression

使用Pytorch实现线性回归 # import necessary packages import torch import torch.nn as nn import numpy as np import matplotlib.pyplot as plt# Set necessary Hyper-parameters. input_size 1 output_size 1 num_epochs 60 learning_rate 0.001# Define a Toy datas…

GB28181视频监控国标平台EasyGBS如何进行服务迁移?

视频流媒体安防监控国标GB28181平台EasyGBS视频能力丰富&#xff0c;部署灵活&#xff0c;既能作为业务平台使用&#xff0c;也能作为安防监控视频能力层被业务管理平台调用。国标GB28181视频EasyGBS平台可提供流媒体接入、处理、转发等服务&#xff0c;支持内网、公网的安防视…

直播岗位认知篇

一、直播岗位概述 直播岗位&#xff0c;也称为直播主播或直播运营&#xff0c;是指在互联网直播平台上进行直播活动的工作岗位。该岗位的主要职责是通过直播形式&#xff0c;向观众展示自己的才艺、分享生活、销售产品或服务&#xff0c;并引导观众互动和参与。直播主播需要具…

【C++】泛型编程 ⑪ ( 类模板的运算符重载 - 函数实现 写在类外部的不同的 .h 头文件和 .cpp 代码中 )

文章目录 一、类模板的运算符重载 - 函数实现 写在类外部的不同的 .h 头文件和 .cpp 代码中1、分离代码 后的 友元函数报错信息 - 错误示例Student.h 头文件内容Student.cpp 代码文件内容Test.cpp 代码文件内容执行报错信息 2、问题分析 二、代码示例 - 函数实现 写在类外部的不…

设计模式总结-笔记

一个目标&#xff1a;管理变化&#xff0c;提供复用&#xff01; 两种手段&#xff1a;分解vs.抽象 八大原则&#xff1a; 依赖倒置原则&#xff08;DIP&#xff09; 开放封闭原则&#xff08;OCP&#xff09; 单一职责原则&#xff08;SRP&#xff09; Liskov替换原则&a…