热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

一线互联网大厂面试必备排序算法(C/C++版本)

0常见排序算法总结基础排序算法:冒泡排序、选择排序、插入排序、归并排序、希尔排序、快速排序、堆排序建议看不懂原理说明或图示时请看代码。1.冒泡排序1.1基本思想冒

0 常见排序算法总结
基础排序算法: 冒泡排序、选择排序、插入排序、归并排序、希尔排序、快速排序、堆排序在这里插入图片描述
建议看不懂原理说明或图示时请看代码。

1. 冒泡排序

1.1 基本思想
冒泡排序是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
算法描述:

  1. 比较相邻两个数据如果。第一个比第二个大,就交换两个数
  2. 对每一个相邻的数做同样1的工作,这样从开始一队到结尾一队在最后的数就是最大的数。
  3. 针对所有元素上面的操作,除了最后一个。
  4. 重复1~3步骤,知道顺序完成。

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

1.3 代码

/*1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。2. 对第0个到第n-1个数据做同样的工作。这时,最大的数就“浮”到了数组最后的位置上。3. 针对所有的元素重复以上的步骤,除了最后已经选出的元素(有序)。4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较.
*/

// 稳定排序,平均 O(n**2),最好 O(n), 最差 O(n**2),辅助空间 O(1)
void BubbleSort(vector<int> &nums)
{int n &#61; nums.size();if (n&#61;&#61;0) return;for (int i&#61;0;i<n;i&#43;&#43;){for (int j&#61;0;j<n-1-i;j&#43;&#43;){if (nums[j] > nums[j&#43;1]){// swap(nums[j], nums[j&#43;1]);int temp &#61; nums[j];nums[j] &#61; nums[j&#43;1];nums[j&#43;1] &#61; temp;}}}
}

需要C/C&#43;&#43; Linux服务器架构师学习资料加qun&#xff08;812855908&#xff09;获取&#xff08;资料包括C/C&#43;&#43;&#xff0c;Linux&#xff0c;golang技术&#xff0c;Nginx&#xff0c;ZeroMQ&#xff0c;MySQL&#xff0c;Redis&#xff0c;fastdfs&#xff0c;MongoDB&#xff0c;ZK&#xff0c;流媒体&#xff0c;CDN&#xff0c;P2P&#xff0c;K8S&#xff0c;Docker&#xff0c;TCP/IP&#xff0c;协程&#xff0c;DPDK&#xff0c;ffmpeg等&#xff09;&#xff0c;免费分享在这里插入图片描述

2. 选择排序

2.1 基本思想
选择排序&#xff08;Select Sort&#xff09; 是直观的排序&#xff0c;通过确定一个 Key 最大或最小值&#xff0c;再从带排序的的数中找出最大或最小的交换到对应位置。再选择次之。双重循环时间复杂度为 O(n^2)
算法描述&#xff1a;

  1. 在一个长度为 N 的无序数组中&#xff0c;第一次遍历 n-1 个数找到最小的和第一个数交换。
  2. 第二次从下一个数开始遍历 n-2 个数&#xff0c;找到最小的数和第二个数交换。
  3. 重复以上操作直到第 n-1 次遍历最小的数和第 n-1 个数交换&#xff0c;排序完成。

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

2.3 代码

/*1. 在未排序序列中找到最小&#xff08;大&#xff09;元素&#xff0c;存放到排序序列的起始位置。2. 再从剩余未排序元素中继续寻找最小&#xff08;大&#xff09;元素&#xff0c;然后放到已排序序列的末尾。3. 以此类推&#xff0c;直到所有元素均排序完毕。
*/

