排序算法读书笔记

/*按关键字相等的记录顺序是否变化,分为稳定和不稳定;
 *按存储器不同分为内部排序和外部排序,外部是指数量很大,内存一次不能容纳全部记录,要访问外存
 *按复杂度分简单排序、普通排序和基数排序;
 *按依据的原则不同分为插入排序、交换排序、选择排序、归并排序和计数排序。
 *排序通常需要两种操作:比较、移动记录。
 *移动可以通过存储方式改变来避免:数组、链表(链表排序)、数组辅助向量指向原地址(地址排序)
 */


 /* 1>平均时间快排最佳,但快排最坏情况下为冒泡;n较大时归并排序比堆排快,但辅助空间多。
  * 2>简单排序包括除希尔排序外所有插入排序,冒泡和简单选择排序。直接插入排序最简单,基本有序或n小时最佳。
  * 3>基数排序使用n大关键字小的情况。
  * 4>稳定排序:基数排序、所有O(n^2)排序、堆排。
  */


/** 1.插入排序 **/


/*1.1 直接插入排序 O(n^2) 稳定                 特殊:如果原数据为从小到大为O(n)
 * 将一个记录插入到已排好序的有序表中,从右往左比较n次,原表也移动n次。
 */
void InsetSort(int a[])
{
    for(int i=2;i<=n;++i)
    {
        int tp = a[i], j;
        for(j=i-1;i>0&&tp<a[j];--j)
            a[j+1] = a[j];
        a[j+1] = tp;
    }
}


/*1.2 折半插入排序 O(n^2)
 * 通过二分思想,在数组中折半查找,但是移动还是要O(n)次
 */


/*1.3 2-路插入排序 O(n^2)
 * 在折半插入排序的基础上再改进,目的是减少排序过程中的移动次数,约为n^2/8次(包含平摊除以的2)。
 * 设一辅助数组d[],令d[1]=r[1]。把d[]数组看成一个循环数组,d[1]看成中间记录。
 * 每次插入时只需要在d[1]前或者后移动。移动次数减少一半,但d[1]为最小或者最大时失去作用。
 */


/*1.4 表插入排序 O(n^2)
 * 前面用数组保存可以二分查找但是移动需要O(n)时间,用链表保存移动O(1)时间但是不能二分查找
 * 排序后数据保存在链表中,如果不要额外的空间复制到数组中。有点复杂
 */
void Arrange(int a[])
{
    //根据静态链表r中各节点的指针值调整记录位置,使得数据非递减有序排序在数组中
    int p = r[0].next;      //p指示第一个记录的当前位置
    for(int i=1; i<n; ++i)      //r[1...i-1]中记录已按关键字有序排列,
    {                           //第i个记录在r[]中的当前位置应不小于i
        while(p < i) p = r[p].next;     //找到地i个记录,并用p指示其在r中当前位置
        int q = r[p].next;              //q指示尚未调整的表尾
        if(p != i)
        {
            int tp = r[p];              //交换记录,使第i个记录到位
            r[p] = r[i];
            r[i] = tp;
            r[i].next = p;              //指向被移走的记录,使得以后可有while循环找回
        }
        p = q;                          //p指示尚未调整的表尾,为找第i+1个记录做准备
    }
}


/*希尔(Shell)排序 又称缩小增量排序
 * 它也是一种插入排序,但在时间效率上有较大的改进。时间与增量序列有关
 * 增量序列有各种取法,但:应使增量序列中的值没有除1之外的公因子,并且最后增量值必须等于1
 */
void SheelInsert(int a[], int dk)
{
    //对数组做一趟希尔插入排序。本算法是和一趟直接插入排序相比,做了以下修改:
    //  前后记录位置的增量式dk,而不是1
    for(int i=dk+1; i<=n; ++i)
        if(a[i] < a[i-dk])
        {
            int tp = r[i];
            for(int j=i-dk; j>0&&a[j]>tp; j-=dk)
                a[j+dk] = a[j];
            a[j+dk] = tp;
        }
}
void ShellSort(int a[], int delta[], int t)
{
    //按增量序列delta[0..t-1]对数组做希尔排序
    for(int i=0; i<t; ++i)
        ShellInsert(a,delta[i]);
}




/** 交换排序 **/


//冒泡


//快排 O(nlogn) 原地排序 不稳定 可能退化成冒泡
int partition(int *a,int p,int r){
    int i = p;
    for(int j=p;j<r;++j)
        if(a[j] <= a[r])
            swap(a[i++],a[j]);
    swap(a[i],a[r]);
    return i;
}
void qsort(int *a,int p,int r){
    if(p < r){
        int q = partition(a,p,r);
        qsort(a,p,q-1);
        qsort(a,q+1,r);
    }
}


/** 选择排序 **/


//简单选择排序


//堆排
int size;
void HeapAdjust(int *a,int i){
    int l = i<<1;
    int r = i<<1|1;
    int max = i;
    if(l <= size && a[l] > a[max])
        max = l;
    if(r <= size && a[r] > a[max])
        max = r;


    if(max != i){
        swap(a[i],a[max]);
        HeapAdjust(a,max);
    }
}
void build(int *a,int n){//数组为1...n,因为堆的标号是从1开始的
    size = n;
    for(int i=size>>1;i>=1;--i)
        HeapAdjust(a,i);
}
void HeapSort(int *a,int n){
    size = n;
    build(a,n);
    for(int i=n;i>=2;--i){
        swap(a[1],a[i]);
        --size;
        HeapAdjust(a,1);
    }
}


/** 归并排序
 * O(nlogn) O(n)的空间 同快排堆排比较最大优势是稳定排序
 **/


/** 基数排序
 **/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值