数据结构与算法基础(青岛大学-王卓)(9)

news2024/11/20 4:48:39

终于迎来了最后一部分(排序)了,整个王卓老师的数据结构就算是一刷完成了,但是也才是数据结构的开始而已,以后继续与诸位共勉 😃 (PS.记得继续守护家人们的健康当然还有你自己的)。用三根美味的烤香肠开始吧。。。


文章目录

    • 排序
      • 基本概念和排序方法概述
        • 排序
        • 排序方法概述
        • 按排序依据原则
      • 插入排序
        • 直接插入排序
          • 插入法(临时空间)
          • 插入法(哨兵): 就是将临时空间替换成预留的0号位置
          • 算法
          • 性能分析
        • 折半插入排序
          • 算法
          • 算法分析
        • 希尔排序(Donald.L.Shell)
          • 基本思想
          • 算法效率
      • 交换排序
        • 冒泡排序
          • 算法
          • 改进算法(添加交换标志):
          • 效率分析
          • 冒泡排序算法总结
        • 快速排序
          • 基本思想
          • 具体实现
          • 算法
          • 性能分析
      • 选择排序
        • 简单选择排序
          • 基本操作
          • 算法
          • 时间复杂度
        • 堆排序
          • 堆的定义
          • 堆排序定义
      • 归并排序
        • 基本思想
        • 算法
        • 效率
      • 基数排序
        • 基本思想
        • 排序方法
        • 性能分析
      • 各种排序方法比较
        • 时间性能
        • 空间性能
        • 排序方法的稳定性能
        • 关于"排序方法的时间复杂度的下限"
    • 这是条美丽的分割线

排序

基本概念和排序方法概述

排序

将无序序列排成一个有序序列(由小到大或由大到小)的运算。

如果参加排序的数据结点包含多个数据域,那么排序往往是针对其中某个域而言

排序方法概述
  • 存储介质:

    • 内部排序:数据量不大、数据在内存,无需内外存交换数据
    • 外部排序:数据量较大、数据在外存(文件排序)(外部排序时,要将数据分批调入内存来排序,中间结果还要及时放入外存,显然外部排序要复杂得多)
  • 比较器个数:

    • 串行排序:单处理机(同一时刻比较一对元素)
    • 并行排序:多处理机(同一时刻比较多对元素)
  • 主要操作:

    • 比较排序:用比较的方法, 包含插入排序、交换排序、选择排序、归并排序
    • 基数排序:不比较元素的大小,仅仅根据元素本身的取值确定其有序位置。
  • 辅助空间:

    • 原地排序:辅助空间用量为 O(1) 的排序方法。(所占的辅助存储空间与参加排序的数据量大小无关)
    • 非原地排序:辅助空间用量超过 O(1) 的排序方法。
  • 稳定性:

    • 稳定排序:能够使田可数值相等的元素,排序以后相对次序不变。
    • 非稳定性排序:不是稳定排序的方法。
    • 排序的稳定性只对结构类型数据排序有意义。
  • 自然性:

    • 自然排序:输入数据越有序,排序的速度越快的排序方法。
    • 非自然排序:不是自然排序的方法。
按排序依据原则

插入排序:直接插入排序、折半插入排序、希尔排序

交换排序:冒泡排序、快速排序

选择排序:简单选择排序、堆排序

归并排序: 2 一路归并排序

基数排序

按排序所需工作量

简单的排序方法: T(n)=O(n2)

基数排序: T(n)=O(d.n)

先进的排序方法: T(n)=O(nlogn)

存储结构 - 以顺序表记录序列

在这里插入图片描述

插入排序

基本操作:有序插入

  • 在有序序列中插入一个元素,保持序列有序,有序长度不断增加。

  • 起初, a[0] 是长度为 1 的子序列。然后,逐一将 a[1]至 a[n-1] 插入到有序子序列中。

  • 在插入 a[i]前,数组 a 的前半段( a[0] ~ a[i-1]) 是有序段,后半段( a[i] ~a[n-1]) 是停留于输入次序的无序段

  • 插入 a[i]使 a[0] ~ a[i-1] 保持有序,也就是要为 a[i] 找到有序位置 j( 0 <= j <= i ),将 a[i] 插入在 a[j] 的位置上。

  • 插入位置:中间,前面,后面

