IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构笔记(王道考研) 第八章:排序 -> 正文阅读

[数据结构与算法]数据结构笔记(王道考研) 第八章:排序

大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找。。。)。后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到了查找一章,并增加了并查集、平衡二叉树的删除、红黑树的内容。

排序一章的各种算法动态过程比较难以展现,所以阅读体验可能不是特别好。

西电的校内考试分机试和笔试。笔试占50分,机试2小时4道题占30分,做出2道满分,多做一道总分加5分。机试尽量把老师平时发的OJ题目都过一遍。笔试内容偏基础,但考的量比较大。

?

其他各章节的链接如下:

数据结构笔记(王道考研) 第一章:绪论

数据结构笔记(王道考研) 第二章:线性表

数据结构笔记(王道考研) 第三章:栈和队列

数据结构笔记(王道考研) 第四章:串

数据结构笔记(王道考研) 第五章:树和二叉树

数据结构笔记(王道考研) 第六章:图

数据结构笔记(王道考研) 第七章:查找

数据结构笔记(王道考研) 第八章:排序

其他各科笔记汇总

排序

排序的基本概念

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v1T3FADz-1660482228236)(数据结构.assets/image-20220812184234207.png)]

什么是排序

排序( S o r t Sort Sort),就是重新排列表中的元素,使表中的元素满足按关键字有序的过程。

输入: n n n个记录 R 1 , R 2 , . . , R n R_1,R_2,..,R_n R1?,R2?,..,Rn?,对应的关键字为 k 1 , k 2 , . . . , k n k_1,k_2,...,k_n k1?,k2?,...,kn?

输出:输入序列的一个重排 R 1 ′ , R 2 ′ , . . . , R n ′ R_1^′,R_2^′,...,R_n^′ R1?,R2?,...,Rn?,使得有 k 1 ′ ≤ k 2 ′ ≤ . . . ≤ k n ′ k_1^′\le k_2^′\le...\le k_n^′ k1?k2?...kn?(也可递减)

排序算法的评价指标

1.时间复杂度,空间复杂度

2.稳定性

若待排序表中有两个元素 R i R_i Ri? R j R_j Rj?,其对应的关键字相同即 k e y i = k e y j key_i=key_j keyi?=keyj?,且在排序前 R i R_i Ri? R j R_j Rj?的前面,若使用某一排序算法排序后, R i R_i Ri?仍然在 R j R_j Rj?的前面,则称这个排序算法是稳定的,否则称排序算法是不稳定的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0AoNYbcs-1660482228237)(数据结构.assets/image-20220812184259644.png)]

排序的分类

排序算法可以分为

1.内部排序——数据都在内存中

2.外部排序——数据太多,无法全部放入内存

之所以有这种分类是因为磁盘的容量一般远大于内存,而运算速度又远不如内存。因此排序算法不仅要关注时间和空间复杂度,有时考虑到内存容量的问题还要关注如何使读/写磁盘次数更少

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dAcLGYYl-1660482228238)(数据结构.assets/image-20220812184341662.png)]

插入排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mX5GcFCI-1660482228239)(数据结构.assets/image-20220813100804269.png)]

每次将一个待排序的记录按其关键字大小插入到前面已排好序的子序列中,直到全部记录插入完成。

算法实现

//直接插入排序
void InsertSort(int A[],int n){
    int i,j,temp;
    for(i=1;i<n;i++)                             //将各元素插入已排好序的序列中
        if(A[i]<A[i-1]){                         //若A[i]关键字小于前驱
            temp=A[i];                           //用temp暂存A[i]
            for(j=i-1;j>=0&&A[j]>temp;--j)       //检查所有前面已排好序的元素
                A[j+1]=A[j];                     //所有大于temp的元素都往后挪位
            A[j+1]=temp;                         //复制到插入位置
        }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gc2dFBit-1660482228240)(数据结构.assets/image-20220813101611544.png)]

算法实现(带哨兵)

//直接插入排序(带哨兵)
void InsertSort(int A[],int n){
    int i,j;
    for(i=2;i<=n;i++)                  //依次将A[2]~A[n]插入到前面已排序序列
        if(A[i]<A[i-1]){               //若A[i]关键码小于其前驱,将A[i]插入有序表
            A[0]=A[i];                 //复制为哨兵,A[0]不存放元素
            for(j=i-1;A[0]<A[j];--j)   //从后往前查找待插入位置
                A[j+1]=A[j];           //向后挪位
            A[j+1]=A[0];               //复制到插入位置
        }
}

优点:不用每轮循环都判断 j ≥ 0 j\ge0 j0

算法效率分析

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

只需要定义几个所需空间为常数级的辅助变量(如 i , j , t e m p , a [ 0 ] i,j,temp,a[0] ijtempa[0]),与问题的规模 n n n无关

?

