算法,排序,最全

本文深入讲解了多种排序算法,包括冒泡排序、选择排序、插入排序、快速排序、堆排序和归并排序,详细介绍了每种算法的工作原理,并提供了Python代码实现。同时,对比了不同算法的时间复杂度和适用场景。

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

一、算法概念

1、Algorithm:一个计算的过程,解决问题的方法
汉诺塔问题

def hanoi(n, a, b, c):
    if n > 0:
        hanoi(n-1, a, c, b)
        asd = '从%s到%s' % (a, c)
        list1.append(asd)
        hanoi(n-1, b, a, c)
        return len(list1)

二、查找

一、在一些数据元素中,通过一定的方法找出与给定关键字相同的数据元素的过程。
1、计算程序运行时间的装饰器

def cal_time(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        result = func(*args, **kwargs)
        t2 = time.time()
        print('%s running time : %s secs.' %(func.__name__, (t2 - t1)))
        return result
    return wrapper
@cal_time
def linear_search(li,val):
    for ind, v in enumerate(li):
        if v == val:
            return ind
    else:
        return None
#二分查找函数
@cal_time
def binary_search(li,val):
    left = 0
    right = len(li) - 1
    while left <= right:
        mid = (left + right) // 2
        if li[mid] == val:
            return mid
        elif li[mid] > val:
            right = mid - 1
        else:
            left = mid + 1
    else:
        return None

调用比较

list2 = list(range(1000000))
linear_search(list2, 288888)
binary_search(list2, 288888)

三、一般排序

一、概念:将一组无序的记录调整为有序的记录
1、冒泡排序

def bubble_sort(li):
    for i in range(len(li)-1):
        exchage = False
        for k in range(len(li)-i-1):
            if li[k] > li[k+1]:
                li[k], li[k+1] = li[k+1], li[k]
                exchage = True
        if not exchage:
            return li
    return li

li = [6,2,12,1,32,34,24,3,4,134]
print(bubble_sort(li))

2、选择排序

def select_sort(li):
    for i in range(len(li)-1):
        min_loc = i
        for j in range(i+1,len(li)):
            if li[j] < li[min_loc]:
                min_loc = j
        if min_loc != i :
            li[min_loc],li[i] = li[i],li[min_loc]
    return li


li = [6,2,12,1,32,34,24,3,4,134]
print(select_sort(li))

3、插入排序法

#插入排序法
def insert_sort(li):
    for i in range(1, len(li)):       #摸到的牌的下标
        tmp = li[i]
        j = i-1
        while j >= 0 and tmp < li[j]:
            li[j+1] = li[j]
            j -= 1
        li[j+1] = tmp
    return li

li = [6,2,12,1,32,34,24,3,4,134]
print(insert_sort(li))

四、快速排序

一、快速排序

#第一次取中间值,左边小,右边大
def partition(li, left, right):
    tmp = li[left]
    while left < right:
        while li[right] > tmp and left < right:
            right -= 1
        li[left] = li[right]
        while li[left] < tmp and left < right:
            left += 1
        li[right] = li[left]
    li[left] = tmp
    return left


#快速排序框架,左边、右边分别调用,
def _quick_sort(li, left, right):
    if left < right:
        mid = partition(li, left, right)
        _quick_sort(li, left, mid-1)
        _quick_sort(li, mid+1, right)


#装饰器不能用在递归函数上,所以再写一个函数
@cal_time
def quick_sort(li):
    _quick_sort(li, 0, len(li)-1)


#创建一个乱序列表,调用看时间
li = list(range(10000))
random.shuffle(li)
quick_sort(li)

二、堆排序
1、堆:一种特殊的完全二叉树结构
大根堆:任一节点都比孩子节点大
小根堆:任一节点都比孩子节点小
2、堆排序:
堆的向下调整性质:假设:节点的左右子树都是堆,但自身不是堆。
当根节点的左右子树都是堆时,可以通过一次向下调整来将其变换成一个堆。
3、堆排序的过程:
(1)建立堆
(2)得到堆顶元素,为最大元素
(3)去掉堆顶,将堆最后一个元素,放到堆顶。此时可以通过一次向下调整重新使堆有序。
(4)堆顶元素为第二大元素
(5)重复步骤3,知道堆变空
4、构造堆(农村包围城市)
从最后一个非叶子节点开始调整,倒着走,把大的往上调,就可以构造一个堆。
5、代码实现

def sift(li, low, high):
    """
    堆的向下调整性质:假设:节点的左右子树都是堆,但自身不是堆,这个函数把它变成堆
    :param li:  列表
    :param low:  堆的根节点下标,不是堆的位置
    :param high:  堆的最后一个元素的下标
    :return:
    """
    i = low        # i最开始指向根节点
    j = 2*i+1      # j开始是左孩子
    tmp = li[low]  # 把堆顶存起来
    while j <= high:  # j没有超出堆的个数
        if j+1 <= high and li[j+1] > li[j]:   # 右边有孩子且比左边的大
            j = j+1                           # 把j指向大孩子
        if li[j] > tmp:          # 把大孩子与父亲比较,大孩子比父亲大
            li[i] = li[j]        # 大孩子顶上去
            i = j                # 往下走一层
            j = 2*i+1
        else:
            li[i] = tmp      # 大孩子比父亲小,直接让父亲坐上去
            break
    else:
        li[i] = tmp       # j超出堆的个数,说明堆顶就是叶子节点,就直接坐上去


@cal_time
def heap_sort(li):
    n = len(li)
    for i in range((n-2)//2, -1, -1):   # 循环建堆,从最后一个非叶子节点开始,循环到根
        sift(li, i, n-1)                # 向下调整,建堆的方法,建堆完成
    for i in range(n-1, -1, -1):
        li[0], li[i] = li[i], li[0]
        sift(li, 0, i-1)        # i-1是新的high


li1 = list(range(10000))
random.shuffle(li1)
heap_sort(li1)

6、堆排序的应用,计算topk(排行榜前几)
思路:将一组列表前k组成一个小根堆,遍历剩下的元素,打的元素替换掉小根堆的根,然后向下调整建堆,直到所有元素比较完。然后这个堆就是前k大元素,然后出数。

import random


def sift(li, low, high):
    """
    堆的向下调整性质:假设:节点的左右子树都是堆,但自身不是堆,这个函数把它变成堆
    :param li:  列表
    :param low:  堆的根节点下标,不是堆的位置
    :param high:  堆的最后一个元素的下标
    :return:
    """
    i = low        # i最开始指向根节点
    j = 2*i+1      # j开始是左孩子
    tmp = li[low]  # 把堆顶存起来
    while j <= high:  # j没有超出堆的个数
        if j+1 <= high and li[j+1] < li[j]:   # 右边有孩子且比左边的大
            j = j+1                           # 把j指向大孩子
        if li[j] < tmp:          # 把大孩子与父亲比较,大孩子比父亲大
            li[i] = li[j]        # 大孩子顶上去
            i = j                # 往下走一层
            j = 2*i+1
        else:
            li[i] = tmp      # 大孩子比父亲小,直接让父亲坐上去
            break
    else:
        li[i] = tmp       # j超出堆的个数,说明堆顶就是叶子节点,就直接坐上去


def topk(li, k):
    heap = li[0:k]
    for i in range((k-2)//2, -1, -1):   # 循环建堆,从最后一个非叶子节点开始,循环到根
        sift(heap, i, k-1)                # 向下调整,建堆的方法,建堆完成
    for i in range(k, len(li)-1):    # 遍历k后面的,与小根堆的根比较大小,把小的换下来
        if li[i] > heap[0]:
            heap[0] = li[i]
            sift(heap, 0, k-1)
    for i in range(k-1, -1, -1):    # 出数
        heap[0], heap[i] = heap[i], heap[0]
        sift(heap, 0, i-1)        # i-1是新的high
    return heap


li1 = list(range(1000))
random.shuffle(li1)
print(topk(li1, 10))

三、归并排序
思路:将一组列表分成只有一个或零个元素的列表,然后归并
代码实现

import random


def merge(li, low, mid, high):
    i = low
    j = mid +1
    ltmp = []
    while i <= mid and j <= high:
        if li[i] < li[j]:
            ltmp.append(li[i])
            i += 1
        else:
            ltmp.append(li[j])
            j += 1
    # while 执行完,肯定有一部分没数了
    while i <= mid:
        ltmp.append(li[i])
        i += 1
    while j <=high:
        ltmp.append(li[j])
        j += 1
    li[low:high+1] = ltmp


def merge_sort(li, low, high):
    if low < high:
        mid = (low + high) // 2
        merge_sort(li, low, mid)
        merge_sort(li, mid+1, high)
        merge(li, low, mid, high)


li1 = list(range(100))
random.shuffle(li1)
merge_sort(li1, 0, len(li1)-1)
print(li1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值