如何从这些指令中提取算法?
How do I extract an algorithm from these instructions?
我一直在通读 The Art of Computer Programming,虽然它有我无法理解的高等数学时刻,但一些练习很有趣做。
完成其中一个后,我会查看答案,看看我做的是否比书上建议的更好或更差(通常更差),但我没有得到当前答案的答案我正在尝试传达所有信息。
书中的问题和建议的解决方案可以找到here
我理解的是,t
可能是'missing'个元素的个数,也可能是一个一般的常量,但我真正不理解的是看似随意的排序指令它们基于它们的组件,在我看来这就像在原地旋转你的轮子,因为乍一看它不会让你更接近原始订单。并且决定(除其他外)用数字替换成对名称的一部分(文件 G 包含 n−t < i ≤ n 的所有成对 (i,xi))。
所以我的问题很简单,如何从这个答案中提取算法?
澄清一点:
我明白它的目的是什么,以及我将如何将它翻译成 C++。我不明白的是为什么我应该对输入文件的副本进行排序,如果是这样,我按什么标准排序,以及将对的一侧更改为数字的原因。
假设名称是可排序的,并且有足够数量的磁带驱动器来解决问题。定义一对为 (name, next_name),其中 next_name 是西方人的名字。将成对文件的副本复制到另一盘磁带。第一个文件按名称排序,第二个文件按 next_name 排序。磁带排序是自下而上的合并排序或称为多相合并排序的更复杂的变体,但对于这个问题,标准的自下而上的合并排序就足够了。对于 C++,您可以使用 std::stable_sort() 模拟磁带排序,使用 lambda 函数进行比较,第一个文件按名称排序,第二个文件按 next_name 排序。
索引术语用name[1]代表最东边的名字,name[n]代表最西边的名字。
对两个成对的文件进行初始排序后,解决方案指出 "passing over the files" 已完成识别倒数第二个姓氏 name[n-1],但未指定如何进行。在此过程中,我假设 name[n] 也被识别。文件按顺序进行比较,将第一个文件的名称与第二个文件的 next_name 进行比较。不匹配表示名字 name[1] 或姓氏 name[n],或者在极少数情况下,必须检查每个文件中的两个和下一对以确定不匹配表示什么。在标识姓氏 name[n] 时,第二个文件对中的名称将是姓氏 name[n-1] 的倒数第二个。
一旦 name[n-1] 和 name[n] 已知,就会执行使用这两个文件的类似合并的操作,跳过 name[n-1] 和 name[n] 以创建具有对的 F (name[ i], name[i+2]) for i = 1 to n-2 (in name order), G 有两对 (n-1, x[n-1]), and (n, x[n] ),也是按名称顺序(G 和 G' 在最后一步之前按名称顺序)。
F 被复制到 H,并按照算法中的描述执行迭代过程,t 每次加倍,2, 4, 8, ...。每次通过后,F' 包含对 (x[i], x[i+t]) for i = 1 to n-t,然后 G' 被排序并与 G 合并回 G',导致 G' 包含pairs (i, x[i]) for i = n-t to n, in name order.最终所有的对都在 G (i, x[i]) 中结束,因为 i = 1 到 n,按名称顺序,然后 G 按索引(对的左侧部分)排序,导致名称按排序顺序排列。
我一直在通读 The Art of Computer Programming,虽然它有我无法理解的高等数学时刻,但一些练习很有趣做。
完成其中一个后,我会查看答案,看看我做的是否比书上建议的更好或更差(通常更差),但我没有得到当前答案的答案我正在尝试传达所有信息。
书中的问题和建议的解决方案可以找到here
我理解的是,t
可能是'missing'个元素的个数,也可能是一个一般的常量,但我真正不理解的是看似随意的排序指令它们基于它们的组件,在我看来这就像在原地旋转你的轮子,因为乍一看它不会让你更接近原始订单。并且决定(除其他外)用数字替换成对名称的一部分(文件 G 包含 n−t < i ≤ n 的所有成对 (i,xi))。
所以我的问题很简单,如何从这个答案中提取算法?
澄清一点:
我明白它的目的是什么,以及我将如何将它翻译成 C++。我不明白的是为什么我应该对输入文件的副本进行排序,如果是这样,我按什么标准排序,以及将对的一侧更改为数字的原因。
假设名称是可排序的,并且有足够数量的磁带驱动器来解决问题。定义一对为 (name, next_name),其中 next_name 是西方人的名字。将成对文件的副本复制到另一盘磁带。第一个文件按名称排序,第二个文件按 next_name 排序。磁带排序是自下而上的合并排序或称为多相合并排序的更复杂的变体,但对于这个问题,标准的自下而上的合并排序就足够了。对于 C++,您可以使用 std::stable_sort() 模拟磁带排序,使用 lambda 函数进行比较,第一个文件按名称排序,第二个文件按 next_name 排序。
索引术语用name[1]代表最东边的名字,name[n]代表最西边的名字。
对两个成对的文件进行初始排序后,解决方案指出 "passing over the files" 已完成识别倒数第二个姓氏 name[n-1],但未指定如何进行。在此过程中,我假设 name[n] 也被识别。文件按顺序进行比较,将第一个文件的名称与第二个文件的 next_name 进行比较。不匹配表示名字 name[1] 或姓氏 name[n],或者在极少数情况下,必须检查每个文件中的两个和下一对以确定不匹配表示什么。在标识姓氏 name[n] 时,第二个文件对中的名称将是姓氏 name[n-1] 的倒数第二个。
一旦 name[n-1] 和 name[n] 已知,就会执行使用这两个文件的类似合并的操作,跳过 name[n-1] 和 name[n] 以创建具有对的 F (name[ i], name[i+2]) for i = 1 to n-2 (in name order), G 有两对 (n-1, x[n-1]), and (n, x[n] ),也是按名称顺序(G 和 G' 在最后一步之前按名称顺序)。
F 被复制到 H,并按照算法中的描述执行迭代过程,t 每次加倍,2, 4, 8, ...。每次通过后,F' 包含对 (x[i], x[i+t]) for i = 1 to n-t,然后 G' 被排序并与 G 合并回 G',导致 G' 包含pairs (i, x[i]) for i = n-t to n, in name order.最终所有的对都在 G (i, x[i]) 中结束,因为 i = 1 到 n,按名称顺序,然后 G 按索引(对的左侧部分)排序,导致名称按排序顺序排列。