您的位置:首页 > 其它

插入排序、归并排序、快速排序的比较和分析

2015-02-23 22:42 253 查看

插入排序、归并排序、快速排序的比较和分析

三者的时间复杂度:

平均情况,依次是O(n^2), O(nlogn), O(nlogn)

最好情况,依次是O(n), O(nlogn), O(nlogn)

最差情况,依次是O(n^2), O(nlogn), O(n^2)

三者的空间复杂度:依次是O(1), O(n), O(1)

1)插入排序

#include <iostream>
#include <vector>
#include <cfloat>

using namespace std;

void insertsort(vector<double> & A)
{
for(int j=1; j<A.size(); j++)
{
double key = A.at(j);

int i;
for(i=j-1; i>=0 && A.at(i) > key; i--)
{
A.at(i+1) = A.at(i);
}
/*
int i=j-1;
while( i>=0 && A.at(i) > key )
{
A.at(i+1) = A.at(i);
i--;
}
*/
A.at(i+1) = key;
}
}
int main(int argc, char ** argv)
{
double arr[] = {234, 12, 34, 3.23, 34.3, 23, 124, 1, 2, 5, 3, 9, 12};
vector<double> A(arr, arr+13);
for(int i=0; i<A.size(); i++)
cout<<A.at(i)<<" ";
cout<<"\n\n";
insertsort(A);
for(int i=0; i<A.size(); i++)
cout<<A.at(i)<<" ";
cout<<endl;
return 0;
}


基本思想:不断向有序数组中插入新的数,从而维护一个递增/递减的有序数组。把即将插入的数与有序数组中从后往前进行比较,与从前往后比较相比,虽然不能减少元素向后的挪动次数,但是能减少比较次数。

2)归并排序

#include <iostream>
#include <vector>
#include <cfloat>

using namespace std;

void merge(vector<double> & A, int p, int q, int r)
{
int n1 = q-p+1;
int n2 = r-q;
vector<double> L(n1+1), R(n2+1);
for(int i=0; i<n1; i++)
{
L.at(i) = A.at(p+i);
}
for(int i=0; i<n2; i++)
{
R.at(i) = A.at(q+i+1);
}
L.at(n1) = DBL_MAX;
R.at(n2) = DBL_MAX;
int i=0, j=0;
for(int k=p; k<=r; k++)
{
if(L.at(i) <= R.at(j))
{
A.at(k) = L.at(i);
i++;
}
else
{
A.at(k) = R.at(j);
j++;
}
}
}

void mergesort(vector<double> & A, int p, int r)
{
if(p<r)
{
int q = (p+r) / 2;
mergesort(A, p, q);
mergesort(A, q+1, r);
merge(A, p, q, r);
}

}

int main(int argc, char ** argv)
{
double arr[] = {234, 12, 34, 3.23, 34.3, 23, 124, 1, 2, 5, 3, 9, 12};
vector<double> A(arr, arr+13);
for(int i=0; i<A.size(); i++)
cout<<A.at(i)<<" ";
cout<<"\n\n";
mergesort(A, 0, A.size()-1);
for(int i=0; i<A.size(); i++)
cout<<A.at(i)<<" ";
cout<<endl;
return 0;
}


基本思想:这是典型的分治算法:将原问题分解为多个子问题,解决子问题,子问题合并。一般情况下都要用到递归,因为子问题的解决方法往往与原问题是相似的。

总结:哨兵的恰当使用能使边界处理变得更简洁。

3)快速排序

#include <iostream>
#include <vector>
#include <cfloat>

using namespace std;

int partition(vector<double> & A, int p, int r)
{
double x = A.at(r);
int i = p-1;
for(int j=p; j<r; j++)
{
if(A.at(j) <= x)
{
i++;
double tmp = A.at(j);
A.at(j) = A.at(i);
A.at(i) = tmp;
}
}
A.at(r) = A.at(i+1);
A.at(i+1) = x;
return i+1;
}
void quicksort(vector<double> & A, int p, int r)
{
if(p<r)
{
int q = partition( A, p, r);
quicksort(A, p, q-1);
quicksort(A, q+1, r);
}
}
int main(int argc, char ** argv)
{
double arr[] = {234, 12, 34, 3.23, 34.3, 23, 124, 1, 2, 5, 3, 9, 12};
vector<double> A(arr, arr+13);
for(int i=0; i<A.size(); i++)
cout<<A.at(i)<<" ";
cout<<"\n\n";
quicksort(A, 0, A.size()-1);
for(int i=0; i<A.size(); i++)
cout<<A.at(i)<<" ";
cout<<endl;
return 0;
}


基本思想:以上实现的快速排序是每次把当前待排序数组最后一个元素当作pivot,使用两个指针,把所有元素partition成两拨——比pivot大的放在数组右边,比pivot小的放在左边。然后对每一拨用同样的方法进行partition,直到最后每一拨只剩下两个元素,递归解决原问题。快速排序有其非递归版本和随机版本,原理大相径庭,在此不加赘述。

总结:快速排序的最坏情况时间复杂度达到O(n^2),但是在实际应用中,它的性能往往优于其他排序方法,能达到O(nlogn).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