插入排序种类:直接插入排序、折半插入排序、希尔排序
在这里插入图片描述

直接插入排序

用顺序查找法查找插入位置

插入法(临时空间)

在这里插入图片描述
在这里插入图片描述

插入法(哨兵): 就是将临时空间替换成预留的0号位置

在这里插入图片描述

另外当我们插入i=6号位置的时候,如果i的值比前面一位(5号位)大,因为前面已经是有序了,所以i一定比前面所有元素都大,那就没有比较再赋值到哨兵位置比较了。
在这里插入图片描述

算法
void InsertSort(Sqlist &L) {
    int i,j;
    for (i=2; i<=L.length; ++i) {
        if (L.r[i].key < L.r[i-1].key) {  //若需插入元素比前面元素大就不用比较,反之要将L.r[i]插入有序子表排序
            L.r[0] = L.r[i];  // 复制为哨兵
            for (j=i-1; L.r[0].key<L.r[j].key; --j) {
            	L.r[j+1] = L.r[j]; //记录后移
        	}
        	L.r[j+1] = L.r[0]; //插入到正确位置
        }
    }
}
性能分析

实现排序的基本操作有两个:1. "比较"序列中两个关键字的大小;2. "移动"记录。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

时间复杂度结论

  • 原始数据越接近有序,排序速度越快

  • 最坏情况下(输入数据是逆有序的)Tw(n)=O(n2)

  • 平均情况下,耗时差不多是最坏情况的一半 Te(n)=O(n2)

  • 要提高查找速度

    • 减少元素的比较次数

    • 减少元素的移动次数

折半插入排序

查找位置时采用折半查找法

在这里插入图片描述

算法
void BInsertSort(SqList &L) {
    for (i=2; i<=L.length; ++i) { //依次插入第2~n个元素
        L.r[0]=L.r[i];  //待插入元素放入哨兵位置
        low=1; high=i-1; //二分法查找插入位置
        while (low<=high) {
            mid=(low+high)/2;
            if (L.r[0].key<L.r[mid].key) {
                high=mid-1;
            } else {
                low=mid+1;
            }
        } // 循环结束,high+1为插入位置
        for (j=i-1; j>=high+1; --j;) {  //将(high+1)~(i-1)的元素后移,空出(high+1)位置
            L.r[j+1]=L.r[j];   
        }
        L.r[high+1]=L.r[0];  //正确位置插入元素i
    }
}
算法分析
  • 折半插入排序的平均性能 > 直接插入排序

  • 它所需要的关键码比较次数与待排序对象序列的初始排列无关,仅依赖于对象个数。在插入第 i 个对象时,需要经过 ⌊ l o g   2   i ⌋ \lfloor log~2~i\rfloor log 2 i+1 次关键码比较,才能确定它应插入的位置,

    • 当 n 较大时,总关键码比较次数比直接插入排序的最坏情况要好得多,但比其最好情况(直接插入排序仅1次)要差;
    • 在对象的初始排列已经按关腱码排好序或接近有序时,直接插入排序比折半插入排序执行的关键码比较次数要少;
  • 折半插入排序的对象移动次数与直接插入排序相同,依赖于对象初始排列

    • 减少了比较次数,但没有减少移动次数
    • 平均性能优于直接插入排序
  • 时间复杂度为 O(n2)

  • 空间复杂度为 O(1)

  • 是一种稳定的排序方法

希尔排序(Donald.L.Shell)
基本思想

先将整待排记录序列分割成若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。

希尔排序算法,特点:1)缩小增量 2)多遍插入排序
在这里插入图片描述

排序思路:

  1. 定义增量序列 Dk :DM>DM-1>…>D1=1, 刚才的例子中: D3 = 5 , D2 = 3 , D1 = 1
  2. 对每个 Dk 进行 "Dk-间隔"插入排序 (k=M, M-1,1)

