C 语言 Strfry() 函数2025年1月7日 | 阅读13分钟 strfry() 函数是 GNU C 库 (glibc) 中一个专门的实用工具,它提供了一种随机打乱字符串中字符的方法。它的主要目的是演示 C 语言中的字符串操作和随机化。尽管它不是标准 C 库的一部分,但 strfry() 是一个有趣的非标准库扩展示例,它可以提供超出基本 ANSI C 规范的附加功能。 在支持 GNU C 库的系统上,此函数定义在string.h头文件中。它的设计简单直接。该函数接受一个参数,即指向以 null 结尾的字符串的指针,并就地打乱其字符。原始字符序列被随机化,函数返回指向修改后的字符串的指针。这种行为对于需要简单混淆形式的应用程序或用于教育目的以说明 C 语言中字符串和随机化工作原理的应用程序特别有用。 strfry() 函数作为 C 语言中简单的字符串操作和随机化的工具。虽然由于其非标准性质和基本随机化质量,其实际应用有限,但它仍然是学习这些概念的有用工具。开发人员应考虑其局限性,并确保它符合其项目的特定需求,尤其是在可移植性和随机性要求方面。 语法它具有以下语法: 在这里,字符串表示要打乱的输入字符串。该函数返回传入字符串的相同指针。需要注意的是,strfry() 函数直接更改原始字符串的内容,这意味着原始字符序列会丢失,并被随机顺序取代。 方法 1:Fisher-Yates 洗牌算法Fisher-Yates 洗牌(也称为 Knuth 洗牌)是一种广泛使用且高效的算法,用于随机排列有限序列,在本例中是字符串的字符。该算法的特别之处在于其简单性和均匀随机性,这意味着序列的每种排列都同样可能。 Fisher-Yates 洗牌算法的核心思想是从最后一个元素到第一个元素迭代数组,将每个元素与前面(包括自身)随机选择的另一个元素进行交换。这种就地算法的时间复杂度为 O(n),其中 n 是数组中的元素数量,并且它只需要 O(1) 的额外空间,这使其既高效又节省空间。 程序输出 Enter a string to shuffle: example text Original: Example text Shuffle 1: pt etmleaxxe Shuffle 2: mlxepet atxe Shuffle 3: mlxpatt eexe Shuffle 4: em etaxltpex Shuffle 5: amxlep xtete 说明提供的 C 程序说明了 Fisher-Yates 洗牌算法,这是一种经典的、高效的生成数组或字符串随机排列的方法。该程序包含输入验证、多次洗牌以及大量使用标准 C 库等多种功能。
复杂度分析时间复杂度 Fisher-Yates 洗牌函数 (fisherYatesShuffle) Fisher-Yates 洗牌算法对数组(或字符串)进行精确一次迭代,从最后一个元素到第一个元素,在每次迭代期间执行一个恒定时间的操作(交换两个元素)。 循环分析:循环运行 n-1 次,其中 n 是字符串的长度。在每次迭代中,都会生成一个随机索引,并执行交换操作。 操作 随机索引生成:rand() % (i + 1) 恒定时间,O(1) 交换操作:它交换两个元素,并且具有恒定时间,O(1) 总时间复杂度:由于这些操作是为字符串中的每个字符(第一个字符除外)执行的,因此时间复杂度为 O(n),其中 n 是字符串的长度。这意味着所需时间随输入大小线性增长。 可打印字符串验证 (isPrintableString) 此函数遍历字符串中的每个字符以检查其是否可打印。 循环分析:循环运行 n 次,其中 n 是字符串的长度,检查每个字符的可打印性。 操作 检查可打印性 (isprint):恒定时间,O(1) 总时间复杂度:该函数也具有线性时间复杂度 O(n),因为它必须检查字符串中的每个字符。 多次洗牌 (shuffleMultipleTimes) 此函数多次调用 fisherYatesShuffle 函数(如 times 参数所示)。 循环分析:外循环运行 times 次迭代,对于每次迭代,fisherYatesShuffle 函数运行,其复杂度为O(n)。 总时间复杂度:如果 times 是一个常量 c,则复杂度仍然是 O(n)。但是,如果 times 取决于输入大小,则复杂度将为 O(cn),这简化为 O(n),因为 c 是一个常数乘数。 总体时间复杂度 该程序的总体时间复杂度由最复杂的操作决定,在本例中是 Fisher-Yates 洗牌。因此,总体时间复杂度保持为 O(n)。 空间复杂度 Fisher-Yates 洗牌函数 (fisherYatesShuffle) 该函数就地操作,这意味着它不需要与输入大小成比例的额外空间。 辅助空间:它使用一些变量(用于索引和交换的临时变量),这些变量独立于输入大小。 总空间复杂度:空间复杂度为 O(1),表示与输入大小无关的恒定空间使用。 可打印字符串验证 (isPrintableString) 与洗牌函数类似,此函数也就地操作并使用恒定的额外空间。 多次洗牌 (shuffleMultipleTimes) 此函数也不需要超出 fisherYatesShuffle 函数所用空间的额外空间。 总体空间复杂度 整个程序的操作使用恒定空间 O(1),因为它不分配与输入大小成比例的额外内存。 方法 2:随机排列生成生成索引的随机排列是一种字符串打乱方法,它涉及创建字符索引的排列,然后根据该排列重新排列字符串。此方法提供了灵活性,并且在各种场景中都很有用,例如当您需要将相同的排列应用于多个数组时,或者当您需要保留原始顺序以便以后参考时。 程序输出 Original: example string for permutation Permuted: oesnnptarmtmirulrfixeo gap et 说明提供的 C 代码演示了一种使用 Fisher-Yates 洗牌算法生成字符串字符随机排列的方法。这种方法是一个健壮且富有教育意义的示例,说明了如何在 C 语言中处理字符串操作和随机化。 代码的主要目标是以随机顺序打乱字符串中的字符。这是通过首先生成代表字符串中字符位置的索引排列,然后根据此排列重新排列字符来实现的。
复杂度分析 时间复杂度 Fisher-Yates 洗牌函数 Fisher-Yates 洗牌函数是生成随机排列的核心。以下是其时间复杂度分步解析: 初始化:除了设置循环之外,该函数不执行任何显著的初始化。 循环执行:Fisher-Yates 洗牌的核心操作是从 n-1 向下到 1 运行的 for 循环。在每次迭代中,算法执行一个恒定时间的操作:选择一个随机索引并交换两个元素。 循环执行n-1 次,其中 n 是 indices 数组中的元素数量。每次迭代都涉及恒定数量的操作:生成一个随机索引和交换两个元素。 因此,此算法部分的时间复杂度为O(n)。 Permute String 函数 此函数涉及几个不同的步骤: 内存分配:内存为 indices 数组分配,并且结果字符串涉及每次分配 O(n) 时间。虽然这很重要,但相对于要分配的元素数量,它通常是恒定时间。 初始化索引:使用顺序值初始化 indices 数组需要一次遍历数组,这需要O(n) 时间。 洗牌索引:如上所述,应用于 indices 数组的 Fisher-Yates 洗牌是 O(n)。 重新排列字符串:根据打乱的索引创建新字符串,需要一次遍历字符串来复制字符,这需要O(n) 时间。 复制回和清理:将排列后的结果复制回原始字符串并释放分配的内存的操作也需要 O(n) 时间用于复制和 O(1) 时间用于释放内存。 将所有这些操作加在一起,时间复杂度中的主导因素是 O(n),因为所有主要操作(洗牌、重新排列和复制)都与字符串长度呈线性关系。 空间复杂度 内存分配 indices 数组:分配一个大小为 n 的数组来保存索引。这需要 O(n) 空间。 结果字符串:分配一个大小为 n 的新字符串来存储排列后的结果,这需要O(n) 空间。 附加空间 临时变量:该函数使用一些额外的变量(temp、i、j),但这些变量只消耗恒定的空间,即 O(1)。 总体空间复杂度 总空间复杂度由动态分配数组的大小决定。indices 数组和结果字符串都与输入字符串的长度成正比。 因此,此函数的空间复杂度为O(n)。 |
我们请求您订阅我们的新闻通讯以获取最新更新。