自从我参加 DSA 课程以来,已经快十年了。我浏览了Wikipedia 的排序算法列表,但没有一个比这更突出。它是优先级队列实现的一部分,似乎排序的一部分发生在 push 函数 ( EnQueue
) 中,而另一部分发生在 pop 函数中 (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
(据我所知,这相当于检查 if i == 1
),或者ar[j]
(中间的元素)是否应该在ar[i]
(新元素)之前,那么我们就中断了。否则,我们交换元素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
为 double开始的循环j
。如果i
在边界内(指向一个元素)但相对于下一个元素是无序的,i
则递增。如果i
相对于j
(前部;换句话说,如果前部相对于 )是有序的,i
则交换两个位置,并j
设置为所在的位置i
。我们继续循环,直到j
经过中间。
大部分是上面的粗体部分我不明白。我认为它正在做的是对一半的堆进行排序DeQueue
,并为 中的新元素做一些排序EnQueue
,但我不确定......