2.时间复杂度:主要来自对比关键字,移动元素,若有 n n n个元素,则需要 n ? 1 n?1 n?1趟处理

下面的分析以带哨兵的版本为基础

?

最好情况:原本就有序, O ( n ) O(n) O(n)

n ? 1 n?1 n?1趟处理,每一趟只需要对比关键字1次,不用移动元素

?

最坏情况:原本为逆序, O ( n 2 ) O(n^2) O(n2)

第一趟:对比关键字2次,移动元素3次

第二趟:对比关键字3次,移动元素4次

i i i趟:对比关键字 i + 1 i+1 i+1次,移动元素 i + 2 i+2 i+2

n ? 1 n?1 n?1趟:对比关键字 n n n次,移动元素 n + 1 n+1 n+1

?

平均时间复杂度 O ( n 2 ) O(n^2) O(n2)

?

3.稳定性:稳定

优化 —— 折半插入排序

思路:先用折半查找找到应该插入的位置,再移动元素

l o w > h i g h low>high low>high时折半查找停止,应将 [ l o w , i ? 1 ] [low,i?1] [low,i?1]内的元素全部右移,并将 A [ 0 ] A[0] A[0]复制到 l o w low low所指位置

如果 l o w > i ? 1 low>i?1 low>i?1,则什么都不做

A [ m i d ] = = A [ 0 ] A[mid]==A[0] A[mid]==A[0]时,为了保证算法的“稳定性”,应继续在 m i d mid mid所指位置右边寻找插入位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GcPPiIvx-1660482228244)(数据结构.assets/image-20220813145928245.png)]

?

//折半插入排序
void InsertSort(int A[],int n){
    int i,j,low,high,mid;
    for(i=2;i<=n;i++){    //依次将A[2]~A[n]插入前面的已排序序列       
        A[0]=A[i];        //将A[i]暂存到A[0]
        low=1;high=i-1;   //设置折半查找的范围
        while(low<=high){ //折半查找(默认递增有序)
            mid=(low+high)/2;           //取中间点
            if(A[mid]>A[0]) high=mid-1; //查找左半子表
            else low=mid+1;             //查找右半子表
        }
        for(j=i-1;j>=high+1;--j)
                A[j+1]=A[j];            //统一后移元素,空出插入位置
        A[high+1]=A[0];   //插入操作
    }
}

比起“直接插入排序”,比较关键字的次数减少了,但是移动元素的次数没变,整体来看时间复杂度依然是 O ( n 2 ) O(n^2) O(n2)

对链表进行插入排序

移动元素的次数变少了,但是关键字对比的次数依然是 O ( n 2 ) O(n^2) O(n2)数量级,整体来看时间复杂度依然是 O ( n 2 ) O(n^2) O(n2)

希尔排序(Shell Sort)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rGfuJhNR-1660482228246)(数据结构.assets/image-20220813155200588.png)]

先追求表中元素部分有序,再逐渐逼近全局有序

先将待排序表分割成若干形如 L [ i , i + d , i + 2 d , . . . , i + k d ] L[i,i+d,i+2d,...,i+kd] L[i,i+d,i+2d,...,i+kd]的 “特殊” 子表,对各个子表分别进行直接插入排序。缩小增量 d d d,重复上述过程,直到 d = 1 d=1 d=1为止

一般第一趟排序时设置增量 d = n / 2 d=n/2 d=n/2,每一趟排序后将增量缩小一半

算法实现

//希尔排序
void ShellSort(int A[],int n){
    int d, i, j;
    //A[0]只是暂存单元,不是哨兵,当j<=0时,插入位置已到
    for(d= n/2; d>=1; d=d/2)   //步长变化
        for(i=d+1; i<=n; ++i)
            if(A[i]<A[i-d]){   //需将A[i]插入有序增量子表
                A[0]=A[i];     //暂存在A[0]
                for(j= i-d; j>0 && A[0]<A[j]; j-=d)
                    A[j+d]=A[j];   //记录后移,查找插入的位置
                A[j+d]=A[0];       //插入
            }//if
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D2PNYHXK-1660482228248)(数据结构.assets/image-20220813160906711-16603781482481.png)]

i + + i++ i++会切换着处理每个子表

算法性能分析

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

?

2.时间复杂度:和增量序列 d 1 , d 2 , d 3 . . . d_1,d_2,d_3... d1?,d2?,d3?...的选择有关,目前无法用数学手段证明确切的时间复杂度。最坏时间复杂度为 O ( n 2 ) O(n^2) O(n2),当n在某个范围内时,可达 O ( n 1.3 ) O(n^{1.3}) O(n1.3)

?

3.稳定性:不稳定

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9I4sNuyN-1660482228250)(数据结构.assets/image-20220813162532981.png)]

4.适用性:仅适用于顺序表,不适用于链表

