各种排序算法总结

排序的稳定性和复杂度

不稳定:

选择排序(selection sort)— O(n2)

快速排序(quicksort)— O(nlog2n)平均时间, O(n2)最坏情况;对于大的、乱序串列一般认为是最快的已知排序

堆排序 (heapsort)— O(nlog2n)

希尔排序 (shell sort)— O(n(1+s)) s为0~1的数

基数排序(radix sort)— O(n·k)需要O(n)额外存储空间 (K为特征个数)

稳定:

插入排序(insertion sort)— O(n2)

冒泡排序(bubble sort)— O(n2)

归并排序 (merge sort)— O(nlog2n);需要O(n)额外存储空间

二叉树排序(Binary tree sort)— O(nlogn);需要O(n)额外存储空间

计数排序 (counting sort) — O(n+k);需要O(n+k)额外存储空间,k为序列中Max-Min+1

桶排序 (bucket sort)— O(n);需要O(k)额外存储空间

插入排序

插入排序的基本思想是:将第i个记录的关键字Ki与前面记录r[1]~r[i-1]的关键字从后向前进行顺次比较,将所有关键字大于Ki的记录依次向后移动一个位置,直到遇到一个关键字小于或等于Ki的记录,该记录的位置即为r[i]的插入位置。

如:

将33,12,25,46,33,68,19,80排序
插入排序

void InsertSort(int r[], int n)//n为需要比较数个数
{
    int i,j;
    for(int i=2;i<=n;i++)
    {
        if(r[i]<r[i-1])//如果r[i]>r[i-1],则为正确序列,不用排序
            {
                r[0]=r[i];//监视哨备份,即将r[i]作为关键字
                for(j=i-1;r[0]<r[j];j--)
                {
                    r[j+1]=r[j];    //记录后移
                }
                r[j+1]=r[0];//插入到正确位置
            }
    }
}

希尔排序

希尔排序的基本思想是:将需要排序的序列划分成为若干个较小的子序列,对子序列进行插入排序,通过则插入排序能够使得原来序列成为基本有序。这样通过对较小的序列进行插入排序,然后对基本有序的数列进行插入排序,能够提高插入排序算法的效率。

希尔排序的划分子序列不是像归并排序那种的二分,而是采用的叫做增量的技术,例如有八个元素的数组进行希尔排序,首先选择增量为8/2=4。

r[1]和r[5]比较,r[2]和r[6]比较……

如:

将46,25,68,33,33,19,12,80排序
这里写图片描述

void ShellSort(int r[], int n)//n为需要比较数个数
{
    int i,j;
    int dk;//dk为增量
    for(dk=n/2;d>=1;dk=dk/2)
    {
    for(i=dk+1;i<=n;i++)
    {
        if(r[i]<r[i-dk])//如果r[i]>r[i-dk],则为正确序列,不用排序
        {
            r[0]=r[i];//监视哨备份,即将r[i]作为关键字
            for(j=i-dk;j>0&&r[0]<r[j];j-=dk)
            {
                r[j+dk]=r[j];   //记录交换
            }
            r[j+dk]=r[0];//插入到正确位置
        }
    }
  }
}

冒泡排序

冒泡排序的基本思想是:顺次比较相邻两个记录的关键字大小,如果逆序就交换位置。

void BubbleSort(int r[], int n)//n为需要比较数个数
{
    int i,j,temp;
    int flag=1;//flag为标志位
    for(i=1;i<=n-1&&flag;i++)
    {
        flag=0;//如果顺序正确则不进行比较,直接输出。
        for(j=1;j<=n-i;j++)
        {
            if(r[j]>r[j+1])
                {
                        temp=r[j];
                        r[j]=r[j+1];
                        r[j+1]=temp;
                        flag=1;
                }   
        }   
    }
}

快速排序

快速排序的基本思想是:从待序列中任意选择一个记录,以该记录为关键字,凡小于该关键字的记录均移动到该记录之前,大于该关键字的记录移动到该关键字之后。致使一趟排序之后,记录的无序序列被分割成左右两个子序列,然后再分别对两个子序列进行递归快排,直到每个子序列只含有一个记录为止。

如:

将46,68,12,25,33,80,19,33排序
这里写图片描述
这里写图片描述