特点:

  • 一次移动,移动位置较大,跳跃式地接近排序后的最终位置
  • 最后一次只需要少量移动
  • 增量序列必须是递减的,最后一个必须是 1
  • 增量序列应该是互质的

算法:

void ShellSort(SqList &L, int dlta[], int t) {
    // dlta[t]存放步长dk的值,按增量序列dlta[0..t-1]对顺序表L做希尔排序
    for (k=0; k<t; ++k) { //t为多少趟
        ShellInsert(L, dlta[k]); //一趟增量为dlta[k]的插入排序
    }
}

void ShellInsert(SqList &L, int dk) {
    //对顺序表L进行一趟增量为dk的Shell排序,dk为步长因子
    for (i=dk+1; i<=L.length; ++i) {
        if (L.r[i].key<L.r[i-dk].key) {
            L.r[0]=L.r[i];
            for (j=i-dk; j>0 && (L.r[0].key<L.r[j].key); j=j-dk) {
                L.r[j+dk] = L.r[j];
            }
            L.r[j+dk] = L.r[0];
        }
    }
}
算法效率

希尔排序算法效率与增量序列的取值有关
在这里插入图片描述在这里插入图片描述

希尔排序法是一种不稳定的排序算法。

在这里插入图片描述

Note: 如何选择最佳 d 序列,目前尚未解决, 最后一个增量值必须为1,没有除了1之外的公因子,不宜在链式存储结构上实现。

交换排序

冒泡排序

基于简单交换思想:每趟不断将记录两两比较,并按"前小后大"规则交换

在这里插入图片描述

总结:

  • n 个记录,总共需要 n-1 趟
  • 第 m 趟需要比较 n - m 次
算法
//冒泡排序算法
void Bubble_Sort(SqList &L) {
    int m,i; RedType x; // 交换时所需临时空间
    for (m=1; m<=n-1; m++) { //总共m=n-1趟
        for (i=1; i<=n-m; i++) { //每趟比较n-m趟
            if (L.r[i].key > L.r[i+1].key) { //发生逆序,交换位置
                x = L.r[i];
                L.r[i] = L.r[i+1];
                L.r[i+1] = x;
            }
        }
    }
}

优点:每趟结束时,不仅能挤出一个最大值到最后面位置,还能同时部分理顺其他元素。

如何提高效率:一旦某一趟比较时不出现记录交换,说明已排好序了就可以结束本算法。

在这里插入图片描述

改进算法(添加交换标志):
//冒泡排序算法改进版(添加是否发生交换的标记)
void Bubble_Sort(SqList &L) {
    int m,i,flag=1; RedType x; // flag作为是否有交换的标记
    for (m=1; (flag=1) && (m<=n-1); m++) { //总共m=n-1趟
        flag=0; // 初始化为0,即没有交换
        for (i=1; i<=n-m; i++) { //每趟比较n-m趟
            if (L.r[i].key > L.r[i+1].key) { //发生逆序,交换位置
                flag=1;  //发生交换后flag做标记,这样可以进行下一轮,如果没交换则为0,上层趟数循环结束
                x = L.r[i];
                L.r[i] = L.r[i+1];
                L.r[i+1] = x;
            }
        }
    }
}
效率分析

在这里插入图片描述

冒泡排序算法总结
  • 最好时间复杂度是 O(n)
  • 最坏时间复杂度为 O(n2)
  • 平均时间复杂度为 O(n2)
  • 冒泡排序算法中增加一个辅助空间 temp ,辅助空间为 S(n)=O(1)
  • 冒泡排序是稳定的
快速排序

– 改进的交换排序

基本思想
  • 任取一个元素(如:第一个)为中心(pivot)
  • 所有比它小的元素一律前放,比它大的元素一律后放,形成左右两个子表
  • 对各子表重新选择中心元素并依此规则调整(递归思想),直到每个子表的元素只剩一个
  • 最终达到整个序列有序

在这里插入图片描述

具体实现

选定一个中间数作为参考,所有元素与之比较,小的调到其左边(从左往右放),大的调到其右边(从右往左放)。