冒泡排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FHdStOwv-1660482228252)(数据结构.assets/image-20220813162130259.png)]

冒泡排序和快速排序是基于“交换”的排序

基于“交换”的排序:根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置

?

从后往前(或从前往后)两两比较相邻元素的值,若为逆序(即 A [ i ? 1 ] > A [ i A[i?1]>A[i A[i?1]>A[i]),则交换它们,直到序列比较完。称这样过程为“一趟”冒泡排序

第1趟排序使关键字值最小的1个元素“冒”到最前面

前边已经确定最终位置的元素不用再对比

第2趟结束后,最小的2个元素会“冒”到最前面

第3趟结束后,最小的3个元素会“冒”到最前面

若某一趟排序没有发生“交换”,说明此时已经整体有序

算法实现

//交换
void swap(int &a,int&b){
    int temp=a;
    a=b;
    b=temp;
}

//冒泡排序
void BubbleSort(int A[],int n){
    for(int i=0;i<n-1;i++){            
        bool flag=false;               //表示本趟冒泡是否发生交换的标志
        for(int j=n-1;j>i;j--)         //一趟冒泡过程
            if(A[j-1]>A[j]){           //若为逆序
                swap(A[j-1],A[j]);     //交换
                flag=true;
            }
        if(flag==false)
            return;                    //本趟遍历后没有发生交换,说明表已经有序
    }
}

算法性能分析

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

2.时间复杂度:

最好情况(有序)

比较次数 = n ? 1 =n?1 =n?1;交换次数 = 0 =0 =0

最好时间复杂度 = O ( n ) =O(n) =O(n)

?

最坏情况(逆序)

比较次数 = ( n ? 1 ) + ( n ? 2 ) + . . . + 1 = n ( n ? 1 ) 2 = =(n?1)+(n?2)+...+1=n(n?1)2= =(n?1)+(n?2)+...+1=n(n?1)2=交换次数

每次交换都需要移动元素3次

最坏时间复杂度 = O ( n 2 ) =O(n^2) =O(n2)

?

平均时间复杂度 = O ( n 2 ) =O(n^2) =O(n2)

?

3.稳定性:只有 A [ j ? 1 ] > A [ j ] A[j?1]>A[j] A[j?1]>A[j]时才交换,因此算法是稳定的

是否适用于链表?

可从前往后“冒泡”,每一趟将更大的元素“冒’'到链尾

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A9TaFdmM-1660482228253)(数据结构.assets/image-20220814150459215.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z1RW5xsG-1660482228254)(数据结构.assets/image-20220814150523895.png)]

快速排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q7CfBRKp-1660482228255)(file://C:\Users\24190\AppData\Roaming\Typora\typora-user-images\image-20201027144621114.png?lastModify=1660300759)]

算法思想:在待排序表 L [ 1... n ] L[1...n] L[1...n]中任取一个元素 p i v o t pivot pivot作为枢轴(或基准,通常取首元素),通过一趟排序将待排序表划分为独立的两部分 L [ 1... k ? 1 ] L[1...k?1] L[1...k?1] L [ k + 1... n ] L[k+1...n] L[k+1...n],使得 L [ 1.. k ? 1 ] L[1..k?1] L[1..k?1]中的所有元素小于 p i v o t pivot pivot L [ k + 1... n ] L[k+1...n] L[k+1...n]中的所有元素大于等于 p i v o t pivot pivot,则 p i v o t pivot pivot放在了其最终位置 L ( k ) L(k) L(k)上,这个过程称为一次“划分”。然后分别递归地对两个子表重复上述过程,直至每部分内只有一个元素或为空为止,即所有元素放在了其最终位置上

算法实现

//快速排序
void QuickSort(int A[],int low,int high){
    if(low<high){   //递归跳出的条件
        int pivotpos=Partition(A,low,high); //划分
        QuickSort(A,low,pivotpos-1);        //划分左子表
        QuickSort(A,pivotpos+1,high);       //划分右子表
    }
}

//用第一个元素将待排序序列划分为左右两个部分
int Partition(int A[],int low,int high){
    int pivot=A[low];   //第一个元素作为枢轴
    while(low<high){
        while(low<high&&A[high]>=pivot) --high;         
        A[low]=A[high];     //比枢轴小的元素移动到左端
        while(low<high&&A[low]<=pivot)  ++low;         
        A[high]=A[low];     //比枢轴大的元素移动到右端
    }   
    A[low]=pivot;           //枢轴元素存放到最终位置
    return low;             //返回存放枢轴的最终位置
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GkldeGod-1660482228256)(数据结构.assets/image-20220813163957065.png)]

算法效率分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ws18lqgm-1660482228257)(数据结构.assets/image-20220813171114227.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RYzcAXRB-1660482228258)(数据结构.assets/image-20220813171136229.png)]

