Leecode 刷题笔记之可视化六大排序算法:冒泡、快速、归并、插入、选择、桶排序

简介: 这篇文章是关于LeetCode刷题笔记,主要介绍了六大排序算法(冒泡、快速、归并、插入、选择、桶排序)的Python实现及其可视化过程。

冒泡排序

思想
相邻的元素两两比较,较大的数下沉,较小的数冒起来,这样一趟比较下来,最大(小)值就会排列在一端。整个过程如同气泡冒起,因此被称作冒泡排序。

import random
from visual import visualizer

def maopaoSort(arr):
    return maopao(arr,len(arr)-1)

def maopao(num,n):
    for i in range(n):
        #对前一个的数据与后一个的数据进行比较
        for j in range(n):
            if num[j+1]<num[j]:
                visualizer.draw_bars(num, j, j + 1, len(num))
                num[j],num[j+1]=num[j+1],num[j]
    return num

if __name__ == '__main__':
    date = list(range(1, 101))
    random.shuffle(date)
    visualizer.t.bgcolor('black')
    maopaoSort(date)
    visualizer.t.done()

快速排序

思想
通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可以对这两部分记录继续进行排序,以达到整个系列有序。
具体代码

import random
from visual import visualizer

def quicksort(nums):
    quicksorthelper(nums,0,len(nums)-1)
    return nums

def quicksorthelper(nums,startidex,rightidex):
    # 如果列表中只有一个元素或者不存在的话
    if startidex>=rightidex:return
    # 找出第一个元素为初始值
    pivotidex=startidex
    privovalue=nums[pivotidex]
    # 以第二个元素为左指针
    left=startidex+1
    # 以第最后元素为右指针
    right=rightidex
    while left<=right:
        # 如果左指针指向的元素大于初始值大于右指针的元素,则说明左指针的值应该和右指针进行替换
        if nums[left]>privovalue>nums[right]:
            visualizer.draw_bars(nums, left, right, len(nums))
            nums[left],nums[right]=nums[right],nums[left]
        # 如果左指针的元素小于等于初始值,则不需要替换,只需要将左指针往右移动一位
        if nums[left]<=privovalue:
            left+=1
        # 如果右指针的元素大于等于初始值,则不需要替换,只需要将右指针往左移动一位
        if nums[right]>=privovalue:
            right-=1
    # 调换初始指针和右指针的元素位置,完成一次快速排序
    nums[right],nums[pivotidex]=nums[pivotidex],nums[right]
    visualizer.draw_bars(nums, pivotidex, right, len(nums))
    # 每一次递归操作都需要去额外的开辟存储空间,为了尽可能降低空间复杂度
    # 需要先判断左右列表的长短,先对短的进行快速排序,在对长的进行快速排序即可。
    leftlength=right-startidex
    rightlength=rightidex-right
    if leftlength<rightlength:
        quicksorthelper(nums,startidex,right-1)
        quicksorthelper(nums,right+1,rightidex)
    else:
        quicksorthelper(nums,right+1,rightidex)
        quicksorthelper(nums,startidex,right-1)

if __name__ == '__main__':
    date = list(range(1, 101))
    random.shuffle(date)
    visualizer.t.bgcolor('black')
    quicksort(date)
    visualizer.t.done()

归并排序

思想
并指将两个或两个以上的有序数表合并成一个新的有序表
步骤

  1. 将序列中带排序数字分为若干组,每个数字分为一组
  2. 将若干个组两两合并,保证合并后的组是有序的
  3. 重复第二步操作直到只剩下一组,排序完成
import random
from visual import visualizer
def merge(nums,left,mid,right):
    new_nums=[]
    l,r=left,mid+1
    while l<=mid and r<=right:
        if nums[l]<nums[r]:
            new_nums.append(nums[l])
            visualizer.draw_bars(nums,l,r,len(nums))
            l+=1
        else:
            new_nums.append(nums[r])
            visualizer.draw_bars(nums,l,r,len(nums))
            r+=1
    while l<=mid:
        new_nums.append(nums[l])
        visualizer.draw_bars(nums, l, r, len(nums))
        l+=1
    while r<=right:
        new_nums.append(nums[r])
        visualizer.draw_bars(nums, l, r, len(nums))
        r+=1
    nums[left:right+1]=new_nums

def merge_sort(nums,left,right):
    if left<right:
        mid=(left+right)//2
        merge_sort(nums,left,mid)
        merge_sort(nums,mid+1,right)
        merge(nums,left,mid,right)
        visualizer.draw_bars(nums, -1, -1, len(nums))

def run(nums):
    l,r=0,len(nums)-1
    return merge_sort(nums,l,r)

if __name__ == '__main__':
    date=list(range(1,101))
    random.shuffle(date)
    visualizer.t.bgcolor('black')
    run(date)
    visualizer.t.done()

插入排序

思想
将给定元素分为两组,开始第一个元素分为一组,后面的元素分为一组,然后通过不断遍历后面的元素不断插入到前面合适的位置。

# 原理:将给定元素分为两组,开始第一个元素分为一组,后面的元素分为一组,然后通过不断遍历后面的元素不断插入到前面合适的位置
import random
from visual import visualizer
# 0(n^2)Time | O(1) Space
# stable
def insert_arr(a):
    for i in range(len(a)):
        j=i
        while j>0 and a[j]<a[j-1]:
            visualizer.draw_bars(a,j,j-1,len(a))
            a[j],a[j-1]=a[j-1],a[j]
            j-=1
    return a

if __name__ == '__main__':
    date=list(range(1,101))
    random.shuffle(date)
    visualizer.t.bgcolor('black')
    insert_arr(date)
    visualizer.t.done()

选择排序

思想
第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,继续放在起始位置知道未排序元素个数为0。

