27.希尔排序

  1. 27.排序-希尔排序
    1. 27.1 知识点
      1. 希尔排序的基本原理
      2. 代码实现
        1. 前提条件
        2. 希尔排序实例
      3. 总结
    2. 27.2 知识点代码

27.排序-希尔排序


27.1 知识点

希尔排序的基本原理

  • 希尔排序是插入排序的升级版,必须先掌握插入排序。
  • 希尔排序的原理
    • 将整个待排序序列分割成若干子序列。
    • 分别对子序列进行插入排序。

总而言之,希尔排序对插入排序的升级主要就是加入了一个步长的概念:

  • 通过步长每次可以把原序列分为多个子序列。
  • 对子序列进行插入排序。
  • 在极限情况下可以有效降低普通插入排序的时间复杂度,提升算法效率。

通俗理解:

  • 每轮确定一个步长,这个步长决定将当前要排序的元素分成多少个子数组。
  • 在子数组中分别进行插入排序。
  • 步长逐渐减小,直到等于1,就可以说不分组了,最后再对整个数组进行插入排序。

代码实现

前提条件

  • 学习希尔排序的前提条件:先掌握插入排序。

希尔排序实例

实现升序排序:[8, 7, 1, 5, 4, 2, 6, 3, 9],将大的元素放在最后面。

// 创建无序数组
int[] array = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };

// 希尔排序核心代码
// 第一步:实现插入排序
for (int step = array.Length / 2; step > 0; step /= 2)
{
    // 第二步:确定步长

    // 第三步:执行插入排序
    for (int i = step; i < array.Length; i++)
    {
        int nowSortNum = array[i];
        int sortIndex = i - step;

        while (sortIndex >= 0 && array[sortIndex] > nowSortNum)
        {
            array[sortIndex + step] = array[sortIndex];
            sortIndex -= step;
        }

        array[sortIndex + step] = nowSortNum;
    }
}

// 打印输出
for (int i = 0; i < array.Length; i++)
{
    Console.WriteLine(array[i]);
    // 1
    // 2
    // 3
    // 4
    // 5
    // 6
    // 7
    // 8
    // 9
}

总结

  • 基本原理
    • 设置步长。
    • 步长不停缩小,直到为1排序后结束。
  • 具体排序方式
    • 插入排序原理。
  • 套路写法
    • 三层循环。
    • 一层获取步长。
    • 一层获取未排序区元素。
    • 一层找到合适位置插入。
  • 注意事项
    • 步长确定后,会将所有子序列进行插入排序。

27.2 知识点代码

using System;

namespace Lesson26_希尔排序
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("希尔排序");

            #region 知识点一 希尔排序的基本原理

            //希尔排序是
            //插入排序的升级版
            //必须先掌握插入排序

            //希尔排序的原理
            //将整个待排序序列
            //分割成为若干子序列
            //分别进行插入排序

            //总而言之
            //希尔排序对插入排序的升级主要就是加入了一个步长的概念
            //通过步长每次可以把原序列分为多个子序列
            //对子序列进行插入排序
            //在极限情况下可以有效降低普通插入排序的时间复杂度
            //提升算法效率

            //通俗理解
            //每轮确定一个步长 这个步长决定把当前要排序元素分成多少个子数组
            //在子数组分别进行插入排序
            //步长会逐渐减小 直到等于1 就可以说不分组了
            //最后再对整个数组进行插入排序

            #endregion

            #region 知识点二 代码实现

            //学习希尔排序的前提条件 
            //先掌握插入排序

            //希尔排序实例

            //实现升序排序 8 7 1 5 4 2 6 3 9 把大的元素放在最后面

            //创建无序数组
            int[] array = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };

            //希尔排序核心代码

            //第一步:实现插入排序
            ////第一层循环 是用来取出未排序区中的元素的
            //for (int i = 1; i < array.Length; i++)
            //{
            //    //得出未排序区的元素
            //    int nowSortNum = array[i];
            //    //得出排序区中最后一个元素索引
            //    int sortIndex = i - 1;
            //    //进入条件
            //    //首先排序区中还有可以比较的 >=0
            //    //排序区中元素 满足交换条件 升序就是排序区中元素要大于未排序区中元素
            //    while (sortIndex >= 0 &&
            //        array[sortIndex] > nowSortNum)
            //    {
            //        array[sortIndex + 1] = array[sortIndex];
            //        --sortIndex;
            //    }
            //    //找到位置过后 真正的插入 值
            //    array[sortIndex + 1] = nowSortNum;
            //}
            ////打印输出
            //for (int i = 0; i < array.Length; i++)
            //{
            //    Console.WriteLine(array[i]);
            //}

            //第二步:确定步长
            //基本规则:每次步长变化都是/2
            //一开始步长 就是数组的长度/2
            //之后每一次 都是在上一次的步长基础上/2
            //结束条件是 步长 <=0 
            //1.第一次的步长是数组长度/2  所以:int step = array.length/2
            //2.之后每一次步长变化都是/2  索引:step /= 2
            //3.最小步长是1  所以:step > 0
            for (int step = array.Length / 2; step > 0; step /= 2)
            {
                //注意:每次得到步长后 会把该步长下所有序列都进行插入排序

                //第三步:执行插入排序

                //i=1代码 相当于 代表取出来的未排序区的第一个元素
                //for (int i = 1; i < array.Length; i++)

                //i=step 相当于 代表取出来的未排序区的第一个元素
                for (int i = step; i < array.Length; i++)
                {
                    //得出未排序区的元素
                    int nowSortNum = array[i];

                    //得出排序区中最后一个元素索引
                    //int sortIndex = i - 1;
                    //i-step 代表和子序列中 已排序区元素一一比较
                    int sortIndex = i - step;

                    //进入条件
                    //首先排序区中还有可以比较的 >=0
                    //排序区中元素 满足交换条件 升序就是排序区中元素要大于未排序区中元素
                    while (sortIndex >= 0 &&
                        array[sortIndex] > nowSortNum)
                    {
                        //+1代表当前比较的对象往后移1个位置 代表整个序列中的下一个位置
                        //array[sortIndex + 1] = array[sortIndex];
                        //+step代表当前比较的对象往后移步长个位置 代表子序列中的下一个位置
                        array[sortIndex + step] = array[sortIndex];

                        //往前移一个单位 准备下次的比较 
                        //--sortIndex;
                        //往前移一个步长单位 准备下次的比较
                        sortIndex -= step;
                    }

                    //找到位置过后 往前一个位置的插入值
                    //array[sortIndex + 1] = nowSortNum;
                    //找到位置过后 往前一个步长位置的插入值
                    array[sortIndex + step] = nowSortNum;
                }
            }

            //打印输出
            for (int i = 0; i < array.Length; i++)
            {
                Console.WriteLine(array[i]);
                //1
                //2
                //3
                //4
                //5
                //6
                //7
                //8
                //9
            }

            #endregion

            #region 知识点三 总结
            //基本原理
            //设置步长
            //步长不停缩小
            //到1排序后结束

            //具体排序方式
            //插入排序原理

            //套路写法
            //三层循环
            //一层获取步长
            //一层获取未排序区元素
            //一层找到合适位置插入

            //注意事项
            //步长确定后
            //会将所有子序列进行插入排序
            #endregion
        }
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