(枢轴)中间数:可以是第一个数、最后一个数、最中间一个数、任选一个数等

在这里插入图片描述

==> 上面的方法在元素量很大的情况下会非常费空间,因为需要一个额外的表空间来存放数据。

改进:直接利用0号空间存放中间数

  1. 每一趟的子表的形成是采用从两头向中间交替式逼近法
  2. 由 于每趟中对各子表的操作都相似,可采用递归算法

在这里插入图片描述

算法
void main() {
    QSort(L,1,L.length);
}

void QSort(SqList &L, int low, int high) { //对顺序表L快速排序
    if (low < high) {  //长度>1
        pivotloc=Partition(L, low, high); //将L.r[low...high]一分为二,pivotloc为枢轴元素排好序的位置
    	QSort(L, low, pivotloc-1); //对低子表递归排序
    	QSort(L, pivotloc+1, high); //对高子表递归排序
    }
}

int Partition(SqList &L, int low, int high) {
    L.r[0]=L.r[low]; //放置pivot到0号位置
    pivotkey=L.r[low].key; //方便比较计算中枢的值
    while (low < high) {
        while ((low < high)&&(pivotkey <= L.r[high].key)) --high; //先找high位的值放到空的low去
        L.r[low]=L.r[high];
        while ((low < high)&&(pivotkey >= L.r[low].key)) ++low; //再找low位的值放到空的high去
        L.r[high]=L.r[low];
    }
    L.r[low]=L.r[0]; // 所有找完后low=high,将此位置返回给pivotloc
    return low; 
}
性能分析
  • 时间复杂度:可以证明,平均计算时间O(nlog2n)

    • Qsort( ): O(log2n)
    • Partition( ): O(n)
  • 实验结果表明:就平均计算时间而言,快速排序是我们所讨论的所有内排序方法中最好的一个.

  • 空间复杂度:快速排序不是原地排序

    • 由于程序中使用了递归,需要递归调用栈的支持,而栈的长度取决于递归调用的深度。(即使不用递归,也需要用用户栈)。
    • 在平均情况下:需要 O(logn)的栈空间。
    • 最坏情况下:栈空间可达 O(n)。
  • 快速排序是一种不稳定的排序方法
    在这里插入图片描述

  • 快速排序不适于对原本有序或基本有序的记录序列进行排序(有序的记录在一次划分之后得到的其中一个子序列的长度会为0,这个时候就退化成没有改进措施的冒泡排序)。

    • 试对( 90 , 85 , 79 , 74 , 68 , 50 , 46 )进行快速排序的划分
    • (子序列0) 90(pivotloc) 85, 79, 74, 68, 50, 46(子序列1)
  • 划分元素的选取是影响时间性能的关键

  • 输入数据次序越乱,所选划分元素值的随机性越好,排序速度越快,快速排序不是自然排序方法。

  • 改变划分元素的选取方法,至多只能改变算法平均情况的下的时间性能,无法改变最坏情况下的时间性能。即最坏情况下,快速排序的时间复杂性总是O(n2)

选择排序

简单选择排序

基本思想:在待排序的数据中选出最大(小)的元素放在其最终的位置。

基本操作
  • 首先通过一次关键字比较,从 n 个记录中找出关键字最小的记录,将它与第一个记录交换
  • 再通过 n-2 次比较,从剩余的一个记录中找出关键字次小的记录,将它与第二个记录交换
  • 重复上述操作,共进行 n-1 趟排序后,排序结束

在这里插入图片描述

算法
void SeletSort(SqList &L) {
    for (i=1; i<L.length; ++i) { //n个元素需执行n-1趟
        k=i; RedType x; //临时变量用于位置交换
        for (j=i+1; j<=L.length; j++) { //每趟比较n-i次
            if (L.r[j].key < L.r[k].key) { //当发现较小值时记录其位置
                k=j;
            }
        }
        if (k!=i) { //将找到的位置和第i个元素位置交换
            x=L.r[i];
            L.r[i]=L.r[k];
            L.r[k]=x;
        }
    }
}
时间复杂度

