C++ 睡眠排序算法2025年3月21日 | 阅读 9 分钟 引言Sleep Sort 算法 是一种非传统且富有创意的数字排序方法,它依赖系统计时来间接实现所需的顺序。Sleep Sort 的想法基于这样一个事实:较大的数字可以“睡眠”或延迟比较小的数字更长的时间,从而使较小的数字在处理时先出现。 在 Sleep Sort 中,数组或列表中的每个数字都在并行线程中进行处理。每个线程负责“睡眠”一段与它所代表的数字值成比例的时间。睡眠期结束后,线程“唤醒”并打印或记录该数字。由于较小的数字具有较短的睡眠时间,因此它们会先输出,从而有效地对数组进行排序。 让我们看看 Sleep Sort 如何工作?
示例考虑数组:[5, 2, 7, 1] 步骤: 为列表中的每个数字创建一个线程
最终输出将是 1 2 5 7,这是输入数组的排序顺序。 方法 1:简单方法实施输出 Sorted output: 1 2 4 5 7 说明步骤 1:导入必要的库 程序首先导入提供线程功能和时间处理功能的库。这些库允许程序创建并发运行的线程,并控制每个线程的睡眠时间。 步骤 2:定义睡眠和打印函数 定义一个函数来处理排序逻辑。此函数以单个数字作为输入,使线程根据该数字的大小睡眠,然后打印该数字。此睡眠持续时间决定了数字的打印顺序。 步骤 3:创建排序函数 创建另一个函数来管理整个排序过程。此函数以数字列表作为输入。对于列表中的每个数字,都会创建一个新线程来执行睡眠和打印函数。这些线程并发运行,意味着它们同时运行而不是顺序运行。 步骤 4:存储线程 在创建每个线程时,都会将其存储在一个集合(如 vector)中,以便程序可以跟踪它已启动的所有线程。这使得主程序能够有效地管理这些线程。 步骤 5:加入线程 创建所有线程后,程序需要确保它们都完成执行。它通过调用一个在继续之前等待每个线程完成的方法来做到这一点。此步骤至关重要,因为它可防止主程序在所有数字都打印出来之前退出。 步骤 6:主函数执行 在程序的中心部分,定义了要排序的数字列表。使用此列表作为输入调用排序函数。函数执行时,它会为每个数字创建线程,使它们根据其值进行睡眠和打印。 步骤 7:显示输出 所有线程执行完成后,输出将显示在屏幕上。由于睡眠时间不同,数字将按升序打印——较小的数字睡眠时间较短,因此先唤醒。 复杂度分析时间复杂度 睡眠持续时间:Sleep Sort 中的主要操作是每个线程根据要排序的数字值进行睡眠。因此,如果输入列表中的最大数字是 M,则最坏情况下的时间复杂度可以视为 O(M),因为最大数字对应的线程将需要这么长时间才能完成。 线程创建:该算法为输入列表中的每个数字创建一个单独的线程。如果 n 个数字,创建 n 个线程会产生开销,但这通常不是影响时间复杂度的主要因素。 整体时间复杂度:由于数字中的最大值决定了排序过程所需的时间,因此整体时间复杂度可以概括为 O(M),其中 M 是列表中最大的数字。如果 M 非常大,这可能会效率低下。 空间复杂度 线程存储:Sleep Sort 需要为每个创建的线程额外空间。因此,对于存储内存中的 n 个线程,空间复杂度为 O(n),其中 n 是输入列表中元素的数量。 其他变量:其他空间需求最少,主要包括输入数组和排序函数中使用的任何临时变量。 整体空间复杂度:因此,由于线程的存储,整体空间复杂度为 O(n)。 方法 2:使用循环和条件变量在这种方法中,我们将使用一个简单的循环来模拟睡眠机制,并依赖于一个共享的条件变量来管理输出顺序。 实施输出 Sorted output: 1 2 4 5 7 说明步骤 1:包含必要的库 程序首先包含提供多线程、时间操作和同步所需功能的库。这些库使程序能够创建线程、管理睡眠持续时间并安全地处理共享数据。 步骤 2:声明共享变量 代码声明了一个互斥锁和一个条件变量。互斥锁确保对共享数据的访问是线程安全的,而条件变量有助于管理线程之间的同步。还定义了一个变量来跟踪迄今为止处理的最大数字。 步骤 3:定义睡眠和信号函数 创建了一个函数,该函数以数字作为输入。此函数使线程根据数字的值睡眠。线程醒来后,它会更新共享变量以反映迄今为止处理过的最大数字,并通知任何等待的线程有一个数字已准备好打印。 步骤 4:定义打印函数 定义另一个函数来处理数字的打印。此函数在单独的线程中运行,并等待来自条件变量的通知。它持续检查是否可以按顺序打印下一个数字。它按升序打印数字,依赖于更新的最大处理数字。 步骤 5:创建排序函数 实现了一个排序函数来管理整体过程。此函数为输入数组中的每个数字创建一个线程。每个线程都将执行睡眠和信号函数。此外,还会创建一个单独的线程来处理数字的打印。 步骤 6:管理线程执行 创建所有线程后,程序会确保它们完成执行。它使用 join 方法等待所有线程完成任务,然后主程序继续。此步骤对于防止主函数在线程仍在运行时退出至关重要。 步骤 7:初始化主函数 在主函数中,程序初始化需要排序的数字数组。然后,它使用此数组作为输入调用排序函数。所有线程完成任务后,将显示输出。 步骤 8:显示输出 所有线程完成睡眠和信号后,排序后的数字将按升序打印到控制台。由于睡眠持续时间得到管理的方式,较小的数字会先出现,从而演示了算法实现的排序。 复杂度分析 时间复杂度 睡眠持续时间:此实现中的主要操作涉及基于每个数字的值睡眠一段时间。如果输入列表中的最大数字是 M,则最坏情况下的时间复杂度可以视为 O(M),因为最长的睡眠将对应于此最大值。 线程管理:与睡眠持续时间相比,创建线程所需的时间很短。实际的线程创建开销与睡眠时间相比微不足道。 打印:打印函数等待通知,这会引入少量开销,但不会显着影响整体时间复杂度。 整体时间复杂度:因此,整体时间复杂度仍然是 O(M),其中 M 是输入列表中的最大数字。这表明当处理较大的值时,该算法可能效率低下。 空间复杂度 线程存储:输入列表中的每个数字都会创建一个相应的线程,导致空间复杂度为 O(n),其中 n 是输入列表中元素的数量。每个线程都会为其堆栈消耗内存资源。 共享变量:共享变量(互斥锁、条件变量和 max_num)具有恒定的空间需求,与输入大小无关。 整体空间复杂度:因此,由于线程的存储,整体空间复杂度为 O(n)。 性质
下一主题C++ 中的所有后缀的 Trie |
简介:C++ 中的 'exit()' 函数用于结束程序执行。它允许您在程序运行的任何时刻停止程序,无论它在代码中的哪个位置被调用。使用 'exit()' 函数的主要目标是结束……
阅读9分钟
在本文中,我们将讨论带实现。简介:纸牌翻转游戏是一种简单但有趣的游戏,玩家将牌面朝下放在网格中进行翻转。此游戏的目标是通过一次翻转两张牌来找到匹配的对...
阅读 6 分钟
在 C++ 中,'std::set' 是一个存储元素的容器。创建集合时,实际上是将元素添加到其中。C++ 提供了初始化集合的方法,允许您从源或以不同方式填充它。正确启动集合很重要,因为...
阅读9分钟
在本文中,我们将讨论 C++ 中 std::thread 和 OpenMP 之间的区别。在深入探讨区别之前,让我们详细了解每个术语及其功能。什么是 C++ 中的 std::thread? std::thread 是程序的最小单元。当您运行叙事设计时...
5 分钟阅读
概述 “半平面交”算法是一种几何方法,用于计算二维区域内一个或多个半平面的交集。半平面是指飞机被数学几何中的直线划分成的两个方面之一,直线 appears as...
11 分钟阅读
跳表是一种数据结构,它提供了一种在排序序列中高效地搜索、插入和删除元素的方法。它是由 William Pugh 在 1989 年发明的,作为平衡树的一种替代方案,具有相似的平均情况性能特征,但实现更简单。问题...
阅读 12 分钟
Gomory-Hu 树是无向图中任意两对节点之间最小割值的压缩表示。该树可用于非常高效地解决网络流、最小割和连通性类型的问题。在 Gomory-Hu 树中,每条边都表示一个最小割...
阅读 8 分钟
引言:“重新排列远程条形码”是计算机科学领域,尤其是在算法设计和优化中经常遇到的一个计算问题。挑战在于重新组织条形码序列(由整数表示),使得没有两个相邻的条形码相同。这个问题类似于寻找...
阅读 15 分钟
简介:负无穷大是 C++ 中一个非常罕见的数,它表示一个比任何其他实数都小得多的值。这个概念在许多计算环境中至关重要,尤其是在处理浮点算术的边缘情况、设计算法和进行数值分析时。
5 分钟阅读
交易处理是杂货店、自动售货机和我们的柠檬水摊每天都会遇到的一个重要常见问题。柠檬水摊找零挑战是一个定义明确的算法问题,在现实世界中,适当的找零管理需要实时动态的找零分配...
阅读9分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India