// 不稳定排序&#xff0c;平均 O(n**2)&#xff0c;最好 O(n**2), 最差 O(n**2),辅助空间 O(1)
void SelectSort(vector<int> &nums)
{int n &#61; nums.size();if (n&#61;&#61;0) return;for (int i&#61;0;i<n-1;i&#43;&#43;){int idx &#61; i; //每一趟循环比较时&#xff0c;idx用于存放较小元素的数组下标&#xff0c;这样当前批次比较完毕最终存放的就是此趟内最小的元素的下标&#xff0c;避免每次遇到较小元素都要进行交换。for (int j&#61;i&#43;1;j<n;j&#43;&#43;){if (nums[idx] > nums[j]);{idx &#61; j;}}if (idx !&#61;i){int temp &#61; nums[idx];nums[idx] &#61; nums[i];nums[i] &#61; temp;}}
}

3. 插入排序&#xff08;重要&#xff09;

3.1 基本思想
将一个数插入一个已经排好序的数据中。

  1. 第一次循环时&#xff0c;从第2个数开始处理。我们将第1个数作为已经排好序的数据&#xff1a;当第2个数 > 第1个数时&#xff0c;将第2个数放在第1个数后面一个位置&#xff1b;否则&#xff0c;将第2个数放在第1个数前面。此时&#xff0c;前两个数形成了一个有序的数据。
  2. 第二次循环时&#xff0c;我们处理第3个数。此时&#xff0c;前两个数形成了一个有序的数据&#xff1a;首先比较第3个数和第2个数&#xff0c;当第3个数 > 第2个数时&#xff0c;将第3个数放在第2个数后面一个位置并结束此次循环&#xff1b;否则&#xff0c;再和第1个数比较。如果第3个数 > 第1个数&#xff0c;则将第3个数插入第1个数和第2个数中间&#xff1b;否则&#xff0c;第3个数 <第1个数&#xff0c;则将第3个数放在第1个数前面。此时&#xff0c;前三个数形成了一个有序的数据。
  3. 后续的数据同理处理&#xff0c;直至结束。

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

3.3 代码

/*直接插入排序基本思想是每一步将一个待排序的记录&#xff0c;插入到前面已经排好序的有序序列中去&#xff0c;直到插完所有元素为止。1. 从第一个元素开始&#xff0c;该元素可以认为已经被排序2. 取出下一个元素&#xff0c;在已经排序的元素序列中从后向前扫描3. 如果被扫描的元素&#xff08;已排序&#xff09;大于新元素&#xff0c;将该元素后移一位4. 重复步骤3&#xff0c;直到找到已排序的元素小于或者等于新元素的位置5. 将新元素插入到该位置后6. 重复步骤2~5
*/

// 稳定排序&#xff0c;平均 O(n**2)&#xff0c;最好 O(n), 最差 O(n**2),辅助空间 O(1)
void InsertSort(vector<int> &nums)
{int n &#61; nums.size();if (n&#61;&#61;0) return;// 从下标为1的元素开始选择合适的位置插入&#xff0c;因为下标为0的只有一个元素&#xff0c;默认是有序的for (int i&#61;1;i<n;i&#43;&#43;){// 记录要插入的数据int temp &#61; nums[i];int j &#61; i- 1;//与已排序的数逐一比较&#xff0c;大于temp时&#xff0c;该数移后while (j>&#61;0) && (temp < nums[j]){nums[j&#43;1] &#61; nums[j];j--;}nums[j&#43;1] &#61; temp;}
}

4. 归并排序&#xff08;重要&#xff09;

4.1 基本思想
归并排序的主要思想是分治法。主要过程是&#xff1a;

  1. 将n个元素从中间切开&#xff0c;分成两部分。&#xff08;左边可能比右边多1个数&#xff09;
  2. 将步骤1分成的两部分&#xff0c;再分别进行递归分解。直到所有部分的元素个数都为1。
  3. 从最底层开始逐步合并两个排好序的数列。

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

4.3 代码

