Matplotlib可视化快速排序算法:动态展示排序过程

Matplotlib可视化快速排序算法:动态展示排序过程

参考:Visualization of Quick sort using Matplotlib

快速排序是一种高效的排序算法,而Matplotlib是Python中强大的数据可视化库。本文将详细介绍如何使用Matplotlib来可视化快速排序算法的执行过程,让读者能够直观地理解算法的工作原理。我们将从快速排序算法的基本概念开始,逐步深入到如何使用Matplotlib创建动态可视化效果,最后探讨一些高级技巧和优化方法。

1. 快速排序算法简介

快速排序是一种分治算法,其基本思想是:

  1. 选择一个基准元素(pivot)
  2. 将数组分为两部分,小于基准的元素放在左边,大于基准的元素放在右边
  3. 对左右两部分递归地应用快速排序

让我们先来看一个简单的快速排序实现:

import random

def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)

# 示例使用
numbers = [3, 6, 8, 10, 1, 2, 1]
print("Sorted array:", quick_sort(numbers))
print("Visit how2matplotlib.com for more information")

Output:

Matplotlib可视化快速排序算法:动态展示排序过程

这个简单的实现展示了快速排序的核心思想。接下来,我们将探讨如何使用Matplotlib来可视化这个过程。

2. Matplotlib基础

在开始可视化快速排序之前,我们需要了解Matplotlib的基本用法。Matplotlib是一个强大的Python绘图库,可以创建各种静态、动态和交互式可视化。

以下是一个简单的Matplotlib示例:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure(figsize=(8, 6))
plt.plot(x, y, label='sin(x)')
plt.title('Simple Matplotlib Example')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.text(5, 0.5, 'Visit how2matplotlib.com', fontsize=12)
plt.show()

Output:

Matplotlib可视化快速排序算法:动态展示排序过程

这个例子展示了如何创建一个简单的线图。我们将使用类似的技术来可视化快速排序过程。

3. 准备数据结构

为了可视化快速排序,我们需要一个数据结构来跟踪排序过程中的每一步。我们可以使用一个列表来存储每一步的数组状态:

def quick_sort_steps(arr):
    steps = [arr.copy()]

    def partition(low, high):
        pivot = arr[high]
        i = low - 1
        for j in range(low, high):
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
                steps.append(arr.copy())
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        steps.append(arr.copy())
        return i + 1

    def quick_sort_recursive(low, high):
        if low < high:
            pi = partition(low, high)
            quick_sort_recursive(low, pi - 1)
            quick_sort_recursive(pi + 1, high)

    quick_sort_recursive(0, len(arr) - 1)
    return steps

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
sorting_steps = quick_sort_steps(arr)
print("Number of steps:", len(sorting_steps))
print("Visit how2matplotlib.com for more information")

Output:

Matplotlib可视化快速排序算法:动态展示排序过程

这个函数返回一个列表,包含了排序过程中每一步的数组状态。我们将使用这些数据来创建可视化。

4. 创建静态可视化

首先,让我们创建一个静态的可视化,展示排序过程中的某一步:

import matplotlib.pyplot as plt

def visualize_step(arr, step):
    plt.figure(figsize=(10, 6))
    plt.bar(range(len(arr)), arr, color='skyblue')
    plt.title(f'Quick Sort Step {step}')
    plt.xlabel('Index')
    plt.ylabel('Value')
    for i, v in enumerate(arr):
        plt.text(i, v, str(v), ha='center', va='bottom')
    plt.text(len(arr)/2, max(arr), 'Visit how2matplotlib.com', ha='center', va='bottom')
    plt.show()

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
sorting_steps = quick_sort_steps(arr)
visualize_step(sorting_steps[0], 0)  # 显示初始状态

这个函数创建了一个条形图,展示了数组在特定步骤的状态。每个条形的高度代表数组中的值。

5. 创建动画可视化

现在,让我们使用Matplotlib的动画功能来创建一个动态的可视化:

