希尔排序算法代码详解(附插入排序代码)

1959年Shell发明,第一个突破O(n2)的排序算法,是直接插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
希尔排序的大致思路是把数组的元素按照一定的间隔进行逻辑分组,分组后针对每一组进行插入排序。并且渐渐减小间隔,随着间隔的缩小,整个数组就变得越来越有序。这个间隔叫做希尔增量。
希尔排序的时间复杂度难以测算,大概是O(n^(1.3—2))这么一个范围。
希尔排序是一种不稳定的排序算法。

下面是希尔排序的代码演示,所有的注释都在代码里。
为了辅助理解,我在文末加入了插入排序的代码和注释,建议两个排序配合着看,看上几遍基本就懂了

public static void ShellSort(int[] array)
        {
           int n = array.Length;
            int inc;//希尔增量
            //这里采用朴素希尔增量,就是每次增量都是原来的一半,直到增量为1为止
            for (inc = n / 2; inc >= 1; inc = inc / 2)
            {//每一次循环都通过不断缩短增量达到排序的效果
                //在一次循环内,inc的值是固定的
                //下面的内容和插入排序的原理是一样的,只不过每个待排序元素的间隔是inc
                for (int i = inc; i < n; i++)
                {//i为什么是从inc开始,而不是从0开始?
                 //因为插入排序中把排序元素分为两组,A组为已排好序的,B组为未排好序要插入的
                 //A组开始时往往是第一个元素(0),那么B组的第一个元素就是整个待拍序列的第二个元素了(inc)
                    int temp = array[i];//temp存储要插入的值
                    int j;
                    for (j = i-inc; j >= 0 && array[j] > temp; j = j - inc)
                    {//j从i-inc开始往前遍历,每一步的距离是inc
                        array[j+inc] = array[j];如果当前遍历到的元素(这里说的遍历到的元素是(array[j])比待插入元素temp小,
                                                  //这个元素往后移动一位,后边的元素被元素覆盖
                                                  //一旦不满足条件,1.说明要么遍历到元素比temp小,这个时候所有比temp大的元素都后移完了
                                                  //2.遍历到头了,此时第一个元素就是要插入的地方
                    }
                    array[j+inc] = temp;
                                    //那么此时array[j+inc]也就是要插入的地方,把temp插入进去
                }
            }
        }

下边直接插入排序的代码:

			//插入排序,时间复杂度为O(n²),且是稳定的排序算法
 public static void InsertSort(int[] array)
        {
            //将数组分为两组,一组是已经排好序的(我们称为A组)另一组是还没有排好序的(称为B组)
            //在数组的刚开始,我们把数组的第一个元素array[0]将入A组,剩下的放入B组
            //从数组的第二个元素开始,逐步与A组的元素相比较(从A组的后边往前边比较)
            for (int i = 1; i < array.Length; i++)
            {
                int temp = array[i];//定义temp存储要插入的值
                int j;
                for (j = i-1; j>=0 && array[j]>temp; j--)//将temp逐步与A组的元素(array[j])相比较(从A组的后边往前边比较)
                {
                    array[j + 1] = array[j];//如果A组中的值大于要比较的值,A组就整个数组往后移动一个位置
                    //这样的移动当然会覆盖A组后边的那个元素的值,
                    //但是别忘了A组后边的那个元素,是要插入的值原本的位置,
                    //所以往后移动只会覆盖这个位置,不会对整个数组产生影响
                }
                array[j + 1] = temp;
                //退出上边的for循环有两种可能
                //1.在A组中找到了一个比temp小的元素,那么temp就可以插入在这个元素的后边,即array[j+1]的位置
                //2.全部遍历完毕,在A组中没有找到比这个temp更小的元素,此时应该把temp插入在A组的最前边(array[0])
                //由于此时j退出循环时候的值为-1,array[j+1]为要插入的位置
            }
        }

可以看出的是,希尔排序在第一个for循环之后的代码基本就和插入排序一样了,所谓的区别只是插排中的"1"变成了inc而已

你可能感兴趣的:(排序算法专栏,冒泡插入堆,快速排序,归并排序,希尔排序,桶排序,算法,插入排序)