插入排序和希尔排序

1 插入排序

1.1 插入排序思想

插入排序是一种简单直观的排序方法。它将待排序的元素根据关键码的大小,逐个插入到已排序的序列中,直至所有元素都插入完毕,从而形成一个新的有序序列。

1.2 插入排序步骤

具体步骤如下:

  1. 初始状态:将第一个元素视为已排序部分,其余元素视为未排序部分。
  2. 逐步插入:从未排序部分取出第一个元素,插入到已排序部分的适当位置。这个过程需要从后向前扫描已排序部分,找到合适的位置进行插入。
  3. 重复步骤:重复上述步骤,直到所有元素都插入到已排序部分中。

插入排序的工作原理类似于整理扑克牌时,将每张新牌插入到已经排好序的牌中。它的时间复杂度在最坏情况下为O(n^2),但在数据接近有序时表现较好,时间复杂度为O(n)。

1.3 插入排序代码

void InsertSort(int* a, int n)
{
    // 遍历数组,从第一个元素到倒数第二个元素
    for (int i = 0; i < n-1; i++)
    {
        int end = i; // 当前已排序部分的最后一个元素的索引
        int temp = a[end + 1]; // 保存未排序部分的第一个元素的值

        // 从已排序部分的最后一个元素开始,向前扫描
        while (end >= 0)
        {
            // 如果temp小于当前已排序部分的元素a[end]
            if (temp < a[end])
            {
                a[end + 1] = a[end]; // 将a[end]向后移动一个位置
                end--; // 将end减1
            }
            else
            {
                break; // 如果temp不小于a[end],跳出循环
            }
        }
        a[end + 1] = temp; // 将temp插入到已排序部分的适当位置
    }
}

2 希尔排序

2.1 希尔排序思想

希尔排序,也被称为“缩小增量排序”,是一种基于插入排序的算法。它的主要思想是通过将原始列表分割成多个子列表,然后对每个子列表进行直接插入排序,来提高插入排序的效率。

2.2 希尔排序步骤

希尔排序的具体步骤如下:

  1. 初始化:首先选择一个间隔(或增量)序列,最常见的选择是以2为底数的幂递减序列,例如:N/2, N/4, ..., 1,其中N是数组的长度。

  2. 分组与排序:对于每一个间隔值,将数组分为几个子序列,每个子序列由相隔该间隔的所有元素组成。然后,对这些子序列分别使用插入排序进行排序。

    • 对于第一个间隔值,将数组分割成若干个子序列,每个子序列包含所有相隔这个间隔的元素。例如,如果间隔是5,那么子序列就是第一个、第六个、第十一个等元素,第二个、第七个、第十二个等元素,以此类推。

    • 然后,对每个子序列使用插入排序进行排序。

  3. 重复步骤2:减小间隔,继续对新的间隔下的子序列进行插入排序,直到间隔值减小至1。

  4. 最终排序:当间隔值为1时,整个数组作为一个子序列进行最后一次插入排序,此时,由于之前的步骤已经使得数组部分有序,所以这一步的插入排序效率较高。

通过这样的步骤,希尔排序能够在较短的时间内完成对大规模数据的排序,特别是在数据部分有序的情况下,其性能优势更加明显。

2.3 希尔排序代码

void ShellSort(int* a, int n)
{
    int p = n; // 初始化增量p为数组长度
    while (p > 1)
    {
        p = p / 3 + 1; // 缩小增量,使用增量序列
        for (int i = 0; i < n - p; ++i)
        {
            int end = i; // 当前已排序部分的最后一个元素的索引
            int temp = a[end + p]; // 保存未排序部分的第一个元素的值

            // 从已排序部分的最后一个元素开始,向前扫描
            while (end >= 0)
            {
                // 如果temp小于当前已排序部分的元素a[end]
                if (temp < a[end])
                {
                    a[end + p] = a[end]; // 将a[end]向后移动一个位置
                    end -= p; // 将end减去增量p
                }
                else
                {
                    break; // 如果temp不小于a[end],跳出循环
                }
            }
            a[end + p] = temp; // 将temp插入到已排序部分的适当位置
        }
    }
}
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值