目录
- 一、实验目的和要求
- 二、实验环境
- 三、实验内容
- 四、实验过程
- 4.1 任务定义和问题分析
- 4.2 数据结构的选择和概要设计
- 五、测试及结果分析
- 5.1 实验数据
- 5.2 结果及分析
- 六、实验收获
- 八、附录(源代码)
一、实验目的和要求
目的:给出一组实验来比较排序算法的时间性能
要求:
(1)时间性能
(2)实验数据应具有说服力
(3)实验结果要能以清晰的形式给出,如图、表等。
(4)算法所用时间必须是机器时间,也可以包括比较和交换元素的次数。
(5)实验分析及其结果要能以清晰的方式来描述,如数学公式或图表等。
(6)要给出实验的方案及其分析。
二、实验环境
软件环境:visual stdio 2017
硬件环境:①CPU:Intel(R)Core(TM)i7-8565U CPU @1.80Ghz
②内存:8.0GB
三、实验内容
给出一组实验来比较排序算法的时间性能
四、实验过程
4.1 任务定义和问题分析
选取若干个排序算法,对每种算法进行大量数据测试,同一规模的数据进行3次测试取平均值,最终得到若干个实验数据,进行绘图展示。
4.2 数据结构的选择和概要设计
本次实验选取直接插入排序,希尔排序,冒泡排序,快速排序,直接选择排序,堆排序,归并排序这7种算法。
分为2个大实验组,第一个大实验组为算法时间复杂度为O(n²)的算法,其中有直接插入排序,冒泡排序,直接选择排序。
第二个实验组为算法时间复杂度为O(nlogn)的算法,其中有希尔排序,快速排序,堆排序,归并排序。
4.3 详细设计
在第一个实验组中,选取规模分别为1000,5000,10000,50000,75000,100000,125000,175000,200000,250000的数据,每种数据测试三次取平均值。
在第二个实验组中,选取规模分别为10000,100000,200000,250000,500000,600000,750000,900000,1000000,10000000,25000000,30000000,40000000,50000000,60000000,75000000,100000000的数据,每种数据测试三次取平均值。在这些数据中,以1000000为分界点,分别制图。
制图采用python中的matplotlib工具,制作曲线图。
- 直接插入排序
template<typename T>
void insert_sort(T array[], int n)
{
for (int i = 1; i < n; i++)
{
T temp = array[i];
int j = i - 1;
while (array[j] > temp&&j >= 0)
array[j + 1] = array[j--];
array[j + 1] = temp;
}
}
- 希尔排序
template<typename T>
void shell_sort(T array[], int n)
{
int d = n / 2;
while (d > 0)
{
for (int i = d; i < n; i++)
{
T temp = array[i];
int j = i - d;
while (j >= 0 && temp < array[j])
{
array[j + d] = array[j];
j -= d;
}
array[j + d] = temp;
}
d = d / 2;
}
}
- 冒泡排序
template<typename T>
void bubble_sort(T array[],int n)
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (array[j] > array[j + 1])
{
T temp = array[j + 1];
array[j + 1] = array[j];
array[j] = temp;
}
}
}
}
- 快速排序
template<typename T>
void quick_sort(T array[], int left, int right)
{
if (left >= right) return;
int i = left, j = right;
T temp = array[left];
while (i != j)
{
while (array[j] > temp&&j > i) j--;
if (i < j) array[i++] = array[j];
while (array[i] < temp&&i < j) i++;
if (i < j) array[j--] = array[i];
}
array[i] = temp;
quick_sort(array, i + 1, right);
quick_sort(array, left, i - 1);
}
- 直接选择排序
template<typename T>
void select_sort(T array[],int n)
{
for (int i = 0; i < n - 1; i++)
{
int index = i;
for (int j = i + 1; j < n; j++)
{
if (array[j] < array[index])
index = j;
}
if (i != index)
{
T temp = array[i];
array[i] = array[index];
array[index] = temp;
}
}
}
- 归并排序
template<typename T>
void merge_sort(T array[], int left, int right)
{
if (left >= right) return;
int mid = (left + right) / 2;
merge_sort(array, left, mid);
merge_sort(array, mid + 1, right);
int i = left, k = left, j = mid + 1;
while (i <= mid&&j <= right)
{
if (array[i] < array[j]) assist[k++] = array[i++];
else assist[k++] = array[j++];
}
while (i <= mid)
assist[k++] = array[i++];
while (j <= right)
assist[k++] = array[j++];
for (int k = left; k <= right; k++)
array[k] = assist[k];
}
- 堆排序
template<typename T>
void swap(T arr[], int a, int b)
{
T temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
template<typename T>
void adjustHeap(T arr[], int i, int length)
{
T temp = arr[i];
for (int k = i * 2 + 1; k < length; k = k * 2 + 1)
{
if (k + 1 < length&&arr[k] < arr[k + 1]) k++;
if (arr[k] > temp)
{
arr[i] = arr[k];
i = k;
}
else break;
}
arr[i] = temp;
}
template<typename T>
void heap_sort(T arr[], int length)
{
for (int i = length / 2 - 1; i >= 0; i--)
adjustHeap(arr, i, length);
for (int j = length - 1; j > 0; j--)
{
swap(arr, 0, j);
adjustHeap(arr, 0, j);
}
}
五、测试及结果分析
5.1 实验数据
数据规模详见上述分析,具体数据由随机数产生,范围为0~1073283121( rand()*rand() )。
5.2 结果及分析
分析:
在图像中可以清晰地看出每种算法的时间复杂度。
先进行纵向对比,可以发现三种O(n²)的算法在数据规模达到250000时的排序用时便已全部超过20s,而O(nlogn)的算法在数据规模达到40000000时的排序用时才开始出现超过20s的现象,二者差异巨大。
故:时间复杂度为O(nlogn)的算法的时间性能远远大于O(n²)时间复杂度算法的时间性能。
再进行横向对比,可以发现:时间复杂度为O(n²)的算法中,各算法对相同规模的数据的排序时间有T(冒泡排序)>T(选择排序)>T(插入排序),时间复杂度为O(nlogn)的算法中,各算法对相同规模的数据的排序时间有T(希尔排序)>T(堆排序)>T(归并排序)>T(快速排序)
故:相同时间复杂度的算法在进行相同规模数据排序时,是有差异的,这种差异随着数据规模的增加愈发明显。在O(n²)的算法中,插入排序优于选择排序,选择排序优于冒泡排序;在O(nlogn)的算法中,快速排序优于归并排序,归并排序优于堆排序,堆排序优于希尔排序。
六、实验收获
在本次实验中,我通过数据,清晰地认识到了不同时间复杂度的算法在处理大规模数据时的差异,同时也认识到,时间复杂度是相对的,尽管时间复杂度的等级相同,但在运行时所耗费的时间也会有差异。本次实验启示我以后在解决问题设计算法的时候,不仅要考虑时间复杂度的等级,也需要关注实际语句的执行次数,对其优化,达到最优。
八、附录(源代码)
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
const int N = 100000 * 1000;
int a[N];
int assist[N];
template<typename T>
void print(T array[],int n)
{
for (int i = 0; i < n; i++)
cout << array[i] << " ";
cout << endl;
}
template<typename T>
void insert_sort(T array[], int n)
{
for (int i = 1; i < n; i++)
{
T temp = array[i];
int j = i - 1;
while (array[j] > temp&&j >= 0)
array[j + 1] = array[j--];
array[j + 1] = temp;
}
}
template<typename T>
void shell_sort(T array[], int n)
{
int d = n / 2;
while (d > 0)
{
for (int i = d; i < n; i++)
{
T temp = array[i];
int j = i - d;
while (j >= 0 && temp < array[j])
{
array[j + d] = array[j];
j -= d;
}
array[j + d] = temp;
}
d = d / 2;
}
}
template<typename T>
void bubble_sort(T array[],int n)
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (array[j] > array[j + 1])
{
T temp = array[j + 1];
array[j + 1] = array[j];
array[j] = temp;
}
}
}
}
template<typename T>
void quick_sort(T array[], int left, int right)
{
if (left >= right) return;
int i = left, j = right;
T temp = array[left];
while (i != j)
{
while (array[j] > temp&&j > i) j--;
if (i < j) array[i++] = array[j];
while (array[i] < temp&&i < j) i++;
if (i < j) array[j--] = array[i];
}
array[i] = temp;
quick_sort(array, i + 1, right);
quick_sort(array, left, i - 1);
}
template<typename T>
void select_sort(T array[],int n)
{
for (int i = 0; i < n - 1; i++)
{
int index = i;
for (int j = i + 1; j < n; j++)
{
if (array[j] < array[index])
index = j;
}
if (i != index)
{
T temp = array[i];
array[i] = array[index];
array[index] = temp;
}
}
}
template<typename T>
void merge_sort(T array[], int left, int right)
{
if (left >= right) return;
int mid = (left + right) / 2;
merge_sort(array, left, mid);
merge_sort(array, mid + 1, right);
int i = left, k = left, j = mid + 1;
while (i <= mid&&j <= right)
{
if (array[i] < array[j]) assist[k++] = array[i++];
else assist[k++] = array[j++];
}
while (i <= mid)
assist[k++] = array[i++];
while (j <= right)
assist[k++] = array[j++];
for (int k = left; k <= right; k++)
array[k] = assist[k];
}
template<typename T>
void swap(T arr[], int a, int b)
{
T temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
template<typename T>
void adjustHeap(T arr[], int i, int length)
{
T temp = arr[i];
for (int k = i * 2 + 1; k < length; k = k * 2 + 1)
{
if (k + 1 < length&&arr[k] < arr[k + 1]) k++;
if (arr[k] > temp)
{
arr[i] = arr[k];
i = k;
}
else break;
}
arr[i] = temp;
}
template<typename T>
void heap_sort(T arr[], int length)
{
for (int i = length / 2 - 1; i >= 0; i--)
adjustHeap(arr, i, length);
for (int j = length - 1; j > 0; j--)
{
swap(arr, 0, j);
adjustHeap(arr, 0, j);
}
}
int main()
{
srand(time(0));
for (int i = 0; i < N; i++)
a[i] = rand()*rand();
clock_t begin = clock();
//merge_sort(a, 0, N - 1);
heap_sort(a, N);
clock_t end = clock();
//print(a, N);
cout << N << "个数据用时为" << double(end - begin) / CLOCKS_PER_SEC << "s" << endl;
return 0;
}