import matplotlib.pyplot as plt
import matplotlib.animation as animation

def animate_quick_sort(sorting_steps):
    fig, ax = plt.subplots(figsize=(10, 6))
    bar_rects = ax.bar(range(len(sorting_steps[0])), sorting_steps[0], align="edge")

    ax.set_xlim(0, len(sorting_steps[0]))
    ax.set_ylim(0, int(1.1 * max(sorting_steps[0])))

    text = ax.text(len(sorting_steps[0])/2, max(sorting_steps[0]), '', ha='center', va='bottom')
    ax.text(len(sorting_steps[0])/2, max(sorting_steps[0])*1.1, 'Visit how2matplotlib.com', ha='center', va='bottom')

    iteration = [0]
    def animate(frame):
        for rect, h in zip(bar_rects, sorting_steps[frame]):
            rect.set_height(h)
        iteration[0] += 1
        text.set_text(f"Step: {iteration[0]}")
        return bar_rects + [text]

    anim = animation.FuncAnimation(
        fig, animate, frames=len(sorting_steps), interval=500, blit=True, repeat=False
    )

    plt.show()

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
sorting_steps = quick_sort_steps(arr)
animate_quick_sort(sorting_steps)

这个函数创建了一个动画,展示了快速排序的整个过程。每一帧代表一个排序步骤,条形图的高度随着排序的进行而变化。

6. 添加颜色编码

为了更好地理解快速排序的过程,我们可以添加颜色编码。例如,我们可以用不同的颜色来标识pivot元素、已排序和未排序的部分:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

def quick_sort_steps_with_pivot(arr):
    steps = []
    pivots = []

    def partition(low, high):
        pivot = arr[high]
        i = low - 1
        for j in range(low, high):
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
                steps.append(arr.copy())
                pivots.append((high, low, high))
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        steps.append(arr.copy())
        pivots.append((i + 1, low, high))
        return i + 1

    def quick_sort_recursive(low, high):
        if low < high:
            pi = partition(low, high)
            quick_sort_recursive(low, pi - 1)
            quick_sort_recursive(pi + 1, high)

    steps.append(arr.copy())
    pivots.append((-1, 0, len(arr) - 1))
    quick_sort_recursive(0, len(arr) - 1)
    return steps, pivots

def animate_quick_sort_with_color(sorting_steps, pivots):
    fig, ax = plt.subplots(figsize=(10, 6))
    bar_rects = ax.bar(range(len(sorting_steps[0])), sorting_steps[0], align="edge")

    ax.set_xlim(0, len(sorting_steps[0]))
    ax.set_ylim(0, int(1.1 * max(sorting_steps[0])))

    text = ax.text(len(sorting_steps[0])/2, max(sorting_steps[0]), '', ha='center', va='bottom')
    ax.text(len(sorting_steps[0])/2, max(sorting_steps[0])*1.1, 'Visit how2matplotlib.com', ha='center', va='bottom')

    iteration = [0]
    def animate(frame):
        for rect, h in zip(bar_rects, sorting_steps[frame]):
            rect.set_height(h)

        pivot, low, high = pivots[frame]
        colors = ['lightblue' if low <= i <= high else 'lightgrey' for i in range(len(sorting_steps[0]))]
        if pivot != -1:
            colors[pivot] = 'red'

        for rect, color in zip(bar_rects, colors):
            rect.set_color(color)

        iteration[0] += 1
        text.set_text(f"Step: {iteration[0]}")
        return bar_rects + [text]

    anim = animation.FuncAnimation(
        fig, animate, frames=len(sorting_steps), interval=500, blit=True, repeat=False
    )

    plt.show()

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
sorting_steps, pivots = quick_sort_steps_with_pivot(arr)
animate_quick_sort_with_color(sorting_steps, pivots)

在这个版本中,我们使用红色来标识pivot元素,浅蓝色表示当前正在排序的子数组,灰色表示已经排序或尚未处理的部分。

7. 添加交互性

