《计算之魂》Task3:关于排序的讨论

在这里插入图片描述

1. 排序

所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减排列起来的操作。排序是计算机内经常进行的一种操作,其目的是将一组无序的记录序列调整为有序的记录序列。


1.1 评价指标

  • 时间复杂度
  • 空间复杂度
  • 使用场景:针对实际对节省时间和空间的不同需求,选择适用于不同场景的排序算法
  • 稳定性:稳定的算法在排序过程中不会改变元素彼此之间次序

1.2 不同排序算法O(n)分类

排序算法平均时间复杂度度最坏时间复杂度额外空间复杂度稳定性
选择排序 O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
插入排序 O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
归并排序 O ( n ∗ log ⁡ n ) O(n*\log n) O(nlogn) O ( n ∗ log ⁡ n ) O(n*\log n) O(nlogn) O ( n ) O(n) O(n)稳定
堆排序 O ( n ∗ log ⁡ n ) O(n*\log n) O(nlogn) O ( n ∗ log ⁡ n ) O(n*\log n) O(nlogn) O ( 1 ) O(1) O(1)不稳定
快速排序 O ( n ∗ log ⁡ n ) O(n*\log n) O(nlogn) O ( n 2 ) O(n^2) O(n2) O ( log ⁡ n ) O(\log n) O(logn)不稳定

2. 算法介绍

2.1 选择排序

在这里插入图片描述
python 实现


def selection_sort(num_list):
    length = len(num_list)
    if length <= 1:
        return num_list

    for j in range(length):
        # 假设第一个元素为最小元素
        min_num_index = j
        
        # 遍历未排序区域元素,以此和未排序区域的第一个元素做对比
        for i in range(j+1, length):
            if num_list[i] < num_list[min_num_index]:
                min_num_index = i
         
        # 交换位置
        num_list[min_num_index], num_list[j] = num_list[j], num_list[min_num_index]

    return num_list

2.2 插入排序

在这里插入图片描述
python 实现

def insertion_sort(ls):
    for i in range(0,len(ls)):
        current_index = i
        while ls[current_index - 1] > ls[current_index] and current_index - 1 >= 0:
            ls[current_index] , ls[current_index - 1] = ls[current_index - 1] , ls[current_index]
            current_index -= 1
    return ls

2.3 归并排序

在这里插入图片描述
python 实现

# 1.将整个数组对半分开,直到只剩一个元素
 # 2.从一个元素开始往回进行对比合并,将合并的内容暂且放在一个空列表中
 # 定义合并merge函数
def merge(L,R):
    # 将两个排过序的两个列表进行合并并排序
    # 分别用于限定L、R的数据减少情况
    i, j = 0,0
    # 用于存放L与R的合并内容
    res = []
    while i < len(L) and j < len(R):
        # 如果左边的数大于右边的数,就将左边的数先添加到res中,再继续比较(合并的R、L已经排过序)
        # 如果如果右边的数大于左边的数,就将右边的数先添加到res中,再继续比较(合并的R、L已经排过序)
        if L[i] <= R[j]:
            res.append(L[i])
            i += 1
        else:
            res.append(R[j])
            j += 1
    # 因为当 i == len(L) 或者 j == len(R)时,跳出while循环,且每次循环只处理一个列表里的内容,所以其中有一个列表内容会先全部加入res中,另一个列表还剩内容未加进res中。
    # 对未处理完的列表,直接加入res中
    res += R[j:] if i == len(L) else L[i:]
    return res

 # 定义排序merge_sort函数
def merge_sort(List):
    length = len(List)
    if length <= 1:
        return List
    else:
        mid = length//2
        left = merge_sort(List[:mid])
        right = merge_sort(List[mid:])
        return merge(left,right)

参考资料:归并排序(Python代码)


2.4 堆排序

演示动画
原理及代码可参考python实现堆排序


2.5 快速排序

在这里插入图片描述

演示动画

python 代码

def quicksort(array):
	if len(array) < 2:
		return array
	else:
		pivot = array[0]
		less = [i for i in array[1:] if i <= pivot]
		greater = [i for i in array[1:] if i >= pivot]
		return quicksort(less) + [pivot] + quicksort(greater)

3. 思考题

思考题1.4.1 赛跑问题(GS)

假定有25名短跑选手比赛争夺前三名,赛场上有五条赛道,一次可以有五名选手同时比赛。比赛并不计时,只看相应的名次。假设选手的发挥是稳定的,也就是说如果约翰比张三跑得快,张三比凯利跑得快,约翰一定比凯利跑得快。最少需要几次比赛才能决出前三名?(在第6章给出了这一问题的解答。(难度系数3颗星))

