一、实验题目
排序问题探究 实现几种经典的排序算法(冒泡排序、快速排序、插入排序、选择排序、归并排 序等)分别对 5000,10000,50000,100000,500000,1000000, 2000000 的数据量进行排序,测试排序的时间,分析各自的适用场景,并给出详 细的性能分析。
二、实验方法及分析
1、冒泡排序
(1)原理:
1、从第一个数据开始,与第二个数据相比较,如果第二个数据小于第一个数据,则交换两个数据的位置。
2、指针由第一个数据移向第二个数据,第二个数据与第三个数据相比较,如果第三个数据小于第二个数据,则交换两个数据的位置。
3、依此类推,完成第一轮排序。第一轮排序结束后,最大的元素被移到了最右面。
4、依照上面的过程进行第二轮排序,将第二大的排在倒数第二的位置。
5、重复上述过程,没排完一轮,比较次数就减少一次。
(2)冒泡排序分析:
N个元素需要排序N-1轮;
第i轮需要比较N-i次;
N个元素排序,需要比较n(n-1)/2次;
冒泡排序的算法复杂度较高,为O(n*n)
2、快速排序
(1)原理:
1、设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2、以第一个数组元素作为关键数据,赋值给key,即 key=A[0];
3、从j开始向前搜索,即由后开始向前搜索(j=j-1即j--), 找到第一个小于key的值A[j],A[i]与A[j]交换;
4、从i开始向后搜索,即由前开始向后搜索(i=i+1即i++), 找到第一个大于key的A[i],A[i]与A[j]交换;
5、重复第3、4、5步,直到I=J; (3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。 找到并交换的时候i, j指针位置不变。另外当i=j这过程一定正好是i+或j-完成的最后令循环结束)
(2)快速排序分析:
如果能“尽快地”把原问题分为规模小的问题,那么它的效率是比较好的。如果每次划分都能平均的将规模缩小一半,那么这种划分就是能最快到达目的的。而这种划分的结果直接和分界点 q 相关,如果每次划分时的q 选的足够好,也就是小于q 的元素个数等于大于q的元素个数,那么这将是最好的情况。但是q的选择往往是随机的。而且如果专门为选择一个合适的q又用一个函数来实现,那么算法的效率将得不到保障。
3、插入排序
(1)原理:
1、将指针指向某个元素,假设该元素左侧的元素全部有序,将该元素抽取出来,然后按照从右往左的顺序分别与其左边的元素比较,遇到比其大的元素便将元素右移,直到找到比该元素小的元素或者找到最左面发现其左侧的元素都比它大,停止;
2、此时会出现一个空位,将该元素放入到空位中,此时该元素左侧的元素都比它小,右侧的元素都比它大;
3、指针向后移动一位,重复上述过程。每操作一轮,左侧有序元素都增加一个,右侧无序元素都减少一个。
(2)插入排序分析:
时间复杂度,由于仍然需要两层循环,插入排序的时间复杂度仍然为O(n*n)。
比较次数:在第一轮排序中,插入排序最多比较一次;在第二轮排序中插入排序最多比较二次;以此类推,最后一轮排序时,最多比较N-1次,因此插入排序的最多比较次数为1+2+...+N-1=N*(N-1)/2。尽管如此,实际上插入排序很少会真的比较这么多次,因为一旦发现左侧有比目标元素小的元素,比较就停止了,因此,插入排序平均比较次数为N*(N-1)/4。
移动次数:插入排序的移动次数与比较次数几乎一致,但移动的速度要比交换的速度快得多。
综上,插入排序的速度约比冒泡排序快一倍(比较次数少一倍),比选择排序还要快一些,对于基本有序的数据,插入排序的速度会很快,是简单排序中效率最高的排序算法。
4、选择排序
(1)原理:
1、从第一个元素开始,分别与后面的元素向比较,找到最小的元素与第一个元素交换位置;
2、从第二个元素开始,分别与后面的元素相比较,找到剩余元素中最小的元素,与第二个元素交换;
3、重复上述步骤,直到所有的元素都排成由小到大为止。
(2)选择排序分析:
N个元素需要排序N-1轮
第i轮需要比较N-i次;
N个元素排序,需要比较n(n-1)/2次;
选择排序的算法复杂度仍为O(n*n);
相比于冒泡排序,选择排序的交换次数大大减少,因此速度要快于冒泡排序。
5、归并排序
(1)原理:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
(2)选择排序分析:
归并排序比较占用内存,但却是一种效率高且稳定的算法。
改进归并排序在归并时先判断前段序列的最大值与后段序列最小值的关系再确定是否进行复制比较。如果前段序列的最大值小于等于后段序列最小值,则说明序列可以直接形成一段有序序列不需要再归并,反之则需要。所以在序列本身有序的情况下,时间复杂度可以降至O(n)。
三、结果对比
四、结论
插入排序算法(附带完成时间结果输出)
#include <stdlib.h>
#include <iostream>
#include <time.h>
#define MAX 500000
using namespace std;
clock_t start,end;
int a[MAX];
void sortCharu(int * a){
start=clock();
for (int i = 1; i<MAX; i++) {
int j = 0;
while (j<i&&a[j] <= a[i]) {
j++;
}
if (j<i) {
int k = i;
int temp = a[i];
while (k>j) {
a[k] = a[k - 1];
k--;
}
a[k] = temp;
}
}end=clock();
/*for (int i = 0; i<MAX; i++) {
cout << a[i] << endl;
}*/
}
int main()
{
srand((unsigned)time(NULL));
for (int i = 0; i < MAX; i++)
{
a[i] = rand();
}
sortCharu(a);
cout<< (double) (end-start)/CLOCKS_PER_SEC<<endl;
return 0;
}
归并排序算法(附带完成时间结果输出)
#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <vector>
#define MAX 5000
using namespace std;
clock_t start,end;
int a[MAX];
void Merge(int A[],int Temp[],int L,int R,int RightEnd)//合并两个有序序列
{
int LeftEnd=R-1;
int p=L,i;
int num=RightEnd-L+1;
while(L<=LeftEnd&&R<=RightEnd)
if(A[L]<=A[R])
Temp[p++]=A[L++];
else
Temp[p++]=A[R++];
while(L<=LeftEnd)
Temp[p++]=A[L++];
while(R<=RightEnd)
Temp[p++]=A[R++];
for(i=0;i<num;i++,RightEnd--)
A[RightEnd]=Temp[RightEnd];
}
void MSort(int A[],int Temp[],int L,int RightEnd)
{
int center;
if(L<RightEnd)
{
center=(L+RightEnd)/2;
MSort(A,Temp,L,center);
MSort(A,Temp,center+1,RightEnd);
Merge(A,Temp,L,center+1,RightEnd);
}
}
void Merge_sort(int A[],int N)
{
int *Temp=(int *)malloc(N*sizeof(int));
if(Temp)
{
MSort(A,Temp,0,N-1);
free(Temp);
}
else
printf("no space!\n");
}
int main(){
srand((unsigned)time(NULL));
for (int i = 0; i < MAX; i++)
{
a[i] = rand();
}
start=clock();
Merge_sort(a,MAX);
end=clock();
/*for(int i=0;i<MAX;++i)
printf(" %d\n",a[i]);
printf("\n");*/
cout<< (double) (end-start)/CLOCKS_PER_SEC<<endl;
return 0;
}
快速排序算法(附带完成时间结果输出)
#include <stdlib.h>
#include <iostream>
#include <time.h>
#define MAX 2000000
using namespace std;
clock_t start,end;
int a[MAX];
void sortSupai(int *arr, int low, int high){
if (low >= high) {
return;
}
int first = low;
int last = high;
int key = arr[first];
while (first<last) {
while (first<last&&arr[last] >= key){
--last;
}
arr[first] = arr[last];
while (first<last&&arr[first] <= key){
++first;
}
arr[last] = arr[first];
}
arr[first] = key;
sortSupai(arr, low, first - 1);
sortSupai(arr, first + 1, high);
}
int main()
{
srand((unsigned)time(NULL));
for (int i = 0; i < MAX; i++)
{
a[i] = rand();
}
start=clock();
sortSupai(a, 0, MAX);
end=clock();
/*for (int i = 0; i<MAX; i++) {
cout << a[i] << endl;
}*/
cout<< (double) (end-start)/CLOCKS_PER_SEC<<endl;
return 0;
}
冒泡排序算法(附带完成时间结果输出)
#include <iostream>
#include <time.h>
#include<ctime>
#include<stdio.h>
#include <stdlib.h>
#define MAX 300000
using namespace std;
clock_t start,end;
int a[MAX];
void sortPole(int * a){
start=clock();
for (int i = 1; i<MAX; i++) {
for (int j = 0; j<MAX - i; j++) {
if (a[j]<a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
end=clock();
/*for (int i = 0; i<MAX; i++) {
cout << a[i] << endl;
}*/
}
int main()
{
srand((unsigned)time(NULL));
for (int i = 0; i < MAX; i++)
{
a[i] = rand();
}
sortPole(a);
cout<< (double) (end-start)/CLOCKS_PER_SEC<<endl;
return 0;
}
选择排序算法(附带完成时间结果输出)
#include <stdlib.h>
#include <iostream>
#include <time.h>
#define MAX 500000
using namespace std;
clock_t start,end;
int a[MAX];
void sortSelect(int * a){
start=clock();
for (int i = 0; i<MAX; i++) {
for (int j = i + 1; j<MAX; j++) {
int index = i;
if (a[index]>a[j]) {
index = j;
}
if (index != i) {
int temp = a[i];
a[i] = a[index];
a[index] = temp;
}
}
}end=clock();
/*for (int i = 0; i<MAX; i++) {
cout << a[i] << endl;
}*/
}
int main()
{
srand((unsigned)time(NULL));
for (int i = 0; i < MAX; i++)
{
a[i] = rand();
}
sortSelect(a);
cout<< (double) (end-start)/CLOCKS_PER_SEC<<endl;
return 0;
}