排序1

排序的基本概念

排序:就是重新排列表中的元素,使得表中的元素满足按关键字递增或者递减的过程。
输入:n个记录 R1,R2,,Rn ,对应的关键字为 k1,k2,,kn
输出:输入的序列的一个重排 R1,R2,,Rn ,使得 k1k2kn
算法的稳定性:如果待排序的表中有两个元素 Ri,Rj ,其对应的关键字 key1=key2 ,且在排序前 Ri Rj 前面,如果使用某一排序算法后, Ri 仍然在 Rj 前面,则成这个排序算法是稳定的。否则成排序算法是不稳定的。需要注意的是,算法是否具有稳定性并不能衡量一个算法的优势。它主要是对算法的性质进行描述。

根据数据元素是否完全在在内存中,可将排序算法分为两类:内部排序是指在排序期间元素全部存放在内存中的排序; 外部排序是指在排序期间元素无法全部同时存放在内存中,必须在排序的过程中根据要求不断地在内,外存之间移动的排序。

插入排序

插入排序的基本思想在于每次将一个待排序的记录,按其关键字体的大小插入到前面已经排好序的子序列中,直到全部记录插入完成。

直接插入排序

假如待排序序列 L[1n] 在某次排序的过程中的某一时刻的状态如下:
(有序序列) L[1i1] L(i) L[i+1n] (无序序列)
为了实现将元素 L(i) 插入到已有序的子序列 L[1i1] 中,需要执行以下操作:

  1. 查找出 L(i) L[1i1] 中的插入位置 k

  2. L[ki1]中的所有元素全部后移一个位置。

  3. L(i) 复制到 L(k)

    为了实现对 L[1n] 的排序,可以将 L(2)L(n) 依次插入到前面已排好序的子序列中,初始假定 L[1] 是一个已经排好序的子序列。上述操作执行 n1 次就能得到一个有序的表。

void InsertSort(int A[],int n)
{
    int i,j;
    for (i=2;i<=n;i++){  //依次将A[2]~A[n]插入到前面排好序序列
        if(A[i] < A[i-1]){
            A[0] = A[i];
            for(j=i-1;A[0]<A[j];--j) //从后往前查找带插入位置
                A[j+1] = A[j]; //向后挪位
            A[j+1] = A[0];
        }
    }
}

空间效率:仅使用了常数个辅助单元,因而空间复杂度 O(1)
时间效率 : 最好的情况下,表中元素已经有序,此时每次插入都只需比较一次而不需要移动,因而时间复杂度为 O(n) 。最坏情况下,表中元素刚好逆序,总的比较次数达到最大 ni=2i ,总移动次数也达到最大,为 ni=2(i+1) 。平均情况下,待排序的元素是随机的,直接插入排序的时间复杂度为 O(n2)
稳定性:由于每次插入元素时总是从后向前先比较再移动,所以不会出现形相对位置发生变化的情况,所以直接插入排序是一个稳定的排序方法。

折半插入排序

在之前的直接插入排序的时候 L[1i1] 是有序的,在找插入位置的时候可以使用二分查找来优化这个查找的过程。于是对直接插入排序算法做如下改进。

void BinaryInsertSort(int A[],int n)
{
    int i,j,low,mid,high;
    for (i=2;i<=n;i++){  //依次将A[2]~A[n]插入到前面排好序序列
        A[0] = A[i];
        low = 1,high=i-1;
        while(low<=high){
            mid = (low+high)/2;
            if(A[mid] > A[0]) high = mid - 1; //插找左半子表
            else
                low = mid+1; //查找右半子表
        }
        for(j=i-1;j>=high+1;--j)
            A[j+1] = A[j];
        A[high+1] = A[0];
    }
}

折半插入排序只是减少了元素的比较次数,约为 O(nlogn) ,该比较次数与待排序表的初始状态无关,仅取决于表中的元素个数 n ,时间复杂度仍然为O(n2),它也是一个稳定的排序方法。

希尔排序

希尔排序的基本思想是:先将待排序表分割成若干个形如 L[i+1,i+d,i+2d,i+kd] 的“特殊”子表,分别进行直接插入排序,当整个表中的元素呈“基本有序”时,再对全体记录进行一次直接插入排序。算法过程如下:

  1. 先取一个小于n的步长 d1 ,把表中全部记录分成 d1 个组,所有距离为 d1 的倍数的记录放在同一个组中,在各组进行直接插入排序。
  2. 选取第二个步长 d2<d1 ,重复上述过程,直到所取到的 d1=1 ,再进行直接插入排序。
    代码如下:
void ShellSort(int A[],int n)
{
    int dk,i,j;
    for(dk=n/2;dk>=1;dk=dk/2){
        for(i=dk+1;i<=n;i++){
            if(A[i]<A[i-dk]){
                A[0] = A[i];
                for(j=i-dk;j>0&&A[0]<A[j];j-=dk)
                    A[j+dk] = A[j];
                A[j+dk] = A[0];
            }
        }
    }
}

空间效率: O(1)
时间效率:当n在某个特定的范围内希尔排序的时间复杂度约为 O(n1.3) ,在最坏的情况下时间复杂度为 O(n2)
稳定性:当相同关键字的记录被划分到不同的子表时,可能会改变它们之间的相对次序,因此希尔排序是不稳定的排序方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值