1. 题目分析
1.1选择排序
每一趟在n-i+1(i=1,2,…n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。
它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。
1.2冒泡排序
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成。这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
1.3归并排序
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
1.4快速排序
基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
1.5插入排序
插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。基本思想是:每步将一个待排序的记录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
2.算法分析
2.1选择排序
(1)第1趟,在待排序记录r[1]~r[n]中选出最小的记录,将它与r[1]交换;
(2)第2趟,在待排序记录r[2]~r[n]中选出最小的记录,将它与r[2]交换;
(3)以此类推,第i趟在待排序记录r[i]~r[n]中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完毕。
2.2冒泡排序
(1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。
(2)对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
(3)针对所有的元素重复以上的步骤,除了最后一个。
(4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
2.3归并排序
- 从下往上的归并排序:将待排序的数列分成若干个长度为1的子数列,然后将这些数列两两合并;得到若干个长度为2的有序数列,再将这些数列两两合并;得到若干个长度为4的有序数列,再将它们两两合并;直接合并成一个数列为止。这样就得到了我们想要的排序结果。
- 从上往下的归并排序:它与"从下往上"在排序上是反方向的。它基本包括3步:
(1)分解 – 将当前区间一分为二,即求分裂点 mid = (low + high)/2;
(2)求解 – 递归地对两个子区间a[low…mid] 和 a[mid+1…high]进行归并排序。递归的终结条件是子区间长度为1。
(3)合并 – 将已排序的两个子区间a[low…mid]和 a[mid+1…high]归并为一个有序的区间a[low…high]。
2.4快速排序
(1)当分区选取的基准元素为待排序元素中的最大或最小值时,为最坏的情况,时间复杂度和直接插入排序的一样,移动次数达到最大值
Cmax = 1+2+…+(n-1) = n*(n-1)/2 = O(n2) 此时最好时间复杂为O(n2)
(2)当分区选取的基准元素为待排序元素中的"中值",为最好的情况,时间复杂度为O(nlog2n)。
(3)快速排序的空间复杂度为O(log2n).
(4)当待排序元素类似[6,1,3,7,3]且基准元素为6时,经过分区,形成[1,3,3,6,7],两个3的相对位置发生了改变,所是快速排序是一种不稳定排序。
2.5 插入排序
(1)将指针指向某个元素,假设该元素左侧的元素全部有序,将该元素抽取出来,然后按照从右往左的顺序分别与其左边的元素比较,遇到比其大的元素便将元素右移,直到找到比该元素小的元素或者找到最左面发现其左侧的元素都比它大,停止;
(2)此时会出现一个空位,将该元素放入到空位中,此时该元素左侧的元素都比它小,右侧的元素都比它大;
(3)指针向后移动一位,重复上述过程。每操作一轮,左侧有序元素都增加一个,右侧无序元素都减少一个。
3.算法实现
#include<iostream>
#include<stdlib.h>
#include<math.h>
#include<time.h>
using namespace std;
/*定义*/
int temp[100001];
int a[100001];//定义数组a
class sorted{
public:
int m;//定义数据个数的变量
int i;
int c;
public :
void Select_sort(int a[], int len);//选择排序
void Bubble_sort(int b[], int len);//冒泡排序
void number(int a[], int m);
void time(int m);
void merge_sort(int a[], int left, int right);//合并排序
void merge(int a[], int left, int middle, int right);
void quick_sort(int a[], int left, int right);//快速排序
void insert_sort(int a[],int len);//插入排序
};
/*时间计算函数*/
void sorted::time(int m)
{
double avg=0;//平均时间
double sum=0;//数组中20组时间的总和
double total[20] = {0};
clock_t start, finish;
number(a, m);
cout << "20组样本(ms):" << endl;
switch (c){
/*选择排序*/
case 1:
cout << "选择排序" << endl;
for (i = 0; i < 20; i++)//进行20组排序测试
{
start = clock();//开始计时
Select_sort(a, m);
finish = clock();//结束计时
total[i] = (double)(finish - start) * 1000 / CLOCKS_PER_SEC; cout << " " << total[i];//输出时间
}
break;
/*冒泡排序*/
case 2:
cout << "冒泡排序" << endl;
for (i = 0; i < 20;i++)//进行20组排序测试
{
start = clock();
Bubble_sort(a, m);
finish = clock();
total[i] = (double)(finish - start) * 1000 / CLOCKS_PER_SEC;
cout << " " << total[i];
}
break;
/*合并排序*/
case 3:
cout << "合并排序" << endl;
for (i = 0; i < 20; i++)
{
start = clock();
merge_sort(a,0,m);
finish = clock();
total[i] = (double)(finish - start) * 1000 / CLOCKS_PER_SEC; cout << " " << total[i];
}
break;
/*快速排序*/
case 4:
cout << "快速排序" << endl;
for (i = 0; i < 20; i++)
{
start = clock();
quick_sort(a, 0, m);
finish = clock();
total[i] = (double)(finish - start) * 1000 / CLOCKS_PER_SEC;
cout << " " << total[i];
}
break;
/*插入排序*/
case 5:
cout << "插入排序" << endl;
for (i = 0; i < 20; i++)
{
start = clock();
insert_sort(a, m);
finish = clock();
total[i] = (double)(finish - start) * 1000 / CLOCKS_PER_SEC;
cout << " " << total[i];
}
break;
}
for (int i = 0; i < 20; i++)
{
sum += total[i];
}
avg = sum / 20;//平均时间
cout << "\n平均花费时间(ms):" <<avg<<" ";//计算20组排序的平均时间
}
/*在数组中产生m个数据*/
void sorted::number(int a[], int m)//将m个数传入数组a[]
{
int i;
for (i = 0; i < m; i++)
{
a[i] = rand() % 100 + 1;
}
cout << "\n数据规模为" << m << "时" << endl;
}
/*选择排序*/
void sorted::Select_sort(int a[], int len)
{
int min, temp;
for (int i = 0; i < len - 1; i++)
{
min = i;
for (int j = i + 1; j<len; j++)
{
if (a[min]>a[j])
min = j;
}
temp = a[i];
a[i] = a[min];
a[min] = temp;
}
}
/*冒泡排序*/
void sorted::Bubble_sort(int a[], int len)
{
int i;
int temp;
for (i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (a[j]>a[j + 1])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
/*归并排序*/
void sorted::merge(int a[], int left, int middle, int right)
{
int t = left, i = left, j = middle + 1;
while (i <= middle&&j <= right){
if (a[i] <= a[j])
temp[t++] = a[i++];
else
temp[t++] = a[j++];
}
while (i <= middle)
temp[t++] = a[i++];
while (j <= right)
temp[t++] = a[j++];
for (int i = left; i <= right; ++i)
a[i] = temp[i];
}
/*归并排序主函数*/
void sorted::merge_sort(int a[], int left, int right)
{
if (left == right)
return;
int middle = (left + right) / 2;
merge_sort(a, left, middle);
merge_sort(a, middle + 1, right);
merge(a, left, middle, right);
}
/*快速排序*/
void sorted::quick_sort(int a[], int left, int right)
{
if (left >= right || a == NULL || (sizeof(a)/sizeof(a[0])) < 1){
return;
}
int l = left;
int r = right;
int z= a[l];
if (l < r)
{
while (l < r)
{
while (l < r && z<= a[r])
{
r--;
}
if (l < r)
{
a[l] = a[r];
l++;
}
while (l<r && z>a[r])
{
l++;
}
if (l < r)
{
a[l] = a[r];
r--;
}
}
}
a[l] = z;
quick_sort(a, left, l - 1);
quick_sort(a, l + 1, right);
}
/*插入排序*/
void sorted::insert_sort(int a[],int len)
{
for (int i = 1; i<len; i++)
{
int tmp = a[i];
int j = i - 1;
while (j >= 0 && tmp<a[j])
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = tmp;//即a[j+1]=a[i]
}
}
/*主函数*/
int main()
{
sorted s;
cout << "请选择排序方法" << endl;
cout << "1. 选择排序 2. 冒泡排序 3.归并排序 4.快速排序 5.插入排序" << endl;
cin >> s.c;
switch (s.c)
{
case 1:
//cout << "选择排序" << endl;
s.time(10);//产生10个数据,间接调用排序算法以及时间计算
system("pause");
s.time(100);//产生100个数据
system("pause");
s.time(1000);//产生1000个数据
system("pause");
s.time(10000);//产生10000个数据
system("pause");
s.time(100000);//产生100000个数据
break;
case 2:
//cout << "冒泡排序" << endl;
s.time(10);
system("pause");
s.time(100);
system("pause");
s.time(1000);
system("pause");
s.time(10000);
system("pause");
s.time(100000)
break;
case 3:
s.time(10);
system("pause");
s.time(100);
system("pause");
s.time(1000);
system("pause");
s.time(10000);
system("pause");
s.time(100000);
break;
case 4:
s.time(10);
system("pause");
s.time(100);
system("pause");
s.time(1000);
system("pause");
s.time(10000);
system("pause");
s.time(100000);
break;
case 5:
s.time(10);
system("pause");
s.time(100);
system("pause");
s.time(1000);
system("pause");
s.time(10000);
system("pause");
s.time(100000);
break;
}
return 0;
}
4.运行结果
5.算法复杂度分析及经验归纳
| 排序方法 时间复杂度 空间复杂度 稳定性 复杂性
平均 最好 最坏
选择排序 O(n2) O(n2) O(n2) O(1) 不稳定 简单
冒泡排序 O(n2) O(n) O(n2) O(1) 稳定 简单
归并排序 O(nlog2n) O(nlog2n) O(nlog2n) O(n) 稳定 较复杂
快速排序 O(nlog2n) O(nlog2n) O(n2) O(nlog2n) 不稳定 较复杂
插入排序 O(n2) O(n) O(n2) O(1) 稳定 简单