浅谈排序算法[动图](有很多你没见过的排序算法)

内部排序

内部排序主要是在OI中可以使用,外部排序则不能。
下面我们将讲述\(n\)种内部排序,请做好准备。

1.内省式排序

其实是多种排序算法的集合,先进行快速排序,如果序列接近有序或比较小用插入排序,如果递归层数过多则改用堆排序。

你有没有想:一开始就介绍这么多种排序算法的集合,还没学那些排序呢!

不用担心,这个东西的实现代码最简单:

sort(arr,arr+n);

如果想要逆序排序或者其他规则排序:

#include<algorithm>     //一定要用这个头文件
bool cmp(obj a,obj b)   //obj指你要排序对象的类型
{
    ...                 //里面的规则如果写return a<b;就是从小到大啦,sort默认从小到大。
    return ...;
}
sort(arr,arr+n,cmp);

2.冒泡排序

冒泡就是先遍历数组1~n-1的元素,如果a[i]>a[i+1]就把他们交换,然后遍历数组2~n-1的元素\(\dots\)最后遍历到n-1~n-1结束。

动图如下:


效果图(可视化感觉更强):

代码如下:

template<typename T>
void BubbleSort(T arr[], T n)
{
    for (int i=0;i<n-1;i++)
        for (int j=0;j<n-i-1;j++)
            if (arr[j]>arr[j+1])
            {
                T temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
}

还可以加个优化,如果没有交换发生(以及有序)就不用再遍历了:

template<typename T>
void BubbleSort(T arr[], T n)
{
    for (int i=0;i<n-1;i++)
        for (int j=0;j<n-i-1;j++)
        {
            bool flag=false;
            if (arr[j]>arr[j+1])
            {
                T temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
                flag=true;
            }
            if (!flag) return ;
        }
}

时间复杂度\(\mathcal{O}(n^2)\)

扫描二维码关注公众号,回复: 9105987 查看本文章

3.[冒泡排序优化]鸡尾酒排序

鸡尾酒排序,也就是定向冒泡排序鸡尾酒搅拌排序搅拌排序(也可以视作选择排序的一种变形),涟漪排序来回排序快乐小时排序,是冒泡排序的一种变形。

这个算法不是单纯的单向排序了,而是第一次从左到右冒泡,第二次从右到左冒泡\(\dots\)

这样的话会优化常数,但还是\(\mathcal{O}(n^2)\)

动图:

代码如下:

void Cocktailsort(int s[],int n)
{
    int left=0;
    int right=n-1;
    while(left<right)
   {
        for(int i=left;i<right;i++)
            if (s[i]>s[i+1]) swap(s[i],s[i+1]);
        right--;
        for(int i=right;i>left;i--)
            if(s[i]<s[i-1]) swap(s[i],s[i-1]);
        left++;
    }
}

鸡尾酒排序也可以加优化:判断是否产生交换,代码并不难写,读者可以自己实现。

4.[冒泡排序优化]地精排序

被Dick Grune称为最简单的排序算法。整个算法只有一层循环,默认情况下前进冒泡,一旦遇到冒泡的情况发生就往回冒,直到把这个数字放好,然后继续前进,前进到数组最后一个数结束。此排序算法虽然代码极短,但效率不高。
动图:

如果看不了来这里

代码:

template<typename T>
void GnomeSort(T *a,T n)
{
    int i=0; 
    while (i<n)
    {
        if (i==0||a[i-1]<=a[i]) i++;
        else swap(a[i],a[i-1]),i--;
    }
}

emm也是\(\mathcal{O}(n^2)\)

5.[冒泡排序逆优化]臭皮匠排序

臭皮匠排序(Stooge Sort),是一种低效的排序算法,在《算法导论》第二版第7章的思考题中被提到,是由Howard Fine等教授提出的所谓“漂亮的”排序算法。将数列平分为三个子串,依次递归排序前两个子串、后两个子串、前两个子串,最后确保整个数列有序。此算法在最坏情况下的递归式为\(T(n) = 3T(2n/3) + 1\)。由主定理很容易知道它的算法复杂性为:\(T(n) = \mathcal{O}(n^{\log_\frac{3}{2}, 3})\)。很显然\(\log_\frac{3}{2}, 3>2\),也就是说这个算法比插入排序的\(\mathcal{O}(n^2)\)性能还差。

最大就\(\mathcal{O}(n^{2.7})\)吧。。

动图:

代码如下:

void StoogeSort(int *a,int i,int j)
{
    if (a[i]>a[j]) swap(a[i],a[j]);
    if ((i+1)>=j) return ;
    int k=(j-i+1)/3;
    StoogeSort(a,i,j-k);
    StoogeSort(a,i+k,j);
    StoogeSort(a,i,j-k);
}

6.[冒泡排序优化]奇偶排序

你有没有想冒泡排序优化怎么这么多

奇偶排序(OddEven Sort),是一种相对简单的排序算法,最初发明用于有本地互联的并行计算。此算法通过比较数组中相邻的(奇-偶)位置数字对,如果该奇偶对是错误的顺序(第一个大于第二个),则交换。下一步重复该操作,但针对所有的(偶-奇)位置数字对。如此交替下去,直到不发生交换,则排序结束。
在并行计算排序中,使用该算法,每个处理器对应处理一个值,并仅有与左右邻居的本地互连。所有处理器可同时与邻居进行比较、交换操作,交替以奇-偶、偶-奇的顺序。该算法由Habermann在\(1972\)年最初发表并展现了在并行处理上的效率。但在单处理器串行运行此算法,类似冒泡排序,较为简单但效率并不特别高。

示意图:

最差\(\mathcal{O}(n^2)\)

代码:

void OddEvenSort(int *a, int len)
{
    bool swapped=true;
    while (swapped)
    {
        swapped=false;
        for (int i=0;i<len-1;i=i+2)
            if (a[i]>a[i+1])
            {
                swap(a[i],a[i+1]);
                swapped=true;
            }
        for (int i=1;i<len-1;i=i+2)
            if (a[i]>a[i+1])
            {
                swap(a[i],a[i+1]);
                swapped=true;
            }
    }
}

冒泡排序优化当然都是稳定排序啦。

7.选择排序

每次选出一个最小的放到左边,然后依次这么做就行。

时间复杂度\(\mathcal{O}(n^2)\)

动图:

效果图(可视化感觉更强):

代码如下:

template<typename T>
void ssort(T* array,int size)
{
    for(int i=0;i<size;i++)
    {
        T Min=array[i];
        int k=i;
        for (int j=i+1;j<size;j++)
            if (array[j]<Min) min=array[j],k=j;
        if (k!=i) array[k]=array[i],array[i]=Min;
    }
}

8.[选择排序优化]堆排序

每次取最小值用堆实现,这样就更快了,可以达到\(\mathcal{O}(n\log n)\)

猜你喜欢

转载自www.cnblogs.com/CDOI-24374/p/12300350.html