记录移动次数:

  • 最好情况: 0

  • 最坏情况: 3(n-1)

比较次数,无论待排序列处于什么状态,选择排序所需进行的"比较"次数都相同 n(n-1)/2 (比较次数为n-1+n-2+…+1)

简单选择排序是不稳定排序

在这里插入图片描述

空间复杂度:需要一个辅助空间O(1)

堆排序
堆的定义

在这里插入图片描述

从堆的定义可以看出,堆实质是满足如下性质的完全二叉树

  • 二叉树中任一非叶子结点均小于(大于)它的孩子结点

在这里插入图片描述

堆排序定义

若在输出堆顶的最小值(最大值)后,使得剩余 n - 1 个元素的序列重又建成一个堆,则得到 n 个元素的次小值(次大值)“如此反复,便能得到一个有序序列,这个过程称之为堆排序。

如何在输出堆顶元素后,调整剩余元素为一个新的堆?

小根堆

​ a. 堆顶元素之同以堆中最后一个元素替代之,

​ b. 然后将根结点值与左、右子树的根结点值进行比较,并与其中小者进行交换

​ c. 重复上述操作,直至叶子结点,将得到新的堆,称这个从堆顶至叶子的调整过程为"筛选"
在这里插入图片描述

算法:

void HeapAdjust(elem R[], int s, int m) {
    /*已知R[s...m]中记录的关键字除了R[s]之外均满足堆的定义,本函数调整R[s]关键字,是R[s...m]成为一个大根堆*/
    rc=R[s]; //将根结点值放在rc中
    for (j=2*s; j<=m; j*=2) { //循环开始沿着较大的孩子节点向下筛选
        if (j<m && (R[j]<R[j+1])) ++j; //哪个孩子大就选哪个结点,左孩子大就取j,右孩子大就取j+1
        if (rc >= R[j]) break; // 当根节点大于孩子结点直接结束for循环(因为其他元素已经满足大根堆定义了)
        R[s]=R[j]; //将该大孩子结点值和此时根节点值互换,重新置for循环的j值为下面子树上的孩子结点位置,循环继续直到比较完
        s=j;
    }
    R[s]=rc; //最后将rc(原根节点)放到最终筛选出来的位置s上
}

堆的调整:对一个无序序列反复筛选就可以得到一个堆,即:从一个无序序列建堆的过程就是一个反复"筛选"的过程。

如何由一个无序序列建成一个堆?

  • 单结点的二叉树是堆;

  • 在完全二叉树中所有以叶子结点(序号 i > n/2 )为根的子树是堆。

  • 这样,我们只需依次将以序号为,n/2, n/2-1, …,1 的结点为根的子树调整为堆即可。即:对应由 n 个元素组成的无序序列,"筛选"只需从第n/2 个元素开始。

建立思想

  • 由于堆实质上是一个线形表,那么我们可以顶序存储一个堆

  • 创建一个小根堆的例:有关键字为 49 , 38 , 65 , 97 , 76 , 1 3 , 27 , 49 的一组记录,将其按关键字调整为一个小根堆。

    在这里插入图片描述

将初始无序的 R[1]到 R[n]建成小根堆可用以下语句实现,

for (i=n/2; i<=1; i--) {
    HeapAdjust(R, i, n);
}

堆排序

堆排序就是利用完全二叉树中父结点与孩子结点之间的内在关系来排序的。

void HeapSort (elem R[]) { //对R[1]到R[n-1]进行堆排序
    int i;
    for (i=n/2; i>=1; i--) {
        HeapAdjust(R, i, n);  //创建初始堆
    }
    for (i=n; i>1; i--) {  //进行n-1趟排序
        Swap(R[1], R[i]);  //根与最后一个元素交换(相当于依次把元素有序从后往前放)
        HeapAdjust(R, i, i-1);  //对R[1]到R[i-1]重新建堆 
    }
}