答:参考了计算之魂第6章给出了的解答。

  1. 先进行五组比赛,决出各组名次。并令各组第一分别为A1B1C1D1E1
A组B组C组D组E组
A1B1C1D1E1
A2B2C2D2E2
A3B3C3D3E3
A4B4C4D4E4
A5B5C5D5E5
  1. 第六组比赛:各组第一 A1B1C1D1E1 分别进行一次比赛。假设名次为 A1B1C1D1E1 。则整体第一名为A1
  2. 第七组比赛:如下表,整体第二名必出现在 A2B1之间;整体第三名必出现在 A2B1A3B2C1 之间。
    A2B1A3B2C1 之间进行第七组比赛,第一名为整体第二名,第二名为整体第三名。
A组B组C组D组E组
B1C1D1E1
A2B2C2D2E2
A3B3C3D3E3
A4B4C4D4E4
A5B5C5D5E5

思考题1.4.2 区间排序

如果有N个区间[l1,r1],[l2,r2],…,[lN,rN],只要满足下面的条件我们就说这些区间是有序的:存在xi∈[li,ri],其中i=1,2,…,N。
比如,[1, 4]、[2, 3]和[1.5, 2.5]是有序的,因为我们可以从这三个区间中选择1.1、2.1和2.2三个数。同时[2, 3]、[1, 4]和[1.5, 2.5]也是有序的,因为我们可以选择2.1、2.2和2.4。但是[1, 2]、[2.7, 3.5]和[1.5, 2.5]不是有序的。
对于任意一组区间,如何将它们进行排序?(难度系数3颗星)

答:该题解答参考了博客《计算之魂》思考题1.4 - Q2,内容如下:

  1. 按照右端点排序;
  2. 将右端点最大的区间作为头区间,讨论剩余 n -1 个区间的情况;
  3. 对剩余的 n - 1 个区间按照步骤二重复,直至仅剩 4 个区间为止(也就是右端点最小的四个区间);
  4. 如果第 4 个区间不能和第 3 个区间交换,则按照上图可以得到前三个区间的情况,并递归地讨论第 4 个区间与第 5 个区间是否能交换,直至递归到最后一个区间,算法终止;
  5. 如果能交换,则将第 3 个区间作为最大的区间,并可以得到 N1、N2、N4(按照右端点的相对大小排序)这三个区间的情况,并归位;
  6. 讨论第 4 个区间能否与第 2 个区间交换,不能的话则返回步骤 4;
  7. 能的话则返回步骤 5,直至讨论到第 4 个区间与第 1 个区间是否能交换,并返回步骤4。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
`std::task::Context` 是 Rust 的异步编程库 `async-std` 和 `tokio` 中常用的类型,用于传递异步任务执行的上下文信息。它包含了当前任务的调度器、Waker、时间信息等。要使用 `Context`,需要先创建一个 `Waker` 对象,它会在任务可以继续执行时被唤醒。 下面是一个示例代码,展示了如何在 `async-std` 中使用 `Context`: ```rust use async_std::task::{Context, Poll}; use async_std::task; use std::future::Future; use std::pin::Pin; async fn my_task() { println!("Start task"); task::sleep(std::time::Duration::from_secs(1)).await; println!("Task completed"); } struct MyFuture {} impl Future for MyFuture { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { // 唤醒任务,使它可以执行 cx.waker().wake_by_ref(); Poll::Ready(()) } } fn main() { // 创建异步任务 let my_task = my_task(); // 执行异步任务 task::spawn(async move { // 等待异步任务完成 my_task.await; println!("My task is done"); // 创建 MyFuture 对象并执行它 let my_future = MyFuture {}; let mut my_future_pin = Pin::new(&mut my_future); my_future_pin.poll(&mut Context::from_waker(task::noop_waker_ref())).await; println!("MyFuture is done"); }); // 等待异步任务执行完成 task::block_on(async {}); } ``` 在上面的代码中,我们首先创建了一个异步任务 `my_task`,然后使用 `task::spawn` 执行它。在任务执行完成后,我们创建了一个 `MyFuture` 对象,并使用 `Context` 执行它。注意到 `poll` 方法中的 `cx.waker().wake_by_ref()`,它会唤醒任务,使得它可以继续执行。 需要注意的是,`Context` 的创建需要传递一个 `Waker` 对象。在示例代码中,我们使用了 `task::noop_waker_ref()`,它是一个空的 `Waker` 对象,可以在不需要唤醒任务的情况下创建 `Context`。如果需要唤醒任务,可以自定义一个 `Waker` 对象并传递给 `Context`。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值