TList 的 quicksort 算法研究和使用。

// 自定义的比较函数

function cmp(p1, p2: pointer): integer;
begin
 

end;

// quicksort原文

procedure QuickSort(SortList: PPointerList; L, R: Integer;
  SCompare: TListSortCompare);
var
  I, J: Integer;
  P, T: Pointer;
begin
  repeat
    I := L;
    J := R;
    P := SortList^[(L + R) shr 1];
    repeat
      while SCompare(SortList^[I], P) < 0 do
        Inc(I);
      while SCompare(SortList^[J], P) > 0 do
        Dec(J);
      if I <= J then
      begin
        T := SortList^[I];
        SortList^[I] := SortList^[J];
        SortList^[J] := T;
        Inc(I);
        Dec(J);
      end;
    until I > J;
    if L < J then
      QuickSort(SortList, L, J, SCompare);
    L := I;
  until I >= R;
end;

前几天用到了Tlist的排序功能,可是按照帮助的说明使用后总是指针错误,我感到非常奇怪和恼火。于是就花了点时间理解了一下quicksort的算法和出错的原因。

比较宏观的讲,quicksort算法就是在需要排列的数组中随机挑选一个数值作为标准,然后将其他的每个数与这个数进行比较,小的排前面,大的排后面。然后将前半部分和后半部分再进行相同的算法运算,直到不能继续分割为止。

 

下面说明语句的功能:

(1)    P := SortList^[(L + R) shr 1];
   这句话的功能就是将数组中间的数取出来作为比较的参考值。因为中间值是随机的,所以参考值也是随机的。 如果将语句改成  P:=SortList^[L]; 效果一样。

(2) while SCompare(SortList^[I], P) < 0 do
            Inc(I);
   这句话的功能就是找到比参考值大的数值。这里需要注意了!问题就出现在这里。

  因为是从前往后找的,正常情况下当  I = (L + R) shr 1 时,这个循环就会结束,而且永远不会越界。但是碰巧的是我比较的是两个浮点数,在这里没有等于,所以循环肯定越界。 所以大家在写比较函数的时候一定不能忽略等于的这种情况,一定要有,否则会出错。

(3)      while SCompare(SortList^[J], P) > 0 do
              Dec(J);
这句话功能和上面的相反,从后往前找比参考值小的,直到找到他自己就停止。

(4) if I <= J then
      begin
        T := SortList^[I];
        SortList^[I] := SortList^[J];
        SortList^[J] := T;
        Inc(I);
        Dec(J);
      end;
  这些语句就是将找到的两个数进行交换位置了! 这就是这个算法的精华了,一次交换解决两个数值大小排序。

(5)  if L < J then
      QuickSort(SortList, L, J, SCompare);
中间的repeat 将 [L,R]之间的数值分割为两大阵营(比参考值小的和比参考值大的), 这里就是对前面的阵营继续进行分割。这是一个递归的过程,直到不能分割为止。

算法就简单介绍到这里啦!

不过我觉得最后一句话可以改进一下

   if L < J then
      QuickSort(SortList, L, J, SCompare);     //继续比较前面的阵营
    if I < R then
      QuickSort(SortList, I, R, SCompare);     //继续比较后面的阵营

去掉外面的repeat循环,因为这样写也不会增加递归栈的大小,但是算法意图就很明显了。

posted on   癫狂编程  阅读(113)  评论(0编辑  收藏  举报

编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
历史上的今天:
2017-12-24 Delphi中ClientDataSet.FieldDefs 的 FieldDefs是哪两个单词的缩写?
2017-12-24 Delphi中快速修改变量名称

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
好的代码像粥一样,都是用时间熬出来的
点击右上角即可分享
微信分享提示