排序 - 希尔排序 Shell Sort

Shell Sort 可以看作改进版的 Insertion Sort。

希尔排序

插入排序的问题在于,如果右侧的数据全局来看比较小的话,insert-bubble 过程中不能尽早地「提前终止」。 这种情况也可以认为是较大的数据所在的位置比较靠近左边。 如果可以尽早地把那些较大的数据移动到右边的话,可以促使「提前终止」的尽早发生。

这可以通过尽早比较左侧的较大数据和右侧的较小数据,并交换它们的位置来实现。

以一定的间隔抽样检查,是很自然的思路。在此思路基础上,可以把原数组看作是多个子数组的组合。

分别对这多个子数组进行排序,之后整个数组的布局会更有利于整个数组的排序。

希尔排序巧妙地利用逐步减小间隔的办法,把子数组的划分和排序,以及整个数组的排序,统一在一起。希尔排序是基于插入排序的——插入排序有可以提前终止的特性。

proc insert-sort-step {*list step} {
  for {set i 0} {($i+$step)<n} {incr i $step} {
    insert-bubble &list 0 $i+$step $step
  }
}

proc insert-bubble {&list start end} {
  upvar ${&list} list
  for {
    set prev [expr $end-$step]     ;# 间隔序列
  } {$prev>$start} {
    incr prev -$step
    incr end  -$step
  } {
    if { [lindex $list $end] < [lindex $list $prev] } {
      list-swap &list $prev $end     ;# 交换
    } else {
      return                         ;# 提前终止
    }
  }
}