?

?

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mXspYQld-1660482228259)(数据结构.assets/image-20220813171231162.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2kDqxVSt-1660482228261)(数据结构.assets/image-20220813171343007.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n1X3qIZ4-1660482228262)(数据结构.assets/image-20220813171403294.png)]

?

1.时间复杂度 = O ( n × =O(n\times =O(n×递归层数 ) ) )

最好时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2?n)

最坏时间复杂度: O ( n 2 ) O(n^2) O(n2)

平均时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2?n)

?

2.空间复杂度 = O ( =O( =O(递归深度 ) ) )

最好时间复杂度: O ( l o g 2 n ) O(log_2n) O(log2?n)

最坏时间复杂度: O ( n ) O(n) O(n)

?

若每次选中的“枢轴”将待排序序列划分为均匀的两个部分,则递归深度最小,算法效率最高

若每次选中的“枢轴”将待排序序列划分为很不均匀的两个部分,则会导致递归深度增加,算法效率变低

若初始序列有序或逆序,则快速排序的性能最差(因为每次选择的都是最靠边的元素)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7otFO9pl-1660482228263)(数据结构.assets/image-20220813173441363.png)]

?

快速排序算法优化思路:尽量选择可以把数据中分的枢轴元素

eg:1.选头,中,尾三个位置的元素,取中间值作为枢轴元素;2.随机选一个元素作为枢轴元素

?

快速排序是所有内部排序算法中平均性能最优的排序算法

?

?

3.稳定性:不稳定

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o7w732YZ-1660482228265)(数据结构.assets/image-20220813173612037.png)]

简单选择排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aiWfqOTu-1660482228266)(数据结构.assets/image-20220813212928008.png)]

简单选择排序和堆排序都属于选择排序

选择排序:每一趟在待排序元素中选取关键字最小(或最大)的元素加入有序子序列

?

n n n个元素的简单选择排序需要 n ? 1 n?1 n?1趟处理

最后剩一个不用再处理

算法实现

//交换
void swap(int &a,int&b){
    int temp=a;
    a=b;
    b=temp;
}

//简单选择排序
void SelectSort(int A[],int n){
    for(int i=0;i<n-1;i++){            //一共进行n-1趟
        int min=i;                     //记录最小元素位置
        for(int j=i+1;j<n;j++)         //在A[i...n-1]中选择最小的元素
            if(A[j]<A[min]) min=j;     //更新最小元素位置
        if(min!=i) swap(A[i],A[min]);  //封装的swap()函数共移动元素3次
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-728XLpbS-1660482228268)(数据结构.assets/image-20220813212237461.png)]

算法性能分析

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

?

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

无论有序、逆序、还是乱序,一定需要 n ? 1 n?1 n?1趟处理

总共需要对比关键字 ( n ? 1 ) + ( n ? 2 ) + . . . + 1 = n ( n ? 1 ) 2 (n?1)+(n?2)+...+1=\frac{n(n?1)}{2} (n?1)+(n?2)+...+1=2n(n?1)?

元素交换次数 < n ? 1 <n?1 <n?1

?

3.稳定性:不稳定

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0MgAyy3z-1660482228269)(数据结构.assets/image-20220813212847274.png)]

4.适用性:既可以用于顺序表,也可以用于链表

堆排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vwSjItdw-1660482228270)(数据结构.assets/image-20220813220651316.png)]

堆的定义

n n n个关键字序列 L [ 1.. n ] L[1..n] L[1..n]满足下面某一条性质,则称为堆( H e a p Heap Heap

1.若满足: L ( i ) ≥ L ( 2 i ) L(i)\ge L(2i) L(i)L(2i) L ( i ) ≥ L ( 2 i + 1 ) ( 1 ≤ i ≤ n / 2 ) L(i)\ge L(2i+1)(1\le i\le n/2) L(i)L(2i+1)(1in/2) ——大根堆(大顶堆)

2.若满足: L ( i ) ≤ L ( 2 i ) L(i)\le L(2i) L(i)L(2i) L ( i ) ≤ L ( 2 i + 1 ) ( 1 ≤ i ≤ n / 2 ) L(i)\le L(2i+1)(1 \le i\le n/2) L(i)L(2i+1)(1in/2) ——小根堆(小顶堆)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RtXDhFGC-1660482228272)(数据结构.assets/image-20201027152332474.png)]

回顾之前二叉树顺序存储的知识,大根堆在逻辑视角上可以看成所有子树根 ≥ \ge 左、右的完全二叉树。堆排序就建立在堆顶元素关键字最大上

相应的小根堆也可以看成根 ≤ \le 左,右的完全二叉树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rA0zDyC6-1660482228273)(数据结构.assets/image-20220813221003077.png)]

建立大根堆

大根堆:根 ≥ \ge 左,右

