写写希尔排序

2016-07-07 jude 更多博文 » 博客 » GitHub »

algorithm shell sort ruby

原文链接 http://judes.me/tech/2016/07/07/shell-sort.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


希尔排序不应该放在这个系列的,因为并不十分清楚它的原理,想要完整了解的朋友请看维基百科

下面是原理的简单解释:

原理

希尔排序是"插入排序的一种更高效的改进版本",从这个角度理解,它继承了插入排序的优点:

  • 对大体已排好序的集合有相当高的效率

解决了插入排序的一点不足:

  • 每次比较只能把待排序元素移动一位,如果待排序元素离最终位置比较远,需要多次操作

希尔排序依靠变化的比较、交换步长解决这点不足:先用较大的步长把集合整理在大体有序,最后使用步长为 1 的插入排序整理成完全有序。

联想

希尔排序的内核是插入排序,在插入排序的外面再包裹一层循环——让步长从某个初始值逐渐变小到 1 。这个初始值定为待排序集合长度的 1/3 处。

用法

#!/usr/bin/env ruby
sorted_array = SS.sort(array)

大体结构

#!/usr/bin/env ruby
class SS
  class << self
    def sort array
      return array if array.size <= 1
      step = (array.size / 3.0).ceil
      while step >= 1
        # insertion sort  
        step -= 1
      end
      array
    end
  end
end

插入排序部分

插入排序可以参考之前写过的文章,要点是对插入排序的内、外两层循环都应用可变步长

#!/usr/bin/env ruby
class SS
  class << self
    def sort array
      len = array.size
      return array if len <= 1
      step = (len / 3.0).ceil
      while step >= 1
        tag = step
        while tag < len
          inner_tag = tag
          while inner_tag >= 1 && array[inner_tag] < array[inner_tag - step]
            exchange(array, inner_tag, inner_tag - step)
            inner_tag -= step
          end
          tag += step
        end
        step -= 1
      end
      array
    end
    def exchange array, i, j
      array[i], array[j] = array[j], array[i]
    end
  end
end

完整的代码,加测试用例如下:

#!/usr/bin/env ruby

class SS
  class << self
    def sort array
      len = array.size
      return array if len <= 1
      step = (len / 3.0).ceil
      while step >= 1
        tag = step
        while tag < len
          inner_tag = tag
          while inner_tag >= 1 && array[inner_tag] < array[inner_tag - step]
            exchange(array, inner_tag, inner_tag - step)
            inner_tag -= step
          end
          tag += step
        end
        step -= 1
      end
      array
    end
    def exchange array, i, j
      array[i], array[j] = array[j], array[i]
    end
  end
end

if __FILE__ == $0

  require 'test/unit'

  class TestSS < Test::Unit::TestCase
    def test_0
      input = []
      expected = []
      assert_equal SS.sort(input), expected, 'empty array not equal'
    end
    def test_1_0
      input = [0]
      expected = [0]
      assert_equal SS.sort(input), expected, 'one item array not equal'    
    end
    def test_1_1
      input = [1]
      expected = [1]
      assert_equal SS.sort(input), expected, 'one item array not equal'    
    end
    def test_2_0
      input = [0,1]
      expected = [0,1]
      assert_equal SS.sort(input), expected, 'two items array not equal'    
    end
    def test_2_1
      input = [1,0]
      expected = [0,1]
      assert_equal SS.sort(input), expected, 'two items array not equal'    
    end
    def test_2_2
      input = [1,1]
      expected = [1,1]
      assert_equal SS.sort(input), expected, 'two items array not equal'    
    end
    def test_3_0
      input = [0,1,2]
      expected = [0,1,2]
      assert_equal SS.sort(input), expected, 'three items array not equal'    
    end
    def test_3_1
      input = [0,2,1]
      expected = [0,1,2]
      assert_equal SS.sort(input), expected, 'three items array not equal'    
    end
    def test_3_2
      input = [2,1,0]
      expected = [0,1,2]
      assert_equal SS.sort(input), expected, 'three items array not equal'    
    end
    def test_3_3
      input = [2,1,1]
      expected = [1,1,2]
      assert_equal SS.sort(input), expected, 'three items array not equal'    
    end
    def test_3_4
      input = [1,1,1]
      expected = [1,1,1]
      assert_equal SS.sort(input), expected, 'three items array not equal'    
    end
    def test_4_0
      input = [0,1,2,3]
      expected = [0,1,2,3]
      assert_equal SS.sort(input), expected, 'four items array not equal'    
    end
    def test_4_1
      input = [3,1,2,0]
      expected = [0,1,2,3]
      assert_equal SS.sort(input), expected, 'four items array not equal'    
    end
    def test_4_2
      input = [3,1,2,1]
      expected = [1,1,2,3]
      assert_equal SS.sort(input), expected, 'four items array not equal'    
    end
    def test_10_0
      input = [9,8,7,6,5,4,3,2,1,0]
      expected = [0,1,2,3,4,5,6,7,8,9]
      assert_equal SS.sort(input), expected, 'four items array not equal'    
    end
    def test_10_1
      input = [9,5,7,3,8,4,6,1,2,0]
      expected = [0,1,2,3,4,5,6,7,8,9]
      assert_equal SS.sort(input), expected, 'four items array not equal'    
    end
  end
end