七种常见排序算法的总结
2015-11-08 17:34
316 查看
把之前写的算法都测试了一遍,发现了很多bug,真的是你认为是对的东西不去检验一下就发现不了bug,即使是最简单的算法也需要缜密的思维。
常见的排序算法有:
冒泡排序(bubble sort) — O(n^2)
插入排序(insertion sort)— O(n^2)
归并排序(merge sort)— O(nlogn); 需要 O(n) 额外空间
选择排序(selection sort)— O(n^2)
希尔排序(shell sort)— O(nlogn)
堆排序(heapsort)— O(nlogn)
快速排序(quicksort)— O(nlogn) 顾名思义,最快的排序算法。(这里要纠正一下,最快的是桶排序,o(n)时间复杂度,但是比较耗空间;快排也很快,是所有nlg(n)复杂度排序算法里面常数因子最小的,综合性能很好)
根据稳定性可归为两类:
1.stable sort:插入排序、冒泡排序、归并排序。(还有计数排序、基数排序、桶排序)
2.unstable sort:选择排序,快速排序,堆排序,希尔排序。
根据占用内存可分为两类:
In-place sort(不占用额外内存或占用常数的内存):插入排序、选择排序、冒泡排序、堆排序、快速排序。
Out-place sort:归并排序。(还有计数排序、基数排序、桶排序)
下面一一介绍,并附上c++实现。
1。冒泡排序:第i次外循环使A[i]比后面的数都小(很少用就懒得敲了,直接贴图)
2.插入排序:第i次外循环保证前i个数有序
3.归并排序:实质是递归,是分治思想的体现,先分组排序再合并排序
4.选择排序:原理和冒泡排序类似,也是第i次外循环使A[i]比后面的数都小,但是交换次数少。
5. 希尔排序,也叫缩小增量排序,利用了插入排序的最优情况。
#include <iostream>
using namespace std;
void insertsort(int A[],int n)
{
for(int i=1;i<n;++i)
for(int j=i;(j>0)&&A[j]<A[j-1];--j)
{
swap(A[j-1],A[j]);
}
}
void shellsort(int *a,int n)
{
if(a==NULL||n<2) return;
for(int i=n/2;i>1;i=i/2)
for(int j=0;j<i;++j)
for(int k=j;k<n-i;k+=i)
{
if(a[k]>a[k+i]) swap(a[k],a[k+i]);
}
insertsort(a,n);//最后一次就是利用插入排序的最理想情况
}
int main()
{
int a[]={1,77,5,44,434,123,56,-4,65,34,13,6,75,333,23};
int n=sizeof(a)/sizeof(a[0]);
shellsort(a,n);
while(n--) cout<<a
<<" ";
return 0;
}
6.堆排序:(二叉)堆是一个数组,可以近似的看作一个完全二叉树,最大堆指某节点的值小于等于其父节点的值。最差O(nlgn)。是一种非常高效的排序法
最大堆的应用还在于构造最大优先队列,以实现计算机系统作业的调度,而最小堆的应用在于最小优先队列,用于基于事件驱动的模拟器,通常是一个事件的模拟结果会触发另一个事件的模拟。
7.快速排序:通常是实际应用中最好的选择,O(nlgn)中隐含的常数因子非常小。也是分治思想的体现。
第一种实现我觉得比较简洁,但是理解起来不太容易。
第二种是课本上的,稍有不同。
常见的排序算法有:
冒泡排序(bubble sort) — O(n^2)
插入排序(insertion sort)— O(n^2)
归并排序(merge sort)— O(nlogn); 需要 O(n) 额外空间
选择排序(selection sort)— O(n^2)
希尔排序(shell sort)— O(nlogn)
堆排序(heapsort)— O(nlogn)
快速排序(quicksort)— O(nlogn) 顾名思义,最快的排序算法。(这里要纠正一下,最快的是桶排序,o(n)时间复杂度,但是比较耗空间;快排也很快,是所有nlg(n)复杂度排序算法里面常数因子最小的,综合性能很好)
根据稳定性可归为两类:
1.stable sort:插入排序、冒泡排序、归并排序。(还有计数排序、基数排序、桶排序)
2.unstable sort:选择排序,快速排序,堆排序,希尔排序。
根据占用内存可分为两类:
In-place sort(不占用额外内存或占用常数的内存):插入排序、选择排序、冒泡排序、堆排序、快速排序。
Out-place sort:归并排序。(还有计数排序、基数排序、桶排序)
下面一一介绍,并附上c++实现。
1。冒泡排序:第i次外循环使A[i]比后面的数都小(很少用就懒得敲了,直接贴图)
2.插入排序:第i次外循环保证前i个数有序
#include <iostream> using namespace std; void insertsort(int A[],int n) { for(int i=1;i<n;++i) for(int j=i;(j>0)&&A[j]<A[j-1];--j) { swap(A[j-1],A[j]); } } int main() { enum{maxx=10}; int a[maxx]={0,3,2,32,4,22,6,76,0,11}; insertsort(a,maxx); int r=maxx; while(r--) { cout<<a[r]<<" "; } return 0; }
3.归并排序:实质是递归,是分治思想的体现,先分组排序再合并排序
#include<iostream> using namespace std; void Merge(int a[],int left,int mid,int right) { int ln=mid-left+1; int rn=right-mid; int l[ln],r[rn],i,j,k=left; for(i=0;i<ln;i++) l[i]=a[left+i]; for(j=0;j<rn;++j) r[j]=a[mid+1+j]; i=0; j=0; while(i<ln&&j<rn) { if(l[i]<r[j]) a[k++]=l[i++]; else a[k++]=r[j++]; } while(i<ln) a[k++]=l[i++]; while(j<rn) a[k++]=r[j++]; } void mergesort(int a[],int left,int right) { if(left<right)//之前漏了这句导致运行时内存错误。 { int mid=(left+right)/2; mergesort(a,left,mid); mergesort(a,mid+1,right); Merge(a,left,mid,right); } } int main() { int a[]={10,3,2,55,4,22,6,76,0,11,45,33,-1,23}; int l=sizeof(a)/sizeof(a[0]); mergesort(a,0,l-1); while(l--) { cout<<a[l]<<" "; } return 0; }
4.选择排序:原理和冒泡排序类似,也是第i次外循环使A[i]比后面的数都小,但是交换次数少。
#include <iostream> using namespace std; void selectsort(int* a,int n) { int item; for(int i=0;i<n-1;i++) { int lowindex=i; for(int j=n-1;j>i;--j) { if(a[j]<a[lowindex]) lowindex=j; } if(i!=lowindex) { item=a[lowindex]; a[lowindex]=a[i]; a[i]=item; } } } int main() { int a[]={1,77,5,44,434,123,56,-4,65,34,13,6,75,333,23}; int n=sizeof(a)/sizeof(a[0]); selectsort(a,n); while(n--) cout<<a <<" "; return 0; }
5. 希尔排序,也叫缩小增量排序,利用了插入排序的最优情况。
#include <iostream>
using namespace std;
void insertsort(int A[],int n)
{
for(int i=1;i<n;++i)
for(int j=i;(j>0)&&A[j]<A[j-1];--j)
{
swap(A[j-1],A[j]);
}
}
void shellsort(int *a,int n)
{
if(a==NULL||n<2) return;
for(int i=n/2;i>1;i=i/2)
for(int j=0;j<i;++j)
for(int k=j;k<n-i;k+=i)
{
if(a[k]>a[k+i]) swap(a[k],a[k+i]);
}
insertsort(a,n);//最后一次就是利用插入排序的最理想情况
}
int main()
{
int a[]={1,77,5,44,434,123,56,-4,65,34,13,6,75,333,23};
int n=sizeof(a)/sizeof(a[0]);
shellsort(a,n);
while(n--) cout<<a
<<" ";
return 0;
}
6.堆排序:(二叉)堆是一个数组,可以近似的看作一个完全二叉树,最大堆指某节点的值小于等于其父节点的值。最差O(nlgn)。是一种非常高效的排序法
#include <iostream> using namespace std; void maxheapify(int *a,int i,int imax) { int l=2*i+1; int r=2*i+2; int largest=i; if(l<=imax) largest=a[l]>a[i]?l:i; if(r<=imax) largest=a[r]>a[largest]?r:largest; if(largest!=i) { swap(a[i],a[largest]); maxheapify(a,largest,imax); } } void buildmaxheap(int *a,int imax) { for(int j=imax/2;j>-1;j--) maxheapify(a,j,imax); } void heapsort(int *a,int imax) { buildmaxheap(a,imax); for(int j=imax;j>0;j--) { swap(a[0],a[j]); --imax; maxheapify(a,0,imax); } } int main() { int a[]={1,77,5,44,434,123,56,-4,65,34,13,6,75,333,23}; int n=sizeof(a)/sizeof(a[0]); heapsort(a,n-1); while(n--) cout<<a <<" "; return 0; }
最大堆的应用还在于构造最大优先队列,以实现计算机系统作业的调度,而最小堆的应用在于最小优先队列,用于基于事件驱动的模拟器,通常是一个事件的模拟结果会触发另一个事件的模拟。
7.快速排序:通常是实际应用中最好的选择,O(nlgn)中隐含的常数因子非常小。也是分治思想的体现。
第一种实现我觉得比较简洁,但是理解起来不太容易。
#include <iostream> using namespace std; int q_partition(int a[],int p,int r) { int x=a[r]; int i=p-1; for(int j=p;j<r;j++) { if(a[j]<x) { swap(a[++i],a[j]); } } swap(a[++i],a[r]); return i; } void quicksort(int a[],int p,int r) { if(p<r) { int q=q_partition(a,p,r); quicksort(a,p,q-1); quicksort(a,q+1,r); } } int main() { enum{maxx=10}; int a[maxx]={0,3,2,32,4,22,6,76,0,11}; int p=0,r=maxx-1; quicksort(a,p,r); for(int i=0;i<maxx;i++) { cout<<a[i]<<" "; } return 0; }
第二种是课本上的,稍有不同。
#include<iostream> using namespace std; //sort in decreasing order int partition1(int a[],int p,int r) { int k=a[p]; while(p<r) { while(p<r&&k>a[r]) r--; a[p]=a[r]; while(p<r&&k<a[p]) p++; a[r]=a[p]; } a[p]=k; return p; } void qsort(int a[],int p,int r) { if(p<r) { int k=partition1(a,p,r); qsort(a,p,k-1); qsort(a,k+1,r); } } int main() { enum{maxx=10}; int a[maxx]={1,5,33,7,88,6,44,23,65,32}; int p=0; int r=maxx-1; qsort(a,p,r); for(int i=0;i<maxx;i++) { cout<<a[i]<<" "; } return 0; }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- JavaScript演示排序算法
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(七):数据结构详解
- Lua教程(二):C++和Lua相互传递数据示例
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#数据结构揭秘一
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例