天天看點

用matplotlib動畫功能,一幀一幀的錄制排序算法

1 matplotlib繪制動畫

matplotlib

是python中最經典的繪圖包,裡面

animation

子產品能繪制動畫。

首先導入小例子使用的子產品:

from matplotlib import pyplot as plt
from matplotlib import animation
from random import randint, random
           

複制

生成資料,

frames_count

是幀的個數,

data_count

每個幀的柱子個數

class Data:
    data_count = 32
    frames_count = 2

    def __init__(self, value):
        self.value = value
        self.color = (0.5, random(), random()) #rgb

    # 造資料
    @classmethod
    def create(cls):
        return [[Data(randint(1, cls.data_count)) for _ in range(cls.data_count)]
                for frame_i in range(cls.frames_count)]
           

複制

繪制動畫:

animation.FuncAnimation

函數的回調函數的參數

fi

表示第幾幀,注意要調用

axs.cla()

清除上一幀。

def draw_chart():
    fig = plt.figure(1, figsize=(16, 9))
    axs = fig.add_subplot(111)
    axs.set_xticks([])
    axs.set_yticks([])

    # 生成資料
    frames = Data.create()

    def animate(fi):
        axs.cla()  # clear last frame
        axs.set_xticks([])
        axs.set_yticks([])
        return axs.bar(list(range(Data.data_count)),        # X
                       [d.value for d in frames[fi]],       # Y
                       1,                                   # width
                       color=[d.color for d in frames[fi]]  # color
                       )
    # 動畫展示
    anim = animation.FuncAnimation(fig, animate, frames=len(frames))
    plt.show()


draw_chart()
           

複制

用matplotlib動畫功能,一幀一幀的錄制排序算法

2 排序算法的動畫展示

學會第一部分如何制作動畫後,可将此技術應用于排序算法調整過程的動态展示上。

首先生成測試使用的資料,待排序的資料個數至多

20個

,待排序序列為

random_wait_sort

,注意是随機序列。為每個值賦一個顔色值,這個由

random_rgb

負責:

data_count = 20  # here, max value of data_count is 20

random_wait_sort = [12, 34, 32, 24, 28, 39, 5,
                    22, 11, 25, 33, 32, 1, 25, 3, 8, 7, 1, 34, 7]

random_rgb = [(0.5, 0.811565104942967, 0.11211028937187217),
              (0.5, 0.5201323831224014, 0.6660999602342474),
              (0.5, 0.575976663060455, 0.17788242607567772),
              (0.5, 0.6880174797416493, 0.43581701833249353),
              (0.5, 0.4443131322001743, 0.6993600264279745),
              (0.5, 0.5538835821863523, 0.889276053938713),
              (0.5, 0.4851681185146841, 0.7977608586163772),
              (0.5, 0.3886717808488436, 0.09319137949618972),
              (0.5, 0.8952456581687489, 0.8282376936934484),
              (0.5, 0.16360202854998007, 0.4538892160157194),
              (0.5, 0.23233400128809478, 0.8544141586189615),
              (0.5, 0.5224648797546528, 0.8194014475829123),
              (0.5, 0.49396099968405016, 0.47441724394796825),
              (0.5, 0.12078104526714728, 0.7715022079860492),
              (0.5, 0.19428498518228154, 0.08174917157481443),
              (0.5, 0.6058698403873457, 0.6085936584142663),
              (0.5, 0.7801178568951216, 0.6414767240649862),
              (0.5, 0.4768865661174162, 0.3889866229610085),
              (0.5, 0.4301945092238082, 0.961688141676841),
              (0.5, 0.40496648895289855, 0.24234095882836093)]


           

複制

再封裝一個簡單的資料對象

Data

class Data:
    def __init__(self, value, rgb):
        self.value = value
        self.color = rgb

    # 造資料
    @classmethod
    def create(cls):
        return [Data(val, rgb) for val, rgb in zip(random_wait_sort[:data_count],
                                                   random_rgb[:data_count])]
           

複制

3 先拿冒泡實驗

一旦發生調整,我們立即儲存到幀清單

frames

中,注意此處需要

deepcopy

:

