算法 -- 初级排序

  • 程序从标准输入中读取数据(一系列大写字母),并保存在数组中
  • 将数组的元素从小到大排序,并输出结果

模板

#!/usr/bin/python3.5

class Sort:
    def less(self, x, y):
        return x < y;

    def exch(self, sample, i, j):
        t = sample[i]
        sample[i] = sample[j]
        sample[j] = t

    def show(self, sample):
        for element in sample:
            print(element, end=' ')
        print()

    def isSorted(self, sample): 
        length = len(sample)
        for i in range(1, length):
            if self.less(sample[i], sample[i-1]):
                return False
        return True

    def sort():
        pass # 在子类中定义具体的排序算法


if __name__ == '__main__':
    # 标准输入中读取字符,并将其排序
    sample = input().split()
    # sort = Select()  使用一种算法
    sort.sort(sample)
    if sort.isSorted(sample):
        sort.show(sample)
  • N:总是表示数组的长度

选择排序

原理

选择排序:首先从数值找出一个最小元素,将它与数值中第一个元素交换;再从剩下的元素中找出最小元素,将它与数值中第二个元素交换....直到整个数值有序;

代码描述

两层循环:

  • 第一层依次遍历整个数组,假设当前为第 i 次,并将它当做最小元素 the_min
    • 第二层依次遍历 i 后面的元素,假设当前为 j ,将 j 与 the_min 比较,如果 j 小于 the_min,则 j 变成 the_min (最终 the_min 为 i ~ 到数组完的最小元素)
    • 交换 i 和 the_min 的位置,继续第一层循环

实现

class Sort:
    .......

class Select(Sort):
    def sort(self, sample):
        N = len(sample)
        for i in range(N): # 第 i 次扫描数组
            the_min = i
            for j in range(i+1, N): # 找出最小的元素
                if self.less(sample[j], sample[the_min]):
                    the_min = j
            self.exch(sample, i, the_min) 

if __name__ == '__main__':
    # 标准输入中读取字符,并将其排序
    sample = input().split()
    sort = Select()  # 使用选择排序算法
    sort.sort(sample)
    if sort.isSorted(sample):
        sort.show(sample)

/mnt/f/python $ cat data.txt
D G A B E C F
/mnt/f/python $ python3 selection.py  < data.txt
A B C D E F G

效率

假设数组的长度为 N:

  • 排序总共要交换 N 次
  • 排序总共要比较 N² / 2 次
算法 -- 初级排序_第1张图片
背景颜色代表比较次数

分析

选择排序的缺点在于:一个完全有序的数组和一个随机顺序的数组的排序时间一样长

插入排序

原理

插入排序:大循环遍历数组(1 ~ N-1)元素,内循环将当前的元素与前面的元素逐个比较,如果小于前面的元素,则交换;(左边已排序的元素总是有序 — . —)

                        D G A B E C F
                                       当前元素
1.   D - G 比较,不用交换:D G|A B E C F   - G
2.1  G - A 比较,需要交换:D A G|B E C F   - A
2.2  D - A 比较,需要交换:A D G|B E C F   - A
3.1  G - B 比较,需要交换:A D B G|E C F   - B

代码描述

两层循环:

  • 第一层依次遍历第二个元素到数组完,假设当前为 i
    • 第二层将它与前面区域的元素比较:首先,和前面相邻的元素比较,较小则交换,再与前面相邻的元素比较,小则交换,直到遇到一个
      比它大的,结束(因为前面已经有序,肯定比它小,不需要再比较);继续第一层循环

实现

class Insert(Sort):
    def sort(self, sample):
        N = len(sample)
        for i in range(1, N):
            for j in range(i, 0, -1):
                if self.less(sample[j], sample[j-1]):
                    self.exch(sample, j, j-1)
                else:
                    break  # 左边已排序的元素总是有序 — . —

if __name__ == '__main__':
    # 标准输入中读取字符,并将其排序
    sample = input().split()
    # sort = Select()
    sort = Insert()  # 使用插入排序算法
    sort.sort(sample)
    if sort.isSorted(sample):
        sort.show(sample)

分析

  • 当一个数组已经有序时,插入排序的仅需遍历一次数组(不需要进行交换)
  • 插入排序适合部分有序的数组,比如:
    • 一个有序的大数组,接上一个随机小数组
    • 数组中仅有几个元素的位置不正确
    • 数组中的每个元素距离它们的目的位置不远
  • 缺点是:每次仅交换相邻的两个元素

希尔排序

Shell 希尔排序是对插入排序的改进,(插入排序适用于部分有序的数组;缺点是只交换相邻的元素),希尔排序确定一个间隔 h,将整个数组 h 个子数组,对子数组进行插入排序;

h = 4

D G A B E C F
D ----- E
  G ----- C
    A ----- F
      B ----- 

代码描述

  • 根据数组长度 N 计算间隔 h(初始为 1),h = h * 3 + 1 ==》 1, 4, 13, 40, 121 .... N/3
  • 根据 h, 数组会被分成 h 个子数组,将子数组进行插入排序
  • 三层循环
    • 第一层逐渐缩小间隔 h :将 h 从 h 递减到 1 (h = h / 3
      • 第二层用 i 代替 h ,依次遍历 i 到数组完 (这样每次会操作一个不同的子数组 h1, h2, ..., h, h1, ....)
        • 第三层对某一个子数组进行插入排序:用 j 代替 i, 将 j 与 前面相邻的 j - h 比较,小则交换....
  • h 减至 1时,相当于对整个数组进行插入排序

代码

class Shell(Sort):
    def sort(self, sample):
        N = len(sample)
        h = 1
        while h < (N // 3):
            h = h * 3 + 1
        while h >= 1:
            for i in range(h, N):
                j = i
                while self.less(sample[j], sample[j-h]) and j >= h: # 当 j = h 时,比较 子数组最前的两个元素
                    self.exch(sample, j, j-h)
                    print(sample)
                    j -= h

            h = h // 3

完整代码 -- github

你可能感兴趣的:(算法 -- 初级排序)