我们可以添加一些交互性,让用户能够控制动画的播放:

import matplotlib.pyplot as plt
from matplotlib.widgets import Button
import matplotlib.animation as animation

def animate_quick_sort_interactive(sorting_steps, pivots):
    fig, ax = plt.subplots(figsize=(10, 6))
    bar_rects = ax.bar(range(len(sorting_steps[0])), sorting_steps[0], align="edge")

    ax.set_xlim(0, len(sorting_steps[0]))
    ax.set_ylim(0, int(1.1 * max(sorting_steps[0])))

    text = ax.text(len(sorting_steps[0])/2, max(sorting_steps[0]), '', ha='center', va='bottom')
    ax.text(len(sorting_steps[0])/2, max(sorting_steps[0])*1.1, 'Visit how2matplotlib.com', ha='center', va='bottom')

    iteration = [0]
    def animate(frame):
        for rect, h in zip(bar_rects, sorting_steps[frame]):
            rect.set_height(h)

        pivot, low, high = pivots[frame]
        colors = ['lightblue' if low <= i <= high else 'lightgrey' for i in range(len(sorting_steps[0]))]
        if pivot != -1:
            colors[pivot] = 'red'

        for rect, color in zip(bar_rects, colors):
            rect.set_color(color)

        iteration[0] = frame
        text.set_text(f"Step: {iteration[0] + 1}")
        return bar_rects + [text]

    anim = animation.FuncAnimation(
        fig, animate, frames=len(sorting_steps), interval=500, blit=True, repeat=False
    )

    ax_prev = plt.axes([0.7, 0.05, 0.1, 0.075])
    ax_next = plt.axes([0.81, 0.05, 0.1, 0.075])
    bnext = Button(ax_next, 'Next')
    bprev = Button(ax_prev, 'Previous')

    def next(event):
        iteration[0] = min(iteration[0] + 1, len(sorting_steps) - 1)
        anim.frame_seq = anim.new_frame_seq()
        anim.event_source.stop()
        anim._init_draw()
        for _ in range(iteration[0]):
            anim._step()

    def prev(event):
        iteration[0] = max(iteration[0] - 1, 0)
        anim.frame_seq = anim.new_frame_seq()
        anim.event_source.stop()
        anim._init_draw()
        for _ in range(iteration[0]):
            anim._step()

    bnext.on_clicked(next)
    bprev.on_clicked(prev)

    plt.show()

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
sorting_steps, pivots = quick_sort_steps_with_pivot(arr)
animate_quick_sort_interactive(sorting_steps, pivots)

这个版本添加了”Next”和”Previous”按钮,允许用户手动控制动画的进度。

8. 优化性能

对于大型数组,生成和显示每一步可能会很慢。我们可以通过只显示关键步骤来优化性能:

def quick_sort_key_steps(arr):
    steps = []
    pivots = []

    def partition(low, high):
        pivot = arr[high]
        i = low - 1
        for j in range(low, high):
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
        arr[i + 1], arr[high] = arr[high], arr[i+ 1]
        steps.append(arr.copy())
        pivots.append((i + 1, low, high))
        return i + 1

    def quick_sort_recursive(low, high):
        if low < high:
            pi = partition(low, high)
            quick_sort_recursive(low, pi - 1)
            quick_sort_recursive(pi + 1, high)

    steps.append(arr.copy())
    pivots.append((-1, 0, len(arr) - 1))
    quick_sort_recursive(0, len(arr) - 1)
    return steps, pivots

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
key_steps, key_pivots = quick_sort_key_steps(arr)
animate_quick_sort_with_color(key_steps, key_pivots)
print("Visit how2matplotlib.com for more information")

这个优化版本只记录关键步骤,大大减少了需要显示的帧数,从而提高了性能。

9. 添加比较计数器

为了更好地理解算法的效率,我们可以添加一个比较计数器:

import matplotlib.pyplot as plt
import matplotlib.animation as animation