算法性能分析:

  • 初始堆化所需时间不超过 O(n)

  • 排序阶段(不含初始堆化)

    • 一次重新堆化所需时间不超过 O(log n)
    • n-1 次循环所需时间不超过 O(n*log n)
    • Tw(n)=O(n)+ O(nlogn)= O(nlogn)
  • 堆排序的时间主要耗费在建初始堆和调整建新堆时进行的反复筛选上。堆排序在最坏情况下,其时间复杂度也为 O(nlogn), 这是堆排序的最大优点。无论待排序列中的记录是正序还是逆序排列,都不会使堆排序处于"最好"或"最坏"的状态。

  • 另外,堆排序仅需一个记录大小供交换用的辅助存储空间。

  • 然而堆排序是一种不稳定的排序方法,它不适用于待排序记录个数 n较少的情况,但对于 n 较大的文件还是很有效的。

归并排序

基本思想

将两个或两个以上的有序子序列"归并"为一个有序序列,内部排序中通常采用2-路归并排序(每次归并2个元素)

即:将两个位置相邻的有序子序列 R[l…m]和 R[m+1…n]归并为一个有序序列 R[l…n]

在这里插入图片描述

整个归并排序仅需 ⌈ l o g   2   n ⌉ \lceil log~2~n \rceil log 2 n趟(向上取整加一)

关键问题:如何将两个有序序列合成一个有序序列?
在这里插入图片描述

算法

R[low] - R[mid]R[mid+1] - R[high] 为相邻,归并成一个有序序列R1[low] - R1[high]

SR[i].key <= SR[j].key, 则 TR[k] = RS[i]; k++; i++;否则, TR[k]=SR[j];k++; j++;

在这里插入图片描述

效率

时间效率:O(nlog2n)

空间效率: O(n) 因为需要一个与原始序列同样大小的辅助序列 (R1) 。这正是此算法的缺点。

稳定性:稳定

基数排序

基本思想

分配+收集

也叫桶排序或箱排序:设置若干个箱子,将关键字为 k 的记录放入第 k 个箱子,然后在按序号将非空的连接。

排序方法

数字是有范围的,均由 0 - 9这十个数字组成,则只需设置十个箱子,相继按个、十、百….进行排序.
在这里插入图片描述

性能分析

时间效率O(k*(n+m)) (n为扔出去元素个数,m为收回桶的个数,每一趟需要做n+m次(一扔一收),k个关键字,所以总共需要k*(n+m))

  • k: 关键字个数
  • m: 关键字取值范围为 m 个值

在这里插入图片描述

空间效率O(n+m)

稳定性:稳定

缺点:关键字的范围必须是一定的

各种排序方法比较

时间性能
  1. 按平均的时间性能来分,有三类排序方法:

    • 时间复杂度为 O(nlogn)的方法有:快速排序、堆排序和归并排序,其中以快速排序为最好;
    • 时间复杂度为 O(n2)的有: 直接插入排序、冒泡排序和简单选择排序,其中以直接插入为最好,特别是对那些对关键字近似有序的记录序列尤为如此;
    • 时间复杂度为 O(n) 的排序方法只有:基数排序。
  2. 当待排记录序列按关键顺序有序时,直接插入排序和冒泡排序能达到O(n)时间复杂度;而对于快速排序而言,这是最不好的情况,此时的时间性能退化为 O(n2),因此是应该尽量避免的情况。

  3. 简单选择排序、堆排序和归并排序的时间性能不随记录序列中关键字的分布而改变。

空间性能

指的是排序过程中所需的辅助空间大小

  1. 所有的简单排序方法(包括:直接插入、冒泡和简单选择)和堆排序的空间复杂度为 O(1)
  2. 快速排序为 O(logn), 为栈所需的辅助空间
  3. 归并排序所需辅助空间最多,其空间复杂度为 O(n)
  4. 链式基数排序需附设队列首尾指针,则空间复杂度为 O(rd)
排序方法的稳定性能
  • 稳定的排序方法指的是,对于两个关键字相等的记录,它们在序列中的相对位置,在排序之前和经过排序之后,没有改变。
  • 当对多关键字的记录序列进行 LS D 方法排序时,必须采用稳定的排序方法。
  • 对于不稳定的排序方法,只要能举出一个实例说明即可。
  • 快速排序和堆排序是不稳定的排序方法。