#基本原理:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,继续放在起始位置知道未排序元素个数为0
import random
from visual import visualizer
# 时间复杂度
# 空间复杂度
# 是否稳定

def Selectsort(a):
    # 将每一轮的最小值的索引找出来,并放入序列的起始位置
    for i in range(len(a)-1):
        # key
        start_idex=i
        for j in range(i+1,len(a)):
            # 为了找更小的值
            visualizer.draw_bars(a, i, j, len(a))
            if a[start_idex]>a[j]:
                start_idex=j
        # start_idex为我们选出来的最小值索引,i为每一轮的初始值,就进行相应替换即可
        a[start_idex],a[i]=a[i],a[start_idex]
        visualizer.draw_bars(a, i, start_idex, len(a))
    return a

if __name__ == '__main__':
    date=list(range(1,20))
    random.shuffle(date)
    visualizer.t.bgcolor('black')
    Selectsort(date)
    visualizer.t.done()

桶排序

思想
将阵列分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序。

import random

def Tongsort(x):
    # 找到数组的最大值和最小值
    # 方法1
    maxvalue,minvalue=x[0],x[0]
    for i in range(1,len(x)):
        if x[i]>maxvalue:
            maxvalue=x[i]
        if x[i]<minvalue:
            minvalue=x[i]
    # 方法2
    # maxvalue,minvalue=max(x),min(x)

    # 计算桶的数量
    bucketnum=(maxvalue-minvalue)//3+1
    bucket=[[]for i in range(bucketnum)]
    # 根据数值对桶进行划分
    for i in x:
        bucket[i//3].append(i)

    # 针对每一个桶使用快速排序
    for b in bucket:
        quicksorthelper(b,0,len(b)-1)
    x.clear()
    for i in bucket:
        x.extend(i)
    return x

def quicksorthelper(nums,startidex,rightidex):
    # 如果列表中只有一个元素或者不存在的话
    if startidex>=rightidex:return
    # 找出第一个元素为初始值
    pivotidex=startidex
    privovalue=nums[pivotidex]
    # 以第二个元素为左指针
    left=startidex+1
    # 以第最后元素为右指针
    right=rightidex
    while left<=right:
        # 如果左指针指向的元素大于初始值大于右指针的元素,则说明左指针的值应该和右指针进行替换
        if nums[left]>privovalue>nums[right]:
            nums[left],nums[right]=nums[right],nums[left]
        # 如果左指针的元素小于等于初始值,则不需要替换,只需要将左指针往右移动一位
        if nums[left]<=privovalue:
            left+=1
        # 如果右指针的元素大于等于初始值,则不需要替换,只需要将右指针往左移动一位
        if nums[right]>=privovalue:
            right-=1
    # 调换初始指针和右指针的元素位置,完成一次快速排序
    nums[right],nums[pivotidex]=nums[pivotidex],nums[right]
    # 每一次递归操作都需要去额外的开辟存储空间,为了尽可能降低空间复杂度
    # 需要先判断左右列表的长短,先对短的进行快速排序,在对长的进行快速排序即可。
    leftlength=right-startidex
    rightlength=rightidex-right
    if leftlength<rightlength:
        quicksorthelper(nums,startidex,right-1)
        quicksorthelper(nums,right+1,rightidex)
    else:
        quicksorthelper(nums,right+1,rightidex)
        quicksorthelper(nums,startidex,right-1)

if __name__ == '__main__':
    date=list(range(1,11))
    random.shuffle(date)
    b=Tongsort(date)
    print(b)

可视化工具

import turtle as t
import random


def draw_bar(x,y,w,h):
    t.pu()
    t.goto(x,y)
    t.pd()
    t.seth(0)
    t.begin_fill()
    t.fd(w)
    t.left(90)
    t.fd(h)
    t.left(90)
    t.fd(w)
    t.left(90)
    t.fd(h)
    t.end_fill()

def draw_bars(lst,index1,index2,M):
    t.clear()
    x=-420
    n=len(lst)
    # w柱状矩形的宽度
    w=830/n
    # 矩形的高度
    r=650/M
    # 不刷新屏幕
    t.tracer(0)
    # 绘制的时候看不到小箭头
    t.ht()
    for i in range(n):
        if index1==i:
            # 显示出特定的idex
            t.fillcolor('red')
        elif index2==i:
            t.fillcolor('blue')
        else:
            t.fillcolor('white')
        draw_bar(x,-385,w,lst[i]*r)
        x+=w
    t.update()

    # t.clear()
    # x=-420
    # n=len(lst)
    # # w柱状矩形的宽度
    # w=830/n
    # # 矩形的高度
    # r=650/M
    # # 不刷新屏幕
    # t.tracer(0)
    # # 绘制的时候看不到小箭头
    # t.ht()
    # for i in range(n):
    #     t.fillcolor('green')
    #     draw_bar(x,-385,w,lst[i]*r)
    #     x+=w
    # t.update()


# lst=list(range(1,101))
# random.shuffle(lst)
# draw_bars(lst,-1,-1,len(lst))
# t.done()
目录
相关文章
|
2天前
|
编解码 Java 程序员
写代码还有专业的编程显示器?
写代码已经十个年头了, 一直都是习惯直接用一台Mac电脑写代码 偶尔接一个显示器, 但是可能因为公司配的显示器不怎么样, 还要接转接头 搞得桌面杂乱无章,分辨率也低,感觉屏幕还是Mac自带的看着舒服
|
4天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1540 5
|
1月前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
7天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
581 22
|
4天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
201 3
|
10天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
11天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
580 5
|
23天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
7天前
|
XML 安全 Java
【Maven】依赖管理,Maven仓库,Maven核心功能
【Maven】依赖管理,Maven仓库,Maven核心功能
233 3
|
9天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
327 2