思路:把所有非终端结点都检查一遍,是否满足大根堆的要求,如果不满足,则进行调整

检查当前结点是否满足根 ≥ \ge 左,右。若不满足,将当前结点与更大的一个孩子互换

若元素互换破坏了下一级的堆,则采用相同的方法继续往下调整(小元素不断“下坠”)

在顺序存储的完全二叉树中,非终端结点编号 i ≤ [ n / 2 ] i\le[n/2] i[n/2]

i i i的左孩子 —— 2 i 2i 2i

i i i的右孩子 —— 2 i + 1 2i+1 2i+1

i i i的父节点 —— [ i / 2 ] [i/2] [i/2]

?

//建立大根堆
void BuildMaxHeap(int A[],int len){
    for(int i=len/2;i>0;i--){      //从后往前调整所有非终端结点
        HeadAdjust(A,i,len);
    }
}

//将以 k 为根的子树调整为大根堆
void HeadAdjust(int A[],int k,int len){
    A[0]=A[k];                     //A[0]暂存子树的根结点
    for(int i=2*k;i<=len;i*=2){    //沿key较大的子结点向下筛选
        if(i<len&&A[i]<A[i+1])
            i++;                   //取key较大的子结点的下标
        if(A[0]>=A[i]) break;      //筛选结束
        else{
            A[k]=A[i];             //将A[i]调整到双亲结点上
            k=i;                   //修改k值,以便继续向下筛选
        }
    }
    A[k]=A[0]                      //将被筛选结点的值放入最终位置
}

基于大根堆进行排序

堆排序:每一趟将堆顶元素加入有序子序列(与待排序序列中的最后一个元素交换)

并将待排序元素序列再次调整为大根堆(小元素不断“下坠”)

注意:基于“大根堆”的堆排序得到“递增序列”,而基于“小根堆”的堆排序得到“递减序列”

?

代码如下

//建立大根堆
void BuildMaxHeap(int A[],int len)
    
//将以k为根的子树调整为大根堆
void HeadAdjust(int A[],int k,int len)
    
//堆排序的完整逻辑
void HeapSort(int A[],int len){
    BuildMaxHeap(A,len);         //初始建堆
    for(int i=len;i>1;i--){      //n-1趟的交换和建堆过程     
        swap(A[i],A[1]);         //堆顶元素和堆底元素交换
        HeadAdjust(A,1,i-1);     //把剩余的待排序元素整理成堆
    }
}

算法效率分析

堆排序的空间复杂度 = O ( 1 ) =O(1) =O(1)

?

?

下方有两个孩子,则“下坠”一层,需对比关键字2次。下方只有一个孩子,则下坠一层,只需对比关键字1次。故一个结点,每“下坠”一层,最多只需对比关键字2次

若树高为 h h h,某结点在第 i i i层,则将这个结点向下调整最多只需要“下坠” h ? i h-i h?i层,关键字对比次数不超过 2 ( h ? i ) 2(h-i) 2(h?i) n n n个结点的完全二叉树高 h = [ l o g 2 n ] + 1 h=[log_2n]+1 h=[log2?n]+1

?

i i i层最多有 2 i ? 1 2^{i-1} 2i?1个结点,而只有第 1 ~ ( h ? 1 ) 1\sim (h-1) 1(h?1)层的结点才有可能需要“下坠”调整

将整棵树调整为大根堆,关键字对比次数不超过 ∑ i = h ? 1 1 2 i ? 1 2 ( h ? i ) = ∑ i = h ? 1 1 2 i ( h ? i ) = ∑ j = 1 h ? 1 2 h ? j j ≤ 2 n ∑ j = 1 h ? 1 j 2 j ≤ 4 n \sum_{i=h-1}^1 2^{i-1}2(h-i)=\sum_{i=h-1}^12^i(h-i)=\sum_{j=1}^{h-1}2^{h-j}j\le 2n\sum_{j=1}^{h-1}\frac{j}{2^j}\le 4n i=h?11?2i?12(h?i)=i=h?11?2i(h?i)=j=1h?1?2h?jj2nj=1h?1?2jj?4n

∑ j = 1 h ? 1 j 2 j \sum_{j=1}^{h-1}\frac{j}{2^j} j=1h?1?2jj?差比数列求和(错位相减法),求和结果小于2

?

建堆的过程,关键字对比次数不超过 4 n 4n 4n,建堆时间复杂度 = O ( n ) =O(n) =O(n)

?

?

初始建堆时间复杂度为 O ( n ) O(n) O(n)

每趟交换和建堆过程,根节点最多“下坠” h ? 1 h-1 h?1层,每下坠一层最多只需对比关键字2次,因此每一趟排序时间复杂度不超过 O ( h ) = O ( l o g 2 n ) O(h)=O(log_2n) O(h)=O(log2?n)。共 n ? 1 n-1 n?1趟,总的时间复杂度 = O ( l o g 2 n ) =O(log_2n) =O(log2?n)