# 冒泡排序
def bubble_sort(waiting_sort_data):
    frames = [waiting_sort_data]
    ds = copy.deepcopy(waiting_sort_data)
    for i in range(data_count-1):
        for j in range(data_count-i-1):
            if ds[j].value > ds[j+1].value:
                ds[j], ds[j+1] = ds[j+1], ds[j]
                frames.append(copy.deepcopy(ds))
    frames.append(ds)
    return frames
           

複制

實驗結果一共得到

150

幀資料,其前

50

幀:

用matplotlib動畫功能,一幀一幀的錄制排序算法

完整動畫示範:

用matplotlib動畫功能,一幀一幀的錄制排序算法

4 快速排序

先上代碼,比較經典,值得回味:

def quick_sort(data_set):
    frames = [data_set]
    ds = copy.deepcopy(data_set)

    def qsort(head, tail):
        if tail - head > 1:
            i = head
            j = tail - 1
            pivot = ds[j].value
            while i < j:
                if ds[i].value > pivot or ds[j].value < pivot:
                    ds[i], ds[j] = ds[j], ds[i]
                    frames.append(copy.deepcopy(ds))
                if ds[i].value == pivot:
                    j -= 1
                else:
                    i += 1
            qsort(head, i)
            qsort(i+1, tail)

    qsort(0, data_count)
    frames.append(ds)
    return frames
           

複制

快速排序算法對輸入為随機的序列優勢往往較為明顯,同樣的輸入資料,它隻需要

24

幀就能完成排序:

用matplotlib動畫功能,一幀一幀的錄制排序算法

5 選擇排序

選擇排序和堆排序都是選擇思維,但是性能卻不如堆排序:

def selection_sort(data_set):
    frames = [data_set]
    ds = copy.deepcopy(data_set)
    for i in range(0, data_count-1):
        for j in range(i+1, data_count):
            if ds[j].value < ds[i].value:
                ds[i], ds[j] = ds[j], ds[i]
                frames.append(copy.deepcopy(ds))

    frames.append(ds)
    return frames
           

複制

同樣的輸入資料,它完成排序需要

108

幀:

用matplotlib動畫功能,一幀一幀的錄制排序算法

動畫展示如下,每輪會從未排序的清單中,挑出一個最小值,放到已排序序列後面。

用matplotlib動畫功能,一幀一幀的錄制排序算法

6 堆排序

堆排序大大改進了選擇排序,邏輯上使用二叉樹,先建立一個大根堆,然後根節點與未排序序列的最後一個元素交換,重新對未排序序列建堆。

完整代碼如下:

def heap_sort(data_set):
    frames = [data_set]
    ds = copy.deepcopy(data_set)

    def heap_adjust(head, tail):
        i = head * 2 + 1  # head的左孩子
        while i < tail:
            if i + 1 < tail and ds[i].value < ds[i+1].value:  # 選擇一個更大的孩子
                i += 1
            if ds[i].value <= ds[head].value:
                break
            ds[head], ds[i] = ds[i], ds[head]
            frames.append(copy.deepcopy(ds))
            head = i
            i = i * 2 + 1

    # 建立一個最大堆,從最後一個父節點開始調整
    for i in range(data_count//2-1, -1, -1):
        heap_adjust(i, data_count)
    for i in range(data_count-1, 0, -1):
        ds[i], ds[0] = ds[0], ds[i]  # 把最大值放在位置i處
        heap_adjust(0, i)  # 從0~i-1進行堆調整
    frames.append(ds)
    return frames
           

複制

堆排序的性能也比較優秀,完成排序需要51次調整:

用matplotlib動畫功能,一幀一幀的錄制排序算法

7 綜合

依次調用以上常見的4種排序算法,分别儲存所有幀和html檔案。

waiting_sort_data = Data.create()
for sort_method in [bubble_sort, quick_sort, selection_sort, heap_sort]:
    frames = sort_method(waiting_sort_data)
    draw_chart(frames, file_name='%s.html' % (sort_method.__name__,))
           

複制

擷取以上完整代碼、所有資料檔案、結果檔案的方法:

  1. 關于下方公衆号
  2. 回複:

    sort