经常使用排序算法 持续更新

前言

开坑!而后。。。没有而后 就这样
github地址html


提纲

  1. 插入排序&希尔排序
  2. 计数排序
  3. 选择排序
  4. 冒泡排序
  5. 快速排序
  6. 归并排序
  7. 基数排序
  8. 桶排序
  9. 堆排序
  10. 列排序

1.插入排序&希尔排序

插入排序( insertion sort )

就是找到原有序序列中新元素要插入的位置而后把新元素放进去git

核心代码:github

for (j=1;j<n;j++)
{
    key=s[j];
    i=j-1;
    while ((i>=0)&&(s[i]>key))
    {
        s[i+1]=s[i];
        i=i-1;
    }
    s[i+1]=key;
}

时间复杂度: O(n^2)
空间复杂度: O(1)
算法稳定性: 稳定算法

希尔排序( shell sort )

是直接插入排序的改进版本, 也称缩小增量排序。简单的说就是把序列分组处理shell

核心代码:api

for (gap=n/2;gap>0;gap/=2)
{
    for (i=0;i<gap;i++)
    {
        for (j=i+gap;j<n;j+=gap)
        {
            key=s[j];
            k=j-gap;
            while ((k>=0)&&(s[k]>key))
            {
                s[k+gap]=s[k];
                k=k-gap;
            }
            s[k+gap]=key;
        }
    }
}

时间复杂度: O(n^1.25) (时间复杂度根据增量变化)
空间复杂度: O(1)
算法稳定性: 不稳定数组


2.计数排序(counting sort)

计数排序对输入的数据有附加的限制条件:函数

  1. 输入的线性表的元素属于有限偏序集S;
  2. 设输入的线性表的长度为n,|S|=k(表示集合S中元素的总数目为k),则k=O(n)。

(PS:好像要跑至关远啊有限偏序集,先放着,恩)优化

个人理解是 在 1 4 7 6 2 3 这个数列中,比4小的有三个,那毫无疑问生成的数列(1 2 3 4 6 7)中4排在第四位
计数排序是一个非基于比较的排序算法,并且须要处理重复数据的情形 比较排序算法下界O(nlogn) 因此这个算法有时候会比比较排序算法快ui

核心代码:

for (i=0;i<=k;i++)
    c[i]=0;
for (j=0;j<n;j++)
    c[s[j]]++;
for (i=1;i<=k;i++)   
    c[i]=c[i]+c[i-1];
for (j=n-1;j>=0;j--)
{
    out[c[s[j]]-1]=s[j];
    c[s[j]]=c[s[j]]-1;
}

时间复杂度: O(n+k)

假设n个输入元素中的每个都是在0到k区间内的一个整数,其中k为某个整数。当k=O(n)时,运行时间为O(n)。——《算法导论》

空间复杂度: O(n+k)
算法稳定性: 稳定


3.选择排序(selection sort)

选出数列中最小的那个放在第一位 重复这个过程就好啦

核心代码:

for (i=0;i<n-1;i++)
{
    min=i;
    for (j=i+1;j<n;j++)
        if (s[j]<s[min])
            min=j;
    swap=s[i];s[i]=s[min];s[min]=swap;
}

时间复杂度: O(n^2)

空间复杂度: O(1)
算法稳定性: 不稳定


4.冒泡排序(bubble sort)

把小的元素一点点往前调 好像泡泡本身冒上来23333333

核心代码:

for (j=0;j<n-1;j++)
{
    for (i=0;i<n-1-j;i++)
        if (s[i]>s[i+1])
        { swap=s[i];s[i]=s[i+1];s[i+1]=swap;}
}

时间复杂度: O(n^2)
空间复杂度: O(1)
算法稳定性: 稳定


5.快速排序(quick sort)

经过一趟排序将要排序的数据分割成独立的两部分,其中一部分的全部数据都比另一部分的全部数据都要小,而后再按此方法对这两部分数据分别进行快速排序,整个排序过程能够递归进行,以此达到整个数据变成有序序列。

快排,之前是靠背的,如今。。。仍是很难本身写
不过竟然有qsort( )在stdlib.h里面真开心hhhh

头文件:stdlib.h
用 法: void qsort(void base,int nelem,int width,int (fcmp)(const void ,const void ));
参数:
1 待排序数组首地址
2 数组中待排序元素数量
3 各元素的占用空间大小
4 指向函数的指针,用于肯定排序的顺序
(来自 百度百科)

而后 据我一个高中NOIP的同窗说 他用快排都是直接STL的 查了一下STL里面有个sort( ) 好的我决定留坑STL sort 函数实现详解 by fengcc

核心代码:

int quicksort(int *a,int l,int r)
 {
     int i,j,key;

     if ( l>=r ) return 0;
     i=l;j=r;key=a[i];
     while (i<j)
     {
         while ((i<j)&&(key<=a[j]))
             j--;
         a[i]=a[j];
         while ((i<j)&&(key>=a[i]))
             i++;
         a[j]=a[i];
     }
     a[i]=key;
     quicksort(a,l,i-1);
     quicksort(a,i+1,r);
     return 0;
 }