堆排序的时间复杂度 = O ( n ) + O ( n l o g 2 n ) = O ( n l o g 2 n ) =O(n)+O(nlog_2n)=O(nlog_2n) =O(n)+O(nlog2?n)=O(nlog2?n)

?

?

堆排序是不稳定的

堆的插入删除

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IENdUk1E-1660482228274)(数据结构.assets/image-20220814003026071.png)]

在堆中插入新元素

对于小根堆,新元素放到表尾,与父节点对比,若新元素比父节点更小,则将二者互换。新元素就这样一路“上升”,直到无法继续上升为止

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S5p8LXyK-1660482228275)(数据结构.assets/image-20220814003204318.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-shrDx231-1660482228276)(数据结构.assets/image-20220814003417992.png)]

在堆中删除元素

被删除的元素用堆顶元素替代,然后让该元素不断“下坠”,直到无法下坠为止

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0lQLNxhS-1660482228277)(数据结构.assets/image-20220814003629249.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uTM2Mseq-1660482228277)(数据结构.assets/image-20220814003747931.png)]

归并排序(Merge Sort)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sLyCAfL0-1660482228278)(数据结构.assets/image-20220814084055693.png)]

?

Merge(归并/合并)

归并:把两个或多个已经有序的序列合并成一个

“2路”归并 —— 每选出一个小元素就需对比关键字1次。“4路”归并 —— 每选出一个小元素就需对比关键字3次。故 m m m路归并,每选出一个元素需要对比关键字 m ? 1 m-1 m?1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3XNl8sXA-1660482228279)(数据结构.assets/image-20220814082752191.png)]

归并排序(手算模拟)

在内部排序中一般采用2路归并

核心操作:把数组内的两个有序序列归并为一个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SPBN12gl-1660482228280)(数据结构.assets/image-20220814083321783.png)]

代码实现

int *B=(int *)malloc(n*sizeof(int)); //辅助数组B

//A[low...mid]和A[mid+1...high]各自有序,将两个部分归并
void Merge(int A[],int low,int mid,int high){
    int i,j,k;
    for(k=low,k<=high;k++)
        B[k]=A[k];        //把A中所有元素复制到B中
    for(i=low,j=mid+1,k=i;i<=mid&&j<=high,k++){
        if(B[i]<=B[j])    
            A[k]=B[i++];  //将较小值复制到A中
        else
            A[k]=B[j++];
    }//for
    while(i<=mid)   A[k++]=B[i++];  
    while(j<=high)  A[k++]=B[j++];
}

void MergeSort(int A[],int low,int high){
    if(low<high){
        int mid=(low+high)/2;     //从中间划分
        MergeSort(A,low,mid);     //对左半部分归并排序
        MergeSort(A,mid+1,high); //对右半部分归并排序
        Merge(A,low,mid,high);    //归并
    }//if
}

算法效率分析

2路归并的“归并树”——形态上就是一棵倒立的二叉树

二叉树的第 h h h层最多有 2 h ? 1 2h?1 2h?1个结点

若树高为h,则应满足 n ≤ 2 h ? 1 n\le2h?1 n2h?1

h ? 1 = [ l o g 2 n ] h?1=[log2n] h?1=[log2n]

结论: n n n个元素进行2路归并排序,归并趟数 = [ l o g 2 n ] =[log_2n] =[log2?n]

每趟归并时间复杂度为 O ( n ) O(n) O(n),则算法时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2?n)

?

空间复杂度 = O ( n ) =O(n) =O(n),来自于辅助数组B

?

两个元素相等时,优先使用靠前的那个。归并排序是稳定的

基数排序(Radix Sort)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yf2DbKYD-1660482228281)(数据结构.assets/image-20220814124013057.png)]

基数排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cye2nMJL-1660482228282)(数据结构.assets/image-20220814142021360.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lvIoPlNv-1660482228283)(数据结构.assets/image-20220814142043077.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ziq9mqg5-1660482228284)(数据结构.assets/image-20220814142105288.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9RgjVZEU-1660482228286)(数据结构.assets/image-20220814142222419.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A4o0H1el-1660482228286)(数据结构.assets/image-20220814142254146.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qdgTb2l0-1660482228287)(数据结构.assets/image-20220814142612862.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3xfJ9u6T-1660482228288)(数据结构.assets/image-20220814142727372.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9glzqXhl-1660482228290)(数据结构.assets/image-20220814142748479.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zYqK6fOP-1660482228291)(数据结构.assets/image-20220814142828708.png)]

?

?

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2c9eQGUd-1660482228292)(数据结构.assets/image-20220814142925631.png)]

