您的位置:首页 > 理论基础 > 数据结构算法

七种常见排序算法的总结

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个数有序

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息