关于"排序方法的时间复杂度的下限"
  • 本章讨论的各种排序方法,除基数排序外,其它方法都是基于"比较关键字"进行排序的排序方法,可以证明,这类排序法可能达到的最快的时间复杂度为 O(nlogn)。(基数排序不是基于"比较关键字"的排序方法,所以它不受这个限制)。
  • 可以用一棵判定树来描述这类基于"比较关键字"进行排序的排序方法。

这是条美丽的分割线


To Be Continued for Next Series, 共勉~

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

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

相关文章

高级深入--day41

用Pymongo保存数据 爬取豆瓣电影top250movie.douban.com/top250的电影数据&#xff0c;并保存在MongoDB中。 items.py class DoubanspiderItem(scrapy.Item):# 电影标题title scrapy.Field()# 电影评分score scrapy.Field()# 电影信息content scrapy.Field()# 简介info …

基于SSM的OA办公系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

nginx浏览器缓存和上流缓存expires指令_nginx配置HTTPS

1.nginx控制浏览器缓存是针对于静态资源[js,css,图片等] 1.1 expires指令 location /static {alias/home/imooc;#设置浏览器缓存10s过期expires 10s;#设置浏览器缓存时间晚上22:30分过期expires @22h30m;#设置浏览器缓存1小时候过期expires -1h;#设置浏览器不缓存expires …

【JavaEE初阶】 线程安全的集合类

文章目录 &#x1f340;前言&#x1f332;多线程环境使用 ArrayList&#x1f6a9;自己使用同步机制 (synchronized 或者 ReentrantLock)&#x1f6a9;Collections.synchronizedList(new ArrayList);&#x1f6a9;使用 CopyOnWriteArrayList &#x1f38d;多线程环境使用队列&am…

通过jdk自制https证书并配置到nginx并配置http2

生成证书 这里使用自己生成的免费证书。在${JAVA_HOME}/bin 下可以看到keytool.exe,在改目录打开cmd然后输入&#xff1a; keytool -genkey -v -alias lgq.com -keyalg RSA -keystore d:/zj/ssl/fastfly.com.keystore -validity 3650生成证书过程中&#xff1a;【你的名字】对…

美国海运专线冬季通航情况

随着全球经济一体化的推进&#xff0c;海运业务的重要性日益凸显。特别是在美国&#xff0c;作为世界上最大的经济体之一&#xff0c;其海运业务的发展对全球物流供应链有着重要影响。而在冬季&#xff0c;美国海运专线又会面临怎样的通航情况呢?下面就让我们一起来探讨一下。…

区块链技术与应用 【全国职业院校技能大赛国赛题目解析】第二套区块链系统部署与运维

第二套区块链系统部署与运维题目 环境 : ubuntu20 fisco : 2.8.0 docker: 20.10.21 webase-deploy : 1.5.5 mysql: 8.0.34 子任务1-2-1: 搭建区块链系统并验证(4分) 使用build_chain.sh 脚本文件进行搭建区块链 ,要求: 四节点,默认配置,单机,docker root@192-168-19…

【推荐】如何使用drawio的编辑器,看本文就够

学会使用drawio的编辑器 drawio是免费的开源的图表应用&#xff0c;你可以通过app.diagrams.net使用在线版本或者下载离线安装版在桌面端使用。 对于团队来讲&#xff0c; 把数据存储作为安全第一的图表应用&#xff0c; 你可以选择存储数据到不同的介质。例如Atlassian Conf…

deepxde更改backend

deepxde更改backend 1. 问题描述2. 解决方案 1. 问题描述 如果在使用deepxde库时&#xff0c;想使用除tensorflow.compat.v1之外的后端依赖&#xff0c;例如pytorch&#xff0c;会出现如下情况&#xff1a; 这时提示目前的后端依赖是tensorflow.compat.v1&#xff0c;需要更改…

RHCE---正则表达式

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 一. 文本搜索工具 grep是linux中一种强大的文件搜索过滤工具&#xff0c;可以按照正 则表达式检索文件内容&#xff0c;并把匹配的结果显示到屏幕上 &#xff08;匹配的内容会标红&#x…

[Python]Selenium-自动化测试

Selenium是一个web自动化测试的工具,在使用之前先在对应的项目添加工具包噢. 本文章主要简单的介绍了selenium对于自动化测试的使用 目录 添加浏览器驱动 get函数来到对应网站 驱动的定位 元素定位 id定位 class name定位 CSS定位 XPath定位 link text定位 定位一…

【如何去掉Unity点击运行时,Photon的警告弹窗】

如何去掉Unity点击运行时&#xff0c;Photon的警告弹窗 一、前言二、解决办法1、解决思路2、解决步骤 一、前言 我导入了Photon插件&#xff0c;但是我现在用不着&#xff0c;又不想将其删掉&#xff0c;Photon的配置也没有弄&#xff0c;导致现在一运行Unity&#xff0c;就会…

python re 使用非捕获组来忽略第一个value的匹配结果

import retext " value1,value2,value3 "pattern r"(?:value\d,){2}value(\d)"match re.search(pattern, text) print(match.group(1)) 其中&#xff0c;(?:...)表示非捕获组&#xff0c;{1}表示匹配前面的模式一次。该正则表达式的含义是&#xff1a…

力扣刷题 day56:10-26

1.解码异或后的数组 未知 整数数组 arr 由 n 个非负整数组成。 经编码后变为长度为 n - 1 的另一个整数数组 encoded &#xff0c;其中 encoded[i] arr[i] XOR arr[i 1] 。例如&#xff0c;arr [1,0,2,1] 经编码后得到 encoded [1,2,3] 。 给你编码后的数组 encoded 和原…

Hbase基本使用,读写原理,性能优化学习

文章目录 HBase简介HBase定义HBase数据模型**HBase** **逻辑结构****HBase** **物理存储结构****HBase** **基本架构** HBase 入门**HBase** **安装部署****HBase** 配置文件**HBase** 启动停止**HBase** **访问页面****HBase** **高可用****HBase Shell****HBase API**HBaseCo…

解决msvcp120.dll丢失的问题的5个方法,修复系统dll问题

在使用计算机的过程中&#xff0c;我们经常会遇到各种各样的动态链接库&#xff08;DLL&#xff09;文件。其中之一就是“msvcp120.dll丢失”。这个错误通常会导致某些应用程序无法正常运行。为了解决这个问题&#xff0c;我们需要找到合适的方法来修复丢失的msvcp120.dll文件。…

用Wireshark在本机环回接口上抓包

Wireshark版本下载、安装 访问官网&#xff1a;https://www.wireshark.org/ 可以下载最新的版本&#xff0c;例如4.0.10版本。包比较大&#xff0c;可能下载得比较慢。 下载到本地后&#xff0c;双击按照提示安装就行了。 在环回接口上抓包 启动Wireshark&#xff0c;双击在…

【网络】想学TCP,这一篇就够了 —— TCP理论知识详解(基于前面手搓TCP服务端博客的补充)

TCP理论 前言正式开始TCP报文如何进行分离和封装TCP如何将有效载荷交付给上层如何理解TCP的可靠性TCP报头中的序号和确认序号&#xff08;简单过一下&#xff0c;后面还会详细讲&#xff09;只要序号不要确认序号行不行乱序问题 16位窗口大小TCP的全双工通信方式16位窗口大小的…

java小程序商城免费搭建 VR全景商城 saas商城 b2b2c商城 o2o商城 积分商城 秒杀商城 拼团商城 分销商城 短视频商城

涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis …

C语言每日一题(20)最大公因数等于 K 的子数组数目

力扣 2447 最大公因数等于 K 的子数组数目 题目描述 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 nums 的子数组中元素的最大公因数等于 k 的子数组数目。 子数组 是数组中一个连续的非空序列。 数组的最大公因数 是能整除数组中所有元素的最大整数。 …