假设长度为 n n n的线性表中每个结点 a j a_j aj?的关键字由 d d d元组( k j d ? 1 , k j d ? 2 , . . . , k j 1 , k j 0 k_j^{d?1},k_j^{d?2},...,k_j^1,k_j^0 kjd?1?,kjd?2?,...,kj1?,kj0?)组成。其中, 0 ≤ k j i ≤ r ? 1 ( 0 ≤ j ≤ n , 0 ≤ i ≤ d ? 1 ) 0\le k_j^i\le r?1(0\le j\le n,0\le i\le d?1) 0kji?r?1(0jn,0id?1) r r r称为“基数”

k j d ? 1 k_j^{d?1} kjd?1?为最高位关键字(最主位关键字), k j 0 k_j^0 kj0?为最低位关键字(最次位关键字)

?

基数排序得到递减序列的过程如下,

初始化:设置 r r r个空队列, Q r ? 1 , Q r ? 2 , . . . , Q 0 Q_{r?1},Q_{r?2},...,Q_0 Qr?1?,Qr?2?,...,Q0?

按照各个关键字位权重递增的次序(个、十、百),对 d d d个关键字位分别做“分配”和“收集”

分配:顺序扫描各个元素,若当前处理的关键字位 = x =x =x,则将元素插入 Q x Q_x Qx?队尾

收集:把 Q r ? 1 , Q r ? 2 , . . . , Q 0 Q_{r?1},Q_{r?2},...,Q_0 Qr?1?,Qr?2?,...,Q0?各个队列中的结点依次出队并链接

可见基数排序不是基于“比较”的排序算法

?

基数排序得到递增序列的过程如下,

初始化:设置 r r r个空队列, Q 0 , Q 1 , . . . , Q r ? 1 Q_{0},Q_{1},...,Q_{r-1} Q0?,Q1?,...,Qr?1?

按照各个关键字位权重递增的次序(个、十、百),对 d d d个关键字位分别做“分配”和“收集”

分配:顺序扫描各个元素,若当前处理的关键字位 = x =x =x,则将元素插入 Q x Q_x Qx?队尾

收集:把 Q 0 , Q 1 , . . . , Q r ? 1 Q_{0},Q_{1},...,Q_{r-1} Q0?,Q1?,...,Qr?1?各个队列中的结点依次出队并链接

算法效率分析

基数排序通常基于链式存储实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78vCTI8J-1660482228293)(数据结构.assets/image-20220814144707782.png)]

typedef struct LinkNode{
    ElemType data;
    struct LinkNode *next;
}LinkNode, *LinkList;

typedef struct{              //链式队列
    LinkNode *front,*rear;   //队列的对头和队尾指针
}LinkQueue;

一般不太考察基数排序的代码实现

?

1.空间复杂度

需要 r r r个辅助队列,空间复杂度 O ( r ) O(r) O(r)

?

2.时间复杂度:

把关键字拆为 d d d个部分,每个部分可能取得 r r r个值

一趟分配 O ( n ) O(n) O(n),一趟收集 O ( r ) O(r) O(r),总共 d d d趟分配、收集,总的时间复杂度 = O ( d ( n + r ) ) =O(d(n+r)) =O(d(n+r))

收集一个队列只需 O ( 1 ) O(1) O(1)时间


p->next = Q[6].front;
Q[6].front = NULL;
Q[6].rear = NULL;

?

3.稳定性:稳定的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iuTp0eAg-1660482228294)(数据结构.assets/image-20220814145751154.png)]

基数排序的应用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QuhnbCje-1660482228295)(数据结构.assets/image-20220814145826301.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oErsfO61-1660482228296)(数据结构.assets/image-20220814145926531.png)]

外部排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sPsXTJgK-1660482228297)(数据结构.assets/image-20220814151242487.png)]

内存、外存之间的数据交换

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rc9g9QWd-1660482228298)(数据结构.assets/image-20220814174848171.png)]

外部排序原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X8aV9qWy-1660482228299)(数据结构.assets/image-20220814174931693.png)]

构建初始”归并段“

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Brpl4tDP-1660482228301)(数据结构.assets/image-20220814175455812.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2BJQRjYJ-1660482228302)(数据结构.assets/image-20220814175241632.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hsfL6GHY-1660482228303)(数据结构.assets/image-20220814175537793.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PHiip9pu-1660482228304)(数据结构.assets/image-20220814175321927.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-stYtJE72-1660482228306)(数据结构.assets/image-20220814175343161.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sGY5OcEI-1660482228307)(数据结构.assets/image-20220814175617344.png)]

归并过程

第一趟归并:把8个有序子序列(初始归并段)两两归并

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HUJJX49E-1660482228309)(数据结构.assets/image-20220814175742104.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uwRxcIYg-1660482228310)(数据结构.assets/image-20220814175807699.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eWNY7ntg-1660482228311)(数据结构.assets/image-20220814175828558.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1yaWwps2-1660482228312)(数据结构.assets/image-20220814175917753.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a5ymBTMF-1660482228313)(数据结构.assets/image-20220814175948319.png)]

