【发布时间】:2015-03-20 14:20:17
【问题描述】:
我参加 DSA 课程已经快十年了。我浏览过Wikipedia's list of sorting algorithms,但没有一个能像这个一样突出。它是优先级队列实现的一部分,似乎排序的一部分发生在推送函数 (EnQueue) 中,而另一部分发生在弹出函数 (DeQueue) 中。
这是原始的 Mathematica 代码,但由于大多数人不熟悉 Mathematica,我在每个函数下方进行了一些翻译。
EnQueue[q : queue[ar_, n_, pred_], val_] := Module[{i, j},
If[n == Length[ar], ar = Join[ar, makeArray@Length@ar]];
n++; ar[[n]] = val;
i = n;
While[True,
j = Quotient[i, 2];
If[j < 1 || pred[ar[[j]], ar[[i]]],
Break[]
];
ar[[{i, j}]] = {ar[[j]], ar[[i]]};
i = j;
];
q
]
EnQueue 函数首先检查元素的数量n 是否已达到堆的大小ar,如果是,则将堆加倍。接下来,它增加元素的数量并将新元素存储在该索引处(Mathematica 索引是从 1 开始的,而不是从 0 开始的)。然后,它将i 设置为(新元素的)该索引,并进入将j 设置为floor(i/2) 的循环,即堆中间的某个元素。现在,如果j < 1(据我所知,这相当于检查i == 1),或者ar[j](中间的元素)应该在@987654335之前@(新元素),然后我们打破。否则,我们交换i和j处的元素,然后继续;所以在第二次迭代中,我们从i 指向中间 开始,j 指向四分之一路径。
DeQueue[queue[ar_, n_, pred_]] :=
Module[{i, j, res = ar[[1]]},
ar[[1]] = ar[[n]]; ar[[n]] = Null; n--;
j = 1;
While[j <= Quotient[n, 2],
i = 2 j;
If[i < n && pred[ar[[i + 1]], ar[[i]]],
i++
];
If[pred[ar[[i]], ar[[j]]],
ar[[{i, j}]] = {ar[[j]], ar[[i]]};
];
j = i];
res]
同时,DeQueue 返回堆的前端,并将堆的后端移到前端(并取消设置后端,并减少元素的数量)。然后,从指向前面的j 开始,它进入一个循环,该循环首先将i 设置为双j。 如果i 在边界内(指向一个元素)但相对于下一个元素是无序的,则i 会递增。如果i 相对于j 是有序的(前面;换句话说,如果前面相对于i 顺序out),那么交换两个位置,并且j 设置为i 所在的位置。我们继续循环直到j 通过中间。
主要是上面的粗体部分我不明白。我认为它正在做的是对DeQueue 上的堆进行排序一半,并为EnQueue 中的新元素做一些排序,但我不是当然……
【问题讨论】:
-
通常称为堆排序。见the Wikipedia article。要维护的排序属性是每个第 n 个元素与其子元素大于等于(或小于等于,取决于使用的排序),位于位置
2n和2n+1。
标签: algorithm sorting wolfram-mathematica binary-heap