def quick_sort_steps_with_counter(arr):
    steps = []
    pivots = []
    comparisons = [0]

    def partition(low, high):
        pivot = arr[high]
        i = low - 1
        for j in range(low, high):
            comparisons[0] += 1
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        steps.append(arr.copy())
        pivots.append((i + 1, low, high))
        return i + 1

    def quick_sort_recursive(low, high):
        if low < high:
            pi = partition(low, high)
            quick_sort_recursive(low, pi - 1)
            quick_sort_recursive(pi + 1, high)

    steps.append(arr.copy())
    pivots.append((-1, 0, len(arr) - 1))
    quick_sort_recursive(0, len(arr) - 1)
    return steps, pivots, comparisons[0]

def animate_quick_sort_with_counter(sorting_steps, pivots, total_comparisons):
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 10), height_ratios=[3, 1])
    bar_rects = ax1.bar(range(len(sorting_steps[0])), sorting_steps[0], align="edge")

    ax1.set_xlim(0, len(sorting_steps[0]))
    ax1.set_ylim(0, int(1.1 * max(sorting_steps[0])))

    text = ax1.text(len(sorting_steps[0])/2, max(sorting_steps[0]), '', ha='center', va='bottom')
    ax1.text(len(sorting_steps[0])/2, max(sorting_steps[0])*1.1, 'Visit how2matplotlib.com', ha='center', va='bottom')

    comparison_line, = ax2.plot([], [], 'r-')
    ax2.set_xlim(0, len(sorting_steps))
    ax2.set_ylim(0, total_comparisons)
    ax2.set_xlabel('Steps')
    ax2.set_ylabel('Comparisons')

    iteration = [0]
    comparisons = [0]
    def animate(frame):
        for rect, h in zip(bar_rects, sorting_steps[frame]):
            rect.set_height(h)

        pivot, low, high = pivots[frame]
        colors = ['lightblue' if low <= i <= high else 'lightgrey' for i in range(len(sorting_steps[0]))]
        if pivot != -1:
            colors[pivot] = 'red'

        for rect, color in zip(bar_rects, colors):
            rect.set_color(color)

        iteration[0] += 1
        comparisons[0] = int(total_comparisons * (frame / len(sorting_steps)))
        text.set_text(f"Step: {iteration[0]}, Comparisons: {comparisons[0]}")

        comparison_line.set_data(range(frame + 1), [int(total_comparisons * (i / len(sorting_steps))) for i in range(frame + 1)])

        return bar_rects + [text, comparison_line]

    anim = animation.FuncAnimation(
        fig, animate, frames=len(sorting_steps), interval=500, blit=True, repeat=False
    )

    plt.tight_layout()
    plt.show()

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
sorting_steps, pivots, total_comparisons = quick_sort_steps_with_counter(arr)
animate_quick_sort_with_counter(sorting_steps, pivots, total_comparisons)

这个版本添加了一个比较计数器,并在动画中显示了比较次数的增长曲线。

10. 多种排序算法的比较

为了更好地理解快速排序的效率,我们可以将其与其他排序算法进行比较:

import matplotlib.pyplot as plt
import numpy as np
import time

def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr

def insertion_sort(arr):
    for i in range(1, len(arr)):
        key = arr[i]
        j = i-1
        while j >= 0 and key < arr[j]:
            arr[j+1] = arr[j]
            j -= 1
        arr[j+1] = key
    return arr

def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)

def compare_sorting_algorithms(sizes):
    algorithms = [
        ("Bubble Sort", bubble_sort),
        ("Insertion Sort", insertion_sort),
        ("Quick Sort", quick_sort),
        ("Python's Sorted", sorted)
    ]

    times = {name: [] for name, _ in algorithms}

    for size in sizes:
        arr = np.random.randint(0, 1000, size)
        for name, algo in algorithms:
            start_time = time.time()
            algo(arr.copy())
            end_time = time.time()
            times[name].append(end_time - start_time)

    plt.figure(figsize=(10, 6))
    for name, _ in algorithms:
        plt.plot(sizes, times[name], label=name)

    plt.xlabel('Array Size')
    plt.ylabel('Time (seconds)')
    plt.title('Sorting Algorithm Comparison')
    plt.legend()
    plt.grid(True)
    plt.text(sizes[-1]/2, max(max(times.values()))/2, 'Visit how2matplotlib.com', ha='center', va='center')
    plt.show()