?

第二趟归并:把4个有序子序列(归并段)两两归并

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H3ItljtD-1660482228314)(数据结构.assets/image-20220814180226197.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mt1HPzi7-1660482228316)(数据结构.assets/image-20220814180247686.png)]

归并之后得到的更长子序列放在磁盘的另一片空间当中,以前的这两片空间会归还给系统,这里只是为了美观

?

第三趟归并:将2个有序子序列(归并段)归并

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7IKx8AGI-1660482228317)(数据结构.assets/image-20220814180426452.png)]

经过3趟归并,整体有序

时间开销分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g4xZKnWB-1660482228318)(数据结构.assets/image-20220814180526256.png)]

优化

1.多路归并

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ldrEZLW-1660482228319)(数据结构.assets/image-20220814180624290.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-02Gt8LLk-1660482228320)(数据结构.assets/image-20220814180644753.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LtLmOfjV-1660482228321)(数据结构.assets/image-20220814180759470.png)]

[ l o g k r ] [log_kr] [logk?r]向上取整

2.减少初始归并段数量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lm1NcHCT-1660482228322)(数据结构.assets/image-20220814180950636.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CDM8fFW0-1660482228324)(数据结构.assets/image-20220814181132530.png)]
在这里插入图片描述

什么是多路平衡归并?

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

[ m / k ] [m/k] [m/k]向上取整

败者树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pZp2WmB8-1660482228328)(数据结构.assets/image-20220814181843715.png)]

败者树的构造

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R3K28upb-1660482228330)(数据结构.assets/image-20220814182559297.png)]

败者树的使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zL8fSYO3-1660482228331)(数据结构.assets/image-20220814182737620.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vob04kEE-1660482228332)(数据结构.assets/image-20220814182850549.png)]

败者树在多路平衡归并中的应用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qgEedXa4-1660482228333)(数据结构.assets/image-20220814183005448.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XliU9bh7-1660482228335)(数据结构.assets/image-20220814183144886.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hWhhu7mX-1660482228336)(数据结构.assets/image-20220814183600761.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ojJunQRb-1660482228337)(数据结构.assets/image-20220814183710145.png)]

[ l o g 2 k ] [log_2k] [log2?k]向上取整

败者树的实现思路

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RxTmMDtB-1660482228339)(数据结构.assets/image-20220814183934175.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xnBIBR3k-1660482228340)(数据结构.assets/image-20220814184038872.png)]

置换-选择排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SLS6TtOV-1660482228341)(数据结构.assets/image-20220814184516224.png)]

?

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DcBmBbQi-1660482228342)(数据结构.assets/image-20220814185220408.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V2gkxkb4-1660482228343)(数据结构.assets/image-20220814184926481.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JzIaC6aD-1660482228344)(数据结构.assets/image-20220814184948845.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d8VWrnDT-1660482228346)(数据结构.assets/image-20220814185031668.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iPEn6fNa-1660482228347)(数据结构.assets/image-20220814185054187.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rihu9QGu-1660482228348)(数据结构.assets/image-20220814185124010.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wgQzytxE-1660482228350)(数据结构.assets/image-20220814185240088.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fedcsvA0-1660482228351)(数据结构.assets/image-20220814185306958.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sEc0q0wR-1660482228352)(数据结构.assets/image-20220814185344252.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j94JZPaM-1660482228353)(数据结构.assets/image-20220814185400954.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4crfchxv-1660482228354)(数据结构.assets/image-20220814185423857.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mnMnS20h-1660482228356)(数据结构.assets/image-20220814185501049.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t7mn84wk-1660482228357)(数据结构.assets/image-20220814185521290.png)]

上面的演示每次读写一个记录,忽略了输出缓冲区和输入缓冲区

最佳归并树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GAPb3XTB-1660482228358)(数据结构.assets/image-20220814190427570.png)]

归并树的性质

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8udZre5G-1660482228359)(数据结构.assets/image-20220814185643385.png)]

构造2路归并的最佳归并树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e1XvNmls-1660482228360)(数据结构.assets/image-20220814185851874.png)]

多路归并的情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qAnYGoJ8-1660482228361)(数据结构.assets/image-20220814190236066.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-coZtSe5y-1660482228362)(数据结构.assets/image-20220814190016155.png)]

?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-44VLtnzC-1660482228363)(数据结构.assets/image-20220814190320347.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gguu4h1O-1660482228364)(数据结构.assets/image-20220814190403611.png)]

添加虚段的数量

在这里插入图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 19:31:09  更:2022-08-19 19:32:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/6 23:04:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码