参考书籍:《数据结构、算法与应用 C++语言描述》
一:排序算法复杂度
排序算法 |
最坏情况性能
|
平均性能
|
冒泡排序
|
n2
|
n2
|
计数排序 |
n2
|
n2
|
插入排序
|
n2
|
n2
|
选择排序
|
n2
|
n2
|
堆排序
|
nlog(n) |
nlog(n) |
归并排序
|
nlog(n) |
nlog(n) |
快速排序
|
n2
|
nlog(n)
|
二、三值取中快排
由于快排对有序的输入序列比对无序输入序列要慢,为了解决这个问题,提高快排的平均性能,提出三值取中规则选择支点元素。方法是对序列的最左头元素、中间元素、最右头元素取三者的中值元素作为支点元素。比如三元素分别为5、9、7,则取7为支点元素;
使用三值取中规则对输入有序的表进行快速排序,用时为O(nlog(n))。并且不会出现一个数据段为空的情况(当快排左右两块大小差不多时性能最好),使用三值取中就可以保证左右两个数据段长度均衡
三、结合两种性能好的排序算法
实验发现当排序的数量小于某值时,插入排序性能最好,大于某值,快速排序性能最好;所以可以设置某值c结合着这两种算法.
四、C++中的排序方法
sort:使用改进的快排,当子序列(已经经过了分治)的数量超过对数的某个常数倍时,使用堆排序,数据段不大时,使用过插入排序;
stable_sort:是归并排序,当数据段不大时,使用插入排序。
五、性能最优排序算法(18章课后题28)
发现:1,在1000以上,快排的效果就显示出来了,几百的时候插入排序就很快;2,随着总数的上升nbreak不能太小,在总数0.1倍的时候效果还可以,再小就越来越差。
(注:生成数据随机,带/的后面是STL的sort方法的运行时间,没有的表示sort运行时间为0,每组试验数据多次取平均):
总数
|
1000 |
5000
|
50000
|
nbreak=100
|
0.001
|
太慢
|
|
nbreak=500
|
0有时比sort好
|
0.017
|
|
nbreak=1000
|
0~0.001
|
0.012
|
|
nbreak=2000
|
|
0.008/0.001
|
|
nbreak=2500
|
|
0.010
/0.001
|
45.513/0.005
|
nbreak=5000
|
|
0.017
|
1.111/0.006
|
nbreak=10000
|
|
|
0.636/0.004
|
nbreak=20000
|
|
|
0.646/0.004
|
nbreak=25000
|
|
|
0.956/0.006
|
nbreak=50000
|
|
|
1.373/0.01
|
//书chp18 题28
#include <iostream>
#include <algorithm>
#include <iterator>
#include <array>
#include <time.h>
using namespace std;
//void insertsort(int b[], int leftEnd, int rightEnd);
void MySort(int b[], int leftEnd, int rightEnd);
int main()
{
const int count = 50000;
int sortnumber[count];
srand(unsigned(time(0)));//为了防止后面rand生成的随机数不同
for (size_t i = 0; i < count; i++)
sortnumber[i] = rand() % 30000;
//排序算法,从小到大
clock_t start, finish;
double totaltime;
start = clock();
//int leftEnd = 0;
//int rightEnd = sortnumber.size() - 1;
MySort(sortnumber, 0, count - 1);
finish = clock();
totaltime = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "my sort:" << totaltime<<endl ;
//for (int i = 0; i<count; i++)//输出排列好以后的数组元素
//cout << ' ' << sortnumber[i];
cout << endl;
array<int, count> sortnumber1;
srand(unsigned(time(0)));//为了防止后面rand生成的随机数不同
for (size_t i = 0; i < count; i++)
sortnumber1[i] = rand() % 1000;
start = clock();
sort(sortnumber1.begin(), sortnumber1.end()); //C++ STL函数的sort方法
finish = clock();
totaltime = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "C++ sort:" << totaltime << endl;
return 0;
}
void MySort(int b[], int leftEnd, int rightEnd)
{
int Snum = rightEnd - leftEnd + 1;
int nBreak = 50000;
int a[] = { b[leftEnd], b[(leftEnd + rightEnd) / 2], b[rightEnd] };
if (Snum>nBreak) //使用快排
{
//‘三值取中’
if (a[0] > a[1])
{
swap(b[leftEnd], b[(leftEnd + rightEnd) / 2]);
}
if (a[1] > a[2])
{
swap(b[rightEnd], b[(leftEnd + rightEnd) / 2]);
if (a[0] > a[1])
{
swap(b[leftEnd], b[(leftEnd + rightEnd) / 2]);
}
}
//取中间元素作为支点
int mid = b[(leftEnd + rightEnd) / 2];
MySort(b, 0, (leftEnd + rightEnd) / 2 - 1);
MySort(b, (leftEnd + rightEnd) / 2 + 1, rightEnd);
}
else //使用插入排序
{
//insertsort(b, leftEnd, rightEnd);
for (int i = leftEnd + 1; i <= rightEnd; i++)
{
int t = b[i];
int j;
for (j = i - 1; j >= 0 && t < b[j]; j--)
b[j + 1] = b[j];
b[j + 1] = t; //注意此处是j+1是因为for循环执行完j会多减一次。
}
}
}
等看了二叉树后,补上堆排序。