# 示例使用
sizes = [100, 500, 1000, 2000, 3000, 4000, 5000]
compare_sorting_algorithms(sizes)

这个示例比较了冒泡排序、插入排序、快速排序和Python内置的排序函数的性能。

11. 3D可视化

我们还可以尝试创建一个3D可视化,展示排序过程中数组状态的变化:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

def quick_sort_3d_data(arr):
    steps = []

    def partition(low, high):
        pivot = arr[high]
        i = low - 1
        for j in range(low, high):
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
                steps.append(arr.copy())
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        steps.append(arr.copy())
        return i + 1

    def quick_sort_recursive(low, high):
        if low < high:
            pi = partition(low, high)
            quick_sort_recursive(low, pi - 1)
            quick_sort_recursive(pi + 1, high)

    steps.append(arr.copy())
    quick_sort_recursive(0, len(arr) - 1)
    return steps

def visualize_quick_sort_3d(arr):
    sorting_steps = quick_sort_3d_data(arr)

    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')

    x = np.arange(len(arr))
    y = np.arange(len(sorting_steps))
    X, Y = np.meshgrid(x, y)

    Z = np.array(sorting_steps)

    ax.plot_surface(X, Y, Z, cmap='viridis')

    ax.set_xlabel('Array Index')
    ax.set_ylabel('Sorting Step')
    ax.set_zlabel('Value')
    ax.set_title('3D Visualization of Quick Sort')

    ax.text(len(arr)/2, len(sorting_steps)/2, max(arr), 'Visit how2matplotlib.com', ha='center', va='center')

    plt.show()

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
visualize_quick_sort_3d(arr)

这个3D可视化展示了数组在排序过程中的变化,x轴表示数组索引,y轴表示排序步骤,z轴表示元素值。

12. 自定义颜色映射

我们可以创建一个自定义的颜色映射,以更好地展示排序过程:

import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np

def custom_colormap():
    return colors.LinearSegmentedColormap.from_list("custom", ["blue", "green", "red"])

def visualize_quick_sort_heatmap(arr):
    sorting_steps = quick_sort_3d_data(arr)

    fig, ax = plt.subplots(figsize=(10, 6))

    cmap = custom_colormap()
    im = ax.imshow(sorting_steps, cmap=cmap, aspect='auto', interpolation='nearest')

    ax.set_xlabel('Array Index')
    ax.set_ylabel('Sorting Step')
    ax.set_title('Heatmap Visualization of Quick Sort')

    plt.colorbar(im)

    ax.text(len(arr)/2, len(sorting_steps)/2, 'Visit how2matplotlib.com', ha='center', va='center', color='white')

    plt.show()

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
visualize_quick_sort_heatmap(arr)

这个热图可视化使用自定义的颜色映射,更直观地展示了排序过程中的值变化。

13. 动态柱状图

我们可以创建一个动态的柱状图,展示排序过程中的交换操作:

import matplotlib.pyplot as plt
import matplotlib.animation as animation

def quick_sort_with_swaps(arr):
    steps = []
    swaps = []

    def partition(low, high):
        pivot = arr[high]
        i = low - 1
        for j in range(low, high):
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
                steps.append(arr.copy())
                swaps.append((i, j))
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        steps.append(arr.copy())
        swaps.append((i + 1, high))
        return i + 1

    def quick_sort_recursive(low, high):
        if low < high:
            pi = partition(low, high)
            quick_sort_recursive(low, pi - 1)
            quick_sort_recursive(pi + 1, high)

    steps.append(arr.copy())
    swaps.append((-1, -1))
    quick_sort_recursive(0, len(arr) - 1)
    return steps, swaps