时间复杂度: O(nlogn)
空间复杂度: O(logn)
算法稳定性: 不稳定


6.归并排序(merge sort)

分治法,对两个子序列归并排序

核心代码:

int MergeSort(int *a,int le,int ri)
 {
     int q;
     if (le<ri)
     {
         q=(le+ri)/2;
         MergeSort(a,le,q);
         MergeSort(a,q+1,ri);
         Merge(a,le,q+1,ri);
     }
 }

时间复杂度: O(nlogn)
空间复杂度: O(n)
算法稳定性: 稳定


7.基数排序(radix sort)

基数排序是先按最低有效位进行排序来解决卡片排序问题的。 ——《算法导论》

看起来很反常规可是我简单的这样理解
较高有效位进行比较的时候能够忽视较低有效位,换言之较高有效位和较低有效位不是在一个层次上
因此较高位的变化不会影响到较低位已经排好的顺序

核心代码:

int dig[N];
int di=1,k=0,flag=1,wid;//1 still have a number having k on digit i
while (flag==1)
{
    flag=0;
    wid=pow(10,di);
    for (k=0;k<n;k++)
    {
        dig[k]=(x[k]/(wid/10))%10;
        if (x[k]/wid!=0) flag=1;
    }   
    int i=0,j=0,c[N],y[N];
    for (i=0;i<=10;i++)
        c[i]=0;
    for (j=0;j<n;j++)
        c[dig[j]]++;
    for (i=1;i<=10;i++)   
        c[i]=c[i]+c[i-1];
    for (j=n-1;j>=0;j--)
    {
        y[c[dig[j]]-1]=x[j];
        c[dig[j]]=c[dig[j]]-1;
    }
    for (i=0;i<n;i++)
        x[i]=y[i];
    di++;
}

时间复杂度: O(d(n+k)) (给定n个d位数,每个数位有k个可能取值) PS:程序中采用 k=10
空间复杂度: O(kd+n)
算法稳定性: 稳定

8.桶排序(BucketSort)

桶排序将[0,1)区间划分红n个相同大小的子区间,或称为桶。而后,将n个输入数分别放到各个桶中。
咱们先对每一个桶中的数进行排序,而后遍历每一个桶,按照次序把各个桶的元素列出来便可。 ——《算法导论》

核心代码:

for (i=0;i<n;i++)
{
    j=0;
    while (!((min+step*j<=a[i])&&(min+step*(j+1))))
    {
        j++;
    }
    b[j][next[j]]=a[i];
    next[j]++;
}
for (i=0;i<length;i++)
    InsertionSort(next[i],b[i]);
int now=0;
for (i=0;i<length;i++)
{
    for (j=0;j<next[i];j++)
    {
        a[now]=b[i][j];
        now++;
    }
}

时间复杂度: O(n)
空间复杂度: O(n+m)(m为桶的数量)
算法稳定性: 稳定

9.堆排序(HeapSort)

二叉堆是一个数组,它能够被当作一个近似的彻底二叉树 ——《算法导论》

二叉堆能够分为最大堆和最小堆。最大堆除根节点外的节点i都知足下列不等式A[PARENT(i)]>=A[i]

开始的时候,堆排序把数据建成一个最大堆,因为数组中最大元素总在根节点A1中,只要不断“取出”当前状态下的A1,排序就能够完成。

核心代码:

int HeapSize;//还没有“取出”的元素数
int HeapLength;//总元素数

int HeapSort(int *arr,int n)
{
    HeapLength=n;
    int b[N],i,temp;

    ChangeArray(arr,b,n);//将从0开始的数组改成从1开始,方便计算子节点和父节点的坐标
    BuildMaxHeap(b);

    for (i=HeapLength;i>=2;i--)
    {
        temp=b[1];
        b[1]=b[i];
        b[i]=temp;
        HeapSize-=1;
        MaxHeapify(b,1);//重构新的最大堆
    }

    RecoverArray(b,arr,n);//恢复数组为从0开始
    return 0;

}

时间复杂度: O(nlgn)
空间复杂度: O(1)
算法稳定性: 不稳定

伪·后记 2017.01.14

排序题很经典,因此真的要的话这些排序一搜就会有更好的归纳
为何我还要写呢?
又是初中复赛的那几天(咦我为何要说又),我第一次听到了“桶排序”这个概念。不记得怎么提起来的反正我是一脸懵逼的 可是当时动规都还没太懂就要考试了就放一边去了
而后就没有而后了(瞬间想起前言的举爪让我看见大家
因此此次想起来了,就来作一份,看成是完成一个老早以前的愿望罢
顺便复习一下快排2333333333333333
嘛 先这样吧 归并虽然《算法导论》看过一遍了可是我还不太会
剩下那三个是什么能够吃的(疑惑脸
啊 我知道我没写各个算法的优化那是由于我还不会 会了我再补上

伪·后记 2017.02.02

用".h"把这些排序作成了一个程序 再补上了归并和基数 有点小慢……最近有点懈怠呢 快点吧还剩两个呢 恩

相关文章
相关标签/搜索