python中的冒泡、快速、堆排序及二分法查找

本文深入解析了冒泡排序、快速排序和堆排序三种经典排序算法的原理及实现代码,同时介绍了二分查找法在有序数据集上的高效应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

冒泡排序

它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成。

第一种

def bubble_sort(list):
    for index,element in enumerate(list):
        for sub_index in range(index):
            if list[sub_index] > list[sub_index + 1]:
                list[sub_index],list[sub_index + 1] = list[sub_index + 1],list[sub_index]
    return list
print(bubble_sort([3,9,1,5,6,20])) #[1, 3, 5, 6, 9, 20]

 第二种

def bubble(bubbleList):
    listLength = len(bubbleList)
    while listLength > 0:
        for i in range(listLength - 1):
            if bubbleList[i] > bubbleList[i + 1]:
                bubbleList[i],bubbleList[i + 1]= bubbleList[i+1],bubbleList[i]
        listLength -= 1
    print(bubbleList) #[0, 1, 2, 3, 4, 5, 8]


if __name__ == '__main__':
    bubbleList = [3, 4, 1, 2, 5, 8, 0]
    bubble(bubbleList) 

快速排序

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

第一种

# 首先从列表中挑出一个元素作为基准值key,所有小于key的值放right,大于的方left,分别递归左右侧元素
def quick_sort(list,left,right):
    # 在递归的过程在,如果发现left和right一致时,停滞递归,直接返回列表
    if left >= right:
        return list
    # 定义游标
    low = left
    high = right

    # 取参考值,最左边的列表
    key = list[low]
    while low < high:
        # 从最右侧向左,依次和标志元素对比,如果右侧的元素大于标志的元素
        while low < high and list[high] >= key:
            # 右侧减一
            high -= 1
        # 不然就把high赋值给low
        list[low] = list[high]

        # 从最左侧向右,依次和标志元素对比,如果左侧的元素大于标志的元素
        while low < high and list[low] <= key:
            # 左侧加一
            low += 1
        # 不然就把high赋值给low
        list[high] = list[low]
    # 最后给key的位置赋值
    list[high] = key

    # 处理左侧的元素
    quick_sort(list,left,low-1)
    # 处理右侧的元素
    quick_sort(list,low+1,right)
    return list
Dlist = [10,2,20,7,41,8,88,13]
print(quick_sort(Dlist,0,7)) #[2, 7, 8, 10, 13, 20, 41, 88]

 第二种

def quickSort(array):
    if len(array) < 2:  # 基线条件(停止递归的条件)
        return array
    else:  # 递归条件
        baseValue = array[0]  # 选择基准值
        # 由所有小于基准值的元素组成的子数组
        less = [m for m in array[1:] if m < baseValue]
        # 包括基准在内的同时和基准相等的元素,在上一个版本的百科当中,并没有考虑相等元素
        equal = [w for w in array if w == baseValue]
        # 由所有大于基准值的元素组成的子数组
        greater = [n for n in array[1:] if n > baseValue]
    return quickSort(less) + equal + quickSort(greater)
# 示例:
array = [2,3,5,7,1,4,6,15,5,2,7,9,10,15,9,17,12]
print(quickSort(array))
# 输出为[1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 9, 9, 10, 12, 15, 15, 17]

堆排序

是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

在堆的数据结构中,堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。堆中定义以下几种操作:

  • 最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点

  • 创建最大堆(Build Max Heap):将堆中的所有数据重新排序

  • 堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算

第一种