def animate_quick_sort_with_swaps(sorting_steps, swaps):
    fig, ax = plt.subplots(figsize=(10, 6))
    bar_rects = ax.bar(range(len(sorting_steps[0])), sorting_steps[0], align="edge")

    ax.set_xlim(0, len(sorting_steps[0]))
    ax.set_ylim(0, int(1.1 * max(sorting_steps[0])))

    text = ax.text(len(sorting_steps[0])/2, max(sorting_steps[0]), '', ha='center', va='bottom')
    ax.text(len(sorting_steps[0])/2, max(sorting_steps[0])*1.1, 'Visit how2matplotlib.com', ha='center', va='bottom')

    def animate(frame):
        for rect, h in zip(bar_rects, sorting_steps[frame]):
            rect.set_height(h)

        i, j = swaps[frame]
        colors = ['lightblue'] * len(sorting_steps[0])
        if i != -1 and j != -1:
            colors[i] = 'red'
            colors[j] = 'green'

        for rect, color in zip(bar_rects, colors):
            rect.set_color(color)

        text.set_text(f"Step: {frame + 1}, Swap: {i} <-> {j}")
        return bar_rects + [text]

    anim = animation.FuncAnimation(
        fig, animate, frames=len(sorting_steps), interval=500, blit=True, repeat=False
    )

    plt.show()

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
sorting_steps, swaps = quick_sort_with_swaps(arr)
animate_quick_sort_with_swaps(sorting_steps, swaps)

这个动画展示了快速排序过程中的每一次交换操作,红色和绿色分别表示被交换的两个元素。

14. 多数组并行排序可视化

我们可以同时可视化多个数组的排序过程,以比较不同初始状态下的排序效率:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

def quick_sort_steps(arr):
    steps = [arr.copy()]

    def partition(low, high):
        pivot = arr[high]
        i = low - 1
        for j in range(low, high):
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
                steps.append(arr.copy())
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        steps.append(arr.copy())
        return i + 1

    def quick_sort_recursive(low, high):
        if low < high:
            pi = partition(low, high)
            quick_sort_recursive(low, pi - 1)
            quick_sort_recursive(pi + 1, high)

    quick_sort_recursive(0, len(arr) - 1)
    return steps

def animate_multiple_quick_sorts(arrays):
    sorting_steps = [quick_sort_steps(arr) for arr in arrays]
    max_steps = max(len(steps) for steps in sorting_steps)

    fig, axes = plt.subplots(len(arrays), 1, figsize=(10, 6 * len(arrays)))
    if len(arrays) == 1:
        axes = [axes]

    bar_rects = []
    texts = []

    for ax, arr in zip(axes, arrays):
        rects = ax.bar(range(len(arr)), arr, align="edge")
        bar_rects.append(rects)

        ax.set_xlim(0, len(arr))
        ax.set_ylim(0, int(1.1 * max(arr)))

        text = ax.text(len(arr)/2, max(arr), '', ha='center', va='bottom')
        texts.append(text)

        ax.text(len(arr)/2, max(arr)*1.1, 'Visit how2matplotlib.com', ha='center', va='bottom')

    def animate(frame):
        for i, (rects, steps, text) in enumerate(zip(bar_rects, sorting_steps, texts)):
            if frame < len(steps):
                for rect, h in zip(rects, steps[frame]):
                    rect.set_height(h)
                text.set_text(f"Array {i+1}, Step: {frame + 1}")
        return [rect for rects in bar_rects for rect in rects] + texts

    anim = animation.FuncAnimation(
        fig, animate, frames=max_steps, interval=500, blit=True, repeat=False
    )

    plt.tight_layout()
    plt.show()

# 示例使用
arrays = [
    [3, 6, 8, 10, 1, 2, 1],
    [5, 2, 9, 1, 7, 6, 3],
    [8, 4, 2, 5, 1, 9, 3]
]
animate_multiple_quick_sorts(arrays)

