插入排序、归并排序、快速排序的比较和分析
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).
相关文章推荐
- 归并排序和快速排序比较【算法设计与分析实验报告】
- 归并排序和快速排序比较【算法设计与分析实验报告】
- 排序算法的C++实现与性能分析(插入排序、归并排序、快速排序、STOOGE排序、堆排序)
- 快速排序、希尔排序、插入排序、选择排序、归并排序、堆排序总结
- 排序算法(堆排序、插入排序、归并排序、快速排序)
- 元素排序几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- 几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- 8 排序--选择排序,插入排序,冒泡排序,shell排序,快速排序(递归,迭代,改进版本),归并排序
- 为什么归并排序比插入排序比较次数要少?
- 归并排序和快速排序比较
- 快速排序、希尔排序、插入排序、选择排序、归并排序、堆排序总结
- 插入排序和归并排序实现以及时间复杂度分析
- 归并排序和快速排序的比较
- 归并排序和快速排序的比较
- 归并排序和快速排序比较
- 快速排序和归并排序比较
- 冒泡排序,选择排序,插入排序,堆排序,归并排序,快速排序
- 快速排序、希尔排序、插入排序、选择排序、归并排序、堆排序总结
- 几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- 算法导论之插入排序,选择排序,归并排序,冒泡排序,希尔排序,堆排序,快速排序的c语言实现