void QKpass(int r[],int low,int high)//low,high分别是标志位
{
    r[0]=r[low];
    while(low<high)//当标志位重叠时结束
    {
        while(low<high&&r[high]>r[0])//如果high>关键字,前移
        {
            --high; 
        }   
        r[low]=r[high];//如果high<关键字,将high赋给low
        while(low<high&&r[low]<r[0])//如果low<关键字,后移
        {
            ++low;  
        }
        r[high]=r[low]; //如果low>关键字,将low赋给high  
    }   
    r[low]=r[0];//当标志位重叠时,将r[0]关键字赋值给r[low]
    return low;//返回标志位
}
void QKSort(int r[],int low,int high)
{
    int pos;
    if(low<high)
    {
            pos=QKpass(r,low,high);
            QKSort(r,low,pos-1);//对比关键字小的部分序列的快排
            QKSort(r,pos+1,high);//对比关键字大的部分序列的快排
    }   
}

简单选择排序

简单选择排序的基本思想是:从第一个记录开始遍历,每一趟找出一个最小值。即,第一趟,r[1]与r[2]~r[n]每一个进行比较,如果r[i]<r[1],则r[1]和r[i]值进行交换。第二趟,r[2]与r[3]~r[n]每一个进行比较,如果r[i]<r[2],则r[2]和r[i]值进行交换…….

如:

将33,68,46,33,25,80,19,12排序
这里写图片描述

void SelectSort(int r[],int n)
{
    int k,temp;
    for(int i=0;i<=n-1;i++)
    {
            k=i;
            for(j=i+1;j<=n-1;j++)
            {
                if(r[j]<r[k])
                    {
                        k=j;    
                    }   
            }
            if(k!=i)
                {
                    temp=r[i];
                    r[i]=r[k];
                    r[k]=temp;
                }
    }   
}

堆排序
堆排序的基本思想是:先建一个“大顶堆”,即先选一个关键字最大的记录,然后与序列中最后一个记录交换,之后继续对序列中前n-1记录进行“筛选”,重新将它调整为一个“大顶堆”,再将堆顶记录和第n-1个记录交换,如此反复,直至排序结束。

如:
对46,12,33,72,68,19,80,33进行堆排序

堆的筛选,过程如下:
这里写图片描述

void HeapAdjust(int r[],int s,int n)
{
    int temp=r[s];
    for(int j=2*s;j<=n;j*=2)
    {
        if(j<n&&r[j]>r[j+1])//沿值较小的节点向下筛选
            j++;
        if(temp<r[j])
            break;
            r[s]=r[j];
            s=j;
    }   
    r[s]=temp;//插入
}

建初始堆过程如下:
这里写图片描述

void CreatHeap(int r[],int n)
{
    for(i=n/2;i>=1;i--) 
        HeapAdjust(r,i,n);
}

堆排序过程如下:
这里写图片描述
这里写图片描述

void HeapSort(int r[],n)
{
    CreateHeap(r,n);    
    for(i=n;i>=2;i--)
    {
        r[0]=r[1];
        r[1]=r[i];
        r[i]=r[0];
        HeapAdjust(r,1,i-1);    
    }
}

基数排序
基数排序的基本思想是:对于数字型或字符型的单关键字,可以看做是由多个位数或多个字符构成的多关键字。
如:
对921,435,628,285,862,225,448,193,430排序。
首先按照“个位数”取值,分别为0,1…….,9“分配”成10组,之后按照0到9收集在一起。
然后按照“十位数”分配收集。
然后“百位数”。
然后……
这里写图片描述

//提取关键字第m位的数字值
int digit(KeyType k,int m,int r)
{
    int i,d;
    if(m==0)
        return k%r;
    d=r;
    for(i=1;i<m;i++)
        d*=r;
    return ((int)(key/d)%r);    
}
//基数排列
void RadixSort(Type r[],int n,int m,int r)//L中的关键字为m位r进制数,L的长度为n
{
    LinkQueue *Queue;
    int i,j,k;
    q=(LinkQueue *)malloc(r*sizeof(LinkQueue));
    for(i=0;i<r;i++)
        InitQueue(&Queue[i]);
    for(i=0;i<m;i++)
    {
        for(j=0;j<n;j++)
        {
            k=digit(L[j].key,i,r);
            EnterQueue(&Queue[k],L[j]); 
        }   
        k=0;
        for(j=0;j<r;j++)
            for(;!IsEmptyQueue(Queue[j]);k++)
                DeleteQueue(&Queue[j],&(L[k]));
    }   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值