这个示例同时可视化了三个不同数组的快速排序过程,让我们能够直观地比较不同初始状态下的排序效率。

15. 排序过程中的数组访问次数可视化

我们可以通过可视化数组中每个元素被访问的次数来深入了解快速排序的工作原理:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

def quick_sort_with_access_count(arr):
    steps = [arr.copy()]
    access_counts = [np.zeros_like(arr)]

    def partition(low, high):
        pivot = arr[high]
        access_counts[-1][high] += 1
        i = low - 1
        for j in range(low, high):
            access_counts[-1][j] += 1
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
                access_counts[-1][i] += 1
                access_counts[-1][j] += 1
                steps.append(arr.copy())
                access_counts.append(access_counts[-1].copy())
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        access_counts[-1][i + 1] += 1
        access_counts[-1][high] += 1
        steps.append(arr.copy())
        access_counts.append(access_counts[-1].copy())
        return i + 1

    def quick_sort_recursive(low, high):
        if low < high:
            pi = partition(low, high)
            quick_sort_recursive(low, pi - 1)
            quick_sort_recursive(pi + 1, high)

    quick_sort_recursive(0, len(arr) - 1)
    return steps, access_counts

def animate_quick_sort_with_access_count(sorting_steps, access_counts):
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 12))
    bar_rects1 = ax1.bar(range(len(sorting_steps[0])), sorting_steps[0], align="edge")
    bar_rects2 = ax2.bar(range(len(access_counts[0])), access_counts[0], align="edge")

    ax1.set_xlim(0, len(sorting_steps[0]))
    ax1.set_ylim(0, int(1.1 * max(max(step) for step in sorting_steps)))
    ax1.set_title("Array Values")

    ax2.set_xlim(0, len(access_counts[0]))
    ax2.set_ylim(0, int(1.1 * max(max(count) for count in access_counts)))
    ax2.set_title("Access Counts")

    text = ax1.text(len(sorting_steps[0])/2, max(sorting_steps[0]), '', ha='center', va='bottom')
    ax1.text(len(sorting_steps[0])/2, max(sorting_steps[0])*1.1, 'Visit how2matplotlib.com', ha='center', va='bottom')

    def animate(frame):
        for rect, h in zip(bar_rects1, sorting_steps[frame]):
            rect.set_height(h)
        for rect, h in zip(bar_rects2, access_counts[frame]):
            rect.set_height(h)

        text.set_text(f"Step: {frame + 1}")
        return bar_rects1 + bar_rects2 + [text]

    anim = animation.FuncAnimation(
        fig, animate, frames=len(sorting_steps), interval=500, blit=True, repeat=False
    )

    plt.tight_layout()
    plt.show()

# 示例使用
arr = [3, 6, 8, 10, 1, 2, 1]
sorting_steps, access_counts = quick_sort_with_access_count(arr)
animate_quick_sort_with_access_count(sorting_steps, access_counts)

这个可视化展示了排序过程中数组元素的变化以及每个元素被访问的次数,帮助我们更好地理解快速排序算法的工作原理。

结论

通过本文,我们深入探讨了如何使用Matplotlib来可视化快速排序算法。我们从基本的静态可视化开始,逐步深入到动态动画、3D可视化、热图等高级技巧。这些可视化方法不仅能帮助我们更好地理解快速排序算法的工作原理,还能直观地展示算法的效率和性能特征。

可视化在算法学习和教学中扮演着重要角色,它能够将抽象的概念转化为直观的图像,帮助学习者更快地理解和掌握复杂的算法思想。通过本文介绍的各种可视化技巧,读者可以将这些方法应用到其他算法的学习和分析中,从而提高算法理解和设计能力。

最后,我们要强调的是,虽然可视化是一个强大的工具,但它不应该替代对算法本身的深入理解。结合理论分析、代码实现和可视化展示,我们才能全面地掌握算法的精髓,并在实际问题中灵活运用。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程