def heap_sort(list):
    def adjust(start,end):
        '''最大堆调整'''
        root = start
        while True:
            child = 2 * root + 1
            # 孩子的索引值超过数组最大长度
            if child > end:
                break
            # 确定最大的孩子节点的索引值
            if child + 1 <= end and list[child] < list[child + 1]:
                child += 1
            # 孩子节点最大值和根节点进行交换
            if list[root] < list[child]:
                list[root],list[child] = list[child],list[root]
                root = child
            else:
                break
    # 创建大根堆
    for start in range((len(list) - 2) // 2,-1,-1):
        adjust(start,len(list) - 1)

    for end in range(len(list) - 1,0,-1):
        # 首尾交换
        list[0],list[end] = list[end],list[0]
        # 重新排序
        adjust(0,end-1)
    return list
alist = [57,34,11,20,23,1,4,5]
print(heap_sort(alist)) #[1, 4, 5, 11, 20, 23, 34, 57]

第二种

def big_endian(arr, start, end):
    root = start
    while True:
        child = root * 2 + 1  # 左孩子
        if child > end:  # 孩子比最后一个节点还大 也就意味着最后一个叶子节点了 就得跳出去一次循环已经调整完毕
            break
        if child + 1 <= end and arr[child] < arr[child + 1]:  # 为了始终让其跟子元素的较大值比较 如果右边大就左换右,左边大的话就默认
            child += 1
        if arr[root] < arr[child]:  # 父节点小于子节点直接换位置 同时坐标也得换这样下次循环可以准确判断是否为最底层是不是调整完毕
            arr[root], arr[child] = arr[child], arr[root]
            root = child
        else:  # 父子节点顺序正常 直接过
            break


def heap_sort(arr):
    # 无序区大根堆排序
    first = len(arr) // 2 - 1
    for start in range(first, -1, -1):  # 从下到上,从右到左对每个节点进调整 循环得到非叶子节点
        big_endian(arr, start, len(arr) - 1)  # 去调整所有的节点
    for end in range(len(arr) - 1, 0, -1):
        arr[0], arr[end] = arr[end], arr[0]  # 顶部尾部互换位置
        big_endian(arr, 0, end - 1)  # 重新调整子节点的顺序  从顶开始调整
    return arr


def main():
    l = [3, 1, 4, 9, 6, 7, 5, 8, 2, 10]
    print(heap_sort(l))  # 原地排序 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


if __name__ == "__main__":
    main()

二分法查找

算法:二分法查找适用于数据量较大时,但是数据需要先排好顺序。主要思想是:(设查找的数组区间为array[low, high])

确定该区间的中间位置K(2)将查找的值T与array[k]比较。若相等,查找成功返回此位置;否则确定新的查找区域,继续二分查找。区域确定如下:a.array[k]>T 由数组的有序性可知array[k,k+1,……,high]>T;故新的区间为array[low,……,K-1]b.array[k]<T 类似上面查找区间为array[k+1,……,high]。每一次查找与中间值比较,可以确定是否查找成功,不成功当前查找区间将缩小一半,递归查找即可。

def dichotomy(list1, target):
    length = len(list1)
    index_low = 0
    index_high = length - 1

    while index_low <= index_high:
        index_midle = int((index_low + index_high) / 2)
        guess = list1[index_midle]
        if guess == target:
            return index_midle
        elif guess > target:
            index_high = index_midle - 1
        elif guess < target:
            index_low = index_midle + 1
    return None


list_1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
target_1 = 3
print(dichotomy(list_1, target_1)) #返回 2

 

 

帮我做选择题 将元素序列{18,23,11,20,2,7,27,33,42,15}按顺序插入一个初始为空的、大小为11的散列表中。散列函数为:H(Key)=Key%11,采用线性探测法处理冲突。问:当第一次发现有冲突,散列表的装填因子大约是多少? A. 0.27 B. 0.45 C. 0.64 D. 0.73 分数 2 作者 DS课程组 单位 临沂大学 折半查找对应的判定树中,外部结点是( )。 A. 一次成功查找过程终止的结点 B. 一次失败查找过程终止的结点 C. 一次成功查找过程中经过的中间结点 D. 一次失败查找过程中经过的中间结点 分数 2 作者 M 单位 西南石油大学 顺序查找n个元素的顺序表,若查找成功,则比较关键字的次数最多为( )次。 A. n B. n+1 C. n+2 D. n-1 分数 2 作者 M 单位 西南石油大学 在散列存储中,装填因子α的值越大,则( )。 A. 存取元素发生冲突的可能性就越大 B. 存取元素发生冲突的可能性就越小 C. 存取元素不可能发生冲突 D. 毫无影响 分数 2 作者 ZXM 单位 西南石油大学 分别以下列序列构造二叉排序树,与用其他三个序列所构造的结果不同的是( )。 A. (89,120,99,86,72,80) B. (89,120,99,80,72,86) C. (89,80,86,72,120,99) D. (89,80,120,72,86,99) 分数 2 作者 黄龙军 单位 绍兴文理学院 对n个元素的表做顺序查找,若查找每个元素的概率相同,则平均查找长度为( ) A. (n-1)/2 B. n/2 C. (n+1)/2 D. n 分数 2 作者 YJ 单位 西南石油大学 有序表元素存储在数组A[1..11]中,其元素为{A,B,C,D,E,F,G,H,I,J,K};二分法查找元素A依次比较的元素是 A. F,B,A B. F,E,B,A C. F,C,A D. C,B,A 分数 2 作者 DS课程组 单位 浙江大学 下列排序算法中,哪种算法可能出现:在最后一趟开始之前,所有的元素都不在其最终的位置上?(设待排元素个数N>2) A. 冒泡排序 B. 插入排序 C. 堆排序 D. 快速排序 分数 2 作者 DS课程组 单位 浙江大学 对一组数据{ 2,12,16,88,5,10 }进行排序,若前三趟排序结果如下: 第一趟排序结果:2,12,16,5,10,88 第二趟排序结果:2,12,5,10,16,88 第三趟排序结果:2,5,10,12,16,88 则采用的排序方法可能是: A. 冒泡排序 B. 希尔排序 C. 归并排序 D. 基数排序 分数 2 作者 DS课程组 单位 浙江大学 就排序算法所用的辅助空间而言,堆排序快速排序、归并排序的关系是: A. 堆排序 < 归并排序 < 快速排序 B. 堆排序 > 归并排序 > 快速排序 C. 堆排序 < 快速排序 < 归并排序 D. 堆排序 > 快速排序 > 归并排序 分数 2 作者 考研试卷 单位 浙江大学 下列排序方法中,若将顺序存储更换为链式存储,则算法的间效率会降低的是: 1.插入排序;2.选择排序;3.起泡排序;4.希尔排序;5.堆排序 A. 仅1、2 B. 仅2、3 C. 仅3、4 D. 仅4、5 分数 2 作者 DS课程组 单位 临沂大学 设一组初始记录关键字序列为(60,80,55,40,42,85),则以第一个关键字60为基准而得到的一趟快速排序结果是( )。 A. 40,42,60,55,80,85 B. 42,45,55,60,85,80 C. 42,40,55,60,80,85 D. 42,40,60,85,55,80
最新发布
06-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值