经典排序算法总结及关键代码(c++)

蹲街弑〆低调 提交于 2020-01-28 03:56:34

主要是理解动图,结合图和代码来分析理解。

  1. 冒泡排序

平均复杂度:O(n2)

空间复杂度:O(1)

稳定性:稳定

冒泡排序 是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

void Bubblesort(vector<int>& a,int n)
{
    for(int i=n-1; i>0; i--)
        for(int j=0; j<i; j++)
        {
            if(a[j]>a[j+1])
                swap(a[j],a[j+1]);
        }
}

 

  1. 选择排序

平均复杂度:O(n2)

空间复杂度:O(1)

稳定性:不稳定

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕

 

vector<int> selectionSort(vector<int>& a) {
    if (a.size() == 0)
        return a;
    for (int i = 0; i < a.size(); i++) {
        int minIndex = i;
        for (int j = i; j < a.size(); j++) {
            if (a[j] < a[minIndex]) //找到最小的数
                minIndex = j; 
        }
    //将最小数与已排序队列末尾元素交换
        int temp = a[minIndex];
        a[minIndex] = a[i];
        a[i] = temp;
    }
    return a;
}
  1. 插入排序

平均复杂度:O(n2)

空间复杂度:O(1)

稳定性:稳定

 

过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间

 

void Insertsort(vector<int>& a,int n)
{
    for(int i=1; i<n; i++)
    {
        int temp=a[i];
        int j=i-1;
        while(j>=0&&temp<a[j])
        {
            a[j+1]=a[j];
            j--;
        }
        a[j+1]=temp;
    }
}
  1. 希尔排序

平均复杂度:O(nlogn)

空间复杂度:O(1)

稳定性:不稳定

希尔排序是简单插入排序经过改进之后的一个更高效的版本,把数组分为多组(每一定间隔(增量)的数为一组),进行多轮插入排序,可以减少移动次数。一开始先选择较大的增量,然后不断缩短增量直至增量为1,变为普通插入排序

void Shellsort(vector<int>& a,int n)
{
    for(int gap=n/3; gap>=1; gap=(gap-1)/3+1)//选取增量并不断缩小,直至为1,增量可以任选
    {
        for(int i=gap; i<n; i++)
        {
            int temp=a[i];
            int j=i-gap;
            while(j>=0&&temp<a[j])
            {
                a[j+gap]=a[j];  //插入排序
                j-=gap;
            }
            a[j+gap]=temp;
        }
        if(gap<=1)//临界判断
            break;
    }
}

 

  1. 快速排序

平均复杂度:O(nlogn)

空间复杂度:O(n)

稳定性:不稳定

过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序

int Swap(vector<int>&a,int n)
{
    int i=0;
    for(int j=0; j<=n-2; j++)   //循环除基准外的所有元素
        if(a[j]<=a[n-1])
            swap(a[i++],a[j]);//选取a[n-1]为基准,比其小的放在前面,大的放在后面
    //主元可以随机选取,尽量避免最坏情况发生
    swap(a[i],a[n-1]);//最后把主元放在中间
    return i;
}
void Quicksort(vector<int>& a,int n)
{
    if(n<=1)
        return;//临界判断
    int i=Swap(a,n);//把a的n个元素划分为两部分,取其分界点。
    Quicksort(a,i);
    Quicksort(a+i+1,n-1-i);//左右两部分递归排序
}

 

  1. 归并排序

平均复杂度:O(nlogn)

空间复杂度:O(n)

稳定性:稳定

建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序是一种稳定的排序方法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并

void Merge(int* a,int p,int n)
{
    int n1=p,n2=n-p;
    int* L=new int[n1+1],*R=new int[n2+1];//建立两个数组来分别保存左右两部分的元素
    for(int i=0; i<n1; i++) //先将元素复制到数组中
        L[i]=a[i];
    for(int i=0; i<n2; i++)
        R[i]=a[p+i];
    L[n1]=R[n2]=INT_MAX;    //将末尾元素设为无穷大
    //将两组元素合并排排序,相当于设两个指针依次往后比较
    for(int i=0,j=0; i+j<n;)
    {
        if(L[i]<R[j])
        {
            a[i+j]=L[i];
            i++;
        }
        else
        {
            a[i+j]=R[j];
            j++;
        }
    }
    delete []L;
    delete []R;
}
void Mergesort(int* a,int n)
{
    if(n<=1)
        return;//临界判断
    int i=n/2;
    Mergesort(a,i);
    Mergesort(a+i,n-i);//对左右两部分分别排序(递归)
    Merge(a,i,n);//将已排好序的两部分合并
}

 

  1. 堆排序

平均复杂度:O(nlogn)

空间复杂度:O(1)

稳定性:不稳定

利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

 

参考:http://www.west999.com/info/html/chengxusheji/Javajishu/20190217/4612849.html

             https://blog.csdn.net/weixin_41190227/article/details/86600821

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!