/*将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列有序&#xff0c;再使子序列段间有序。若将两个有序表合并成一个有序表&#xff0c;称为二路归并。归并排序是一种稳定的排序方法。1、确定数组的大小&#xff0c;以及输入数组中的元素值&#xff1b;
2、将输入的数组进行分组归并&#xff1b;
3、将整个数组分成左右两个数组&#xff0c;左右两个数组再向下分&#xff0c;直至子数组的元素少于2个时&#xff0c;子数组将停止分割&#xff1b;
4、当左右子数组不能再分割&#xff0c;也是都是一个元素时&#xff0c;比较他们的大小&#xff0c;进行排序合并&#xff1b;
5、再排序合并上一级子数组为两个元素的数组&#xff0c;接着再排序合并上一级子数组为四个元素的数组&#xff1b;直至到排序合并刚开始的两个子数组&#xff0c;最后成为拍好序的数组&#xff1b;
*/

// 稳定排序&#xff0c;平均 O(nlogn)&#xff0c;最好 O(nlogn), 最差 O(nlogn),辅助空间 O(n)
void merge(int array[],int first,int last)
{int temp[last&#43;1];int mid&#61;(first&#43;last)/2;int i&#61;0; //临时数组指针int l&#61;first;//左序列指针int r&#61;mid&#43;1;//右序列指针while(l<&#61;mid&&r<&#61;last)//sort the ele of the left array and the right array{if(array[l]<array[r])temp[i&#43;&#43;]&#61;array[l&#43;&#43;];elsetemp[i&#43;&#43;]&#61;array[r&#43;&#43;];}while(l<&#61;mid) //将左边剩余元素填充进temp中{temp[i&#43;&#43;]&#61;array[l&#43;&#43;];}while(r<&#61;last) //将右序列剩余元素填充进temp中{temp[i&#43;&#43;]&#61;array[r&#43;&#43;];}i&#61;0;//将temp中的元素全部拷贝到原数组中while(first<&#61;last){array[first&#43;&#43;]&#61;temp[i&#43;&#43;];}
}
void mergesort(int data[],int first,int last)
{if(first<last){int mid&#61;(first&#43;last)/2;mergesort(data,first,mid); //左边归并排序&#xff0c;使得左子序列有序mergesort(data,mid&#43;1,last); //右边归并排序&#xff0c;使得右子序列有序merge(data,first,last); //将两个有序子数组合并操作}
}

5. 希尔排序

5.1 基本思想
希尔排序&#xff0c;也被称为递减增量排序&#xff0c;是简单插入排序的一种改进版本。
• 在插入排序中&#xff0c;如果待排序列中的某个元素&#xff0c;距离有序数列中待插入位置非常远&#xff0c;就需要比较很多次才可以到达插入位置&#xff0c;这是因为待插入元素局部非常无序&#xff0c;比如说[2, 3, 4, 5, 6, 7, 8, 1, …]&#xff0c;我们要插入1&#xff0c;就必须将1和前面的2-8每个值都比较一下&#xff0c;就是因为1附近非常无序&#xff0c;想象一下&#xff0c;如果待插入元素附近比较有序&#xff0c;那么在进行插入排序的时候就只需要比较非常少的几次就可以插入到正确位置。
• 希尔排序就是先把整个序列排得相对比较有序&#xff0c;再进行插入排序的时候&#xff0c;需要比较的次数就会变得很少。
• 插入排序的增量(间隔)为1&#xff0c;希尔排序相当于将这个间隔从最大为数组长度的一半一直降到1&#xff0c;这一点在程序中体现的很清楚。当间隔很大时&#xff0c;比较的次数也会很少&#xff0c;在进行了几次大间隔的插入排序后&#xff0c;序列已经部分有序&#xff0c;这样再进行小间隔的插入排序也自然会比较很少的次数。
• 希尔排序就是将处在相同间隔的元素提取出来单独进行插入排序&#xff0c;然后逐步将间隔减小到1的过程。

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

5.3 代码

/*数组列在一个表中并对列分别进行插入排序&#xff0c;重复这过程&#xff0c;不过每次用更长的列&#xff08;步长更长了&#xff0c;列数更少了&#xff09;来进行。
*/

// 不稳定排序&#xff0c;平均 O(nlogn)-O(n^2)&#xff0c;最好 O(nlogn), 最差 O(n**2),辅助空间 O(1)
void ShellSort(int a[],size_t n)
{int i,j,k,group;for (group &#61; n/2; group > 0; group /&#61; 2)//增量序列为n/2,n/4....直到1{for (i &#61; 0; i < group; &#43;&#43;i){for (j &#61; i&#43;group; j < n; j &#43;&#61; group){//对每个分组进行插入排序if (a[j - group] > a[j]){int temp &#61; a[j];k &#61; j - group;while (k>&#61;0 && a[k]>temp){a[k&#43;group] &#61; a[k];k -&#61; group;}a[k] &#61; temp;}}}}
}

在这里插入图片描述

6. 快速排序&#xff08;重要&#xff09;

6.1 基本思想
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分&#xff0c;其中一部分的所有数据都比另外一部分的所有数据都要小&#xff0c;然后再按此方法对这两部分数据分别进行快速排序&#xff0c;整个排序过程可以递归进行&#xff0c;以此达到整个数据变成有序序列。
主要过程&#xff1a;

  1. 在待排序的元素任取一个元素作为基准(通常选第一个元素&#xff0c;称为基准元素&#xff09;
  2. 将待排序的元素进行分块&#xff0c;比基准元素大的元素移动到基准元素的右侧&#xff0c;比基准元素小的移动到作左侧&#xff0c;从而一趟排序过程&#xff0c;就可以锁定基准元素的最终位置
  3. 对左右两个分块重复以上步骤直到所有元素都是有序的&#xff08;递归过程&#xff09;

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

6.3 代码

/*1. 从数列中挑出一个元素作为基准数。2. 重新排序数列&#xff0c;将比基准数大的放到右边&#xff0c;小于或等于它的数都放到左边。3. 再对左右区间递归执行第二步&#xff0c;直至各区间只有一个数。
*/

// 不稳定排序&#xff0c;平均 O(nlogn)&#xff0c;最好 O(nlogn), 最差 O(n**2),辅助空间 O(logn)
int Paritition (int A[], int low, int high)
{int pivot &#61; A[low];while (low < high) {while (low < high && A[high] >&#61; pivot) {--high;}A[low] &#61; A[high];while (low < high && A[low] <&#61; pivot) {&#43;&#43;low;}A[high] &#61; A[low];}A[low] &#61; pivot;return low;
}
void QuickSort(int A[], int low, int high) //快排母函数
{if (low < high) {int pivot &#61; Paritition1(A, low, high);QuickSort(A, low, pivot - 1);QuickSort(A, pivot &#43; 1, high);}
}

精简版

void QuickSort(vector<int> &nums, int low, int high)
{if(low < high){int l &#61; low, r &#61; high, pivot &#61; nums[low];while(l<r){while(l<r && nums[r] >&#61;pivot) // 从右向左找第一个小于基准的数{r--;}nums[l] &#61; nums[r];while(l<r && nums[l] < pivot) // 从左向右找第一个大于等于基准的数{l&#43;&#43;;}nums[r] &#61; nums[l];}nums[l] &#61; pivot;quick_sort(nums, low, l-1);quick_sort(nums, l&#43;1, high);}
}

7. 堆排序&#xff08;重要&#xff09;

7.1 基本思想
堆排序(Heapsort)是指利用堆积树&#xff08;堆&#xff09;这种数据结构所设计的一种排序算法&#xff0c;它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆&#xff0c;是完全二叉树。
• 完全二叉树&#xff1a;除了最后一层之外的其他每一层都被完全填充&#xff0c;每一层从左到右的填充数据&#xff0c;不能空缺
• 大根堆&#xff1a;任意一个节点的值均大于等于它的左右孩子的值&#xff0c;位于堆顶的节点值最大
• 小根堆&#xff1a;任意一个节点的值均小于等于它的左右孩子的值&#xff0c;位于堆顶的节点值最小在这里插入图片描述

堆排序的基本思想是&#xff1a;将待排序序列构造成一个大顶堆&#xff0c;此时&#xff0c;整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换&#xff0c;此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆&#xff0c;这样会得到n个元素的次小值。如此反复执行&#xff0c;便能得到一个有序序列了

  1. 将无需序列构建成一个堆&#xff0c;根据升序降序需求选择大顶堆或小顶堆;
  2. 将堆顶元素与末尾元素交换&#xff0c;将最大元素"沉"到数组末端;
  3. 重新调整结构&#xff0c;使其满足堆定义&#xff0c;然后继续交换堆顶元素与当前末尾元素&#xff0c;反复执行调整&#43;交换步骤&#xff0c;直到整个序列有序。

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

7.3 代码

/*
堆排序的基本思想是&#xff1a;将待排序序列构造成一个大顶堆&#xff0c;此时&#xff0c;整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换&#xff0c;此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆&#xff0c;这样会得到n个元素的次小值。如此反复执行&#xff0c;便能得到一个有序序列了
1.将无需序列构建成一个堆&#xff0c;根据升序降序需求选择大顶堆或小顶堆;
2.将堆顶元素与末尾元素交换&#xff0c;将最大元素"沉"到数组末端;
3.重新调整结构&#xff0c;使其满足堆定义&#xff0c;然后继续交换堆顶元素与当前末尾元素&#xff0c;反复执行调整&#43;交换步骤&#xff0c;直到整个序列有序。
*/

// 不稳定排序&#xff0c;平均 O(nlogn)&#xff0c;最好 O(nlogn), 最差 O(n**2),辅助空间 O(1)
void adjustHeap(int nums[],int i,int length)
{int temp &#61; arr[i];//先取出当前元素ifor(int k&#61;i*2&#43;1;k<length;k&#61;k*2&#43;1) //从i结点的左子结点开始&#xff0c;也就是2i&#43;1处开始{if(k&#43;1<length && arr[k]<arr[k&#43;1]) //如果左子结点小于右子结点&#xff0c;k指向右子结点{k&#43;&#43;;}if(arr[k] >temp) //如果子节点大于父节点&#xff0c;将子节点值赋给父节点&#xff08;不用进行交换&#xff09;{ arr[i] &#61; arr[k];i &#61; k;}else{break;}}arr[i] &#61; temp; //将temp值放到最终的位置
}
void HeapSort(int nums[],int len)
{//1.构建大顶堆for(int i&#61;len/2-1;i>&#61;0;i--){//从第一个非叶子结点从下至上&#xff0c;从右至左调整结构adjustHeap(nums,i,len);}//2.调整堆结构&#43;交换堆顶元素与末尾元素for(int j&#61;len-1;j>0;j--){swap(nums[0],nums[j]);//将堆顶元素(最大值)与末尾元素进行交换&#xff0c;将最大值交换到数组的最后位置保存adjustHeap(nums,0,j);//重新对堆进行调整}
}


推荐阅读
  • svnWebUI:一款现代化的svn服务端管理软件
    svnWebUI是一款图形化管理服务端Subversion的配置工具,适用于非程序员使用。它解决了svn用户和权限配置繁琐且不便的问题,提供了现代化的web界面,让svn服务端管理变得轻松。演示地址:http://svn.nginxwebui.cn:6060。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • Linux下部署Symfoy2对app/cache和app/logs目录的权限设置,symfoy2logs
    php教程|php手册xml文件php教程-php手册Linux下部署Symfoy2对appcache和applogs目录的权限设置,symfoy2logs黑色记事本源码,vsco ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 众筹商城与传统商城的区别及php众筹网站的程序源码
    本文介绍了众筹商城与传统商城的区别,包括所售产品和玩法不同以及运营方式不同。同时还提到了php众筹网站的程序源码和方维众筹的安装和环境问题。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 31.项目部署
    目录1一些概念1.1项目部署1.2WSGI1.3uWSGI1.4Nginx2安装环境与迁移项目2.1项目内容2.2项目配置2.2.1DEBUG2.2.2STAT ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
author-avatar
aatwo19668035
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有