Delphi - 什么对象(多维数组等)可以工作?

时间:2011-12-02 22:00:53

标签: delphi delphi-2010 structure

我需要按排序顺序保留前十个值。我的数据结构是:

TMyRecord = record
  Number: Integer;
  Value: Float;
end

我将计算一堆浮点值。我需要保持前10个浮动值。每个值都有一个相关的数字。我想添加“sets”...如果我的浮点值高于前10位中的一个,它应该将自己添加到列表中,然后“旧”数字10(现在为11)被丢弃。我应该能够以(浮点值)排序顺序访问列表...

它几乎就像一个TStringList,它维护排序顺序......

Delphi 2010中是否已经内置了这样的内容?

4 个答案:

答案 0 :(得分:5)

您可以使用通用列表Generics.Collections.TList<TMyRecord>和插入排序的组合。

您的数据结构是这样的

TMyRecord = record
  Number: Integer;
  Value: Float;
end;

var
  Top10: TList<TMyRecord>;

您需要使用Generics.Collections来获取通用列表。

像这样实例化:

Top10 := TList<TMyRecord>.Create;

使用此功能添加到列表中:

procedure Add(const Item: TMyRecord);
var
  i: Integer;
begin
  for i := 0 to Top10.Count-1 do 
    if Item.Value>Top10[i].Value then
    begin
      Top10.Insert(i, Item);
      Top10.Count := Min(10, Top10.Count);
      exit;
    end;
  if Top10.Count<10 then
    Top10.Add(Item);
end;

这是插入排序的简单实现。使该算法有效的关键是确保列表始终有序。

答案 1 :(得分:4)

大卫的答案很棒,但我认为随着数据的逐步推进,您将非常快速地填充列表,并且值大于列表中已有值的几率可能随着时间的推移而降低。

因此,为了提高性能,我认为您可以在for循环之前添加此行,以快速丢弃不会进入前10名的值:

if (Item.Value <= Top10[Top10.Count - 1].Value) and (Top10.Count = 10) then
  Exit;

如果浮点数总是高于某个阈值,那么使用值低于阈值的10个占位记录来初始化数组可能是有意义的,这样您就可以将第一行更改为:

if (Item.Value <= Top10[9].Value) then
  Exit;

并改进方法:

procedure Add(const Item: TMyRecord);
var
  i: Integer;
begin

  // Throw it out if it's not bigger than our smallest top10
  if (Item.Value <= Top10[9].Value) then
    Exit;

  // Start at the bottom, since it's more likely
  for i := 9 downto 1 do 
    if Item.Value <= Top10[i - 1].Value then
    begin
      // We found our spot
      Top10.Insert(i, Item);
      // We're always setting it to 10 now
      Top10.Count := 10;
      // We're done
      Exit;
    end;

  // Welcome, leader!
  Top10.Insert(0, Item);
  // We're always setting it to 10 now
  Top10.Count := 10;
end;

答案 2 :(得分:2)

由于您使用的是固定数量的项目,因此可以使用普通的TMyRecord数组,例如:

type
  TMyRecord = record 
    Number: Integer; 
    Value: Float; 
  end;

const
  MaxRecordsInTopTen = 10;

var
  TopTen: array[0..MaxRecordsInTopTen-1] of TMyRecord; 
  NumRecordsInTopTen: Integer = 0;

procedure CheckValueForTopTen(Value: Float; Number: Integer);
var
  I, J, NumToMove: Integer;
begin
  // see if the new Value is higher than an value already in the list
  for I := 0 to (NumRecordsInTopTen-1) do
  begin
    if Value > TopTen[I].Value then
    begin
      // new Value is higher then this value, insert before
      // it, moving the following values down a slot, and
      // discarding the last value if the list is full

      if NumRecordsInTopTen < MaxRecordsInTopTen then
        NumToMove := NumRecordsInTopTen - I
      else
        NumToMove := MaxRecordsInTopTen - I - 1;

      for J := 1 to NumToMove do
        Move(TopTen[NumRecordsInTopTen-J], TopTen[NumRecordsInTopTen-J-1], SizeOf(TMyRecord));

      // insert the new value now
      TopTen[I].Number := Number;
      TopTen[I].Value := Value;
      NumRecordsInTopTen := Min(NumRecordsInTopTen+1, MaxRecordsInTopTen);

      // all done
      Exit;
    end;
  end;

  // new value is lower then existing values,
  // insert at the end of the list if room
  if NumRecordsInTopTen < MaxRecordsInTopTen then
  begin
    TopTen[NumRecordsInTopTen].Number := Number;
    TopTen[NumRecordsInTopTen].Value := Value;
    Inc(NumRecordsInTopTen);
  end;
end;

答案 3 :(得分:1)

除了直接的Object Pascal,我不会打扰任何东西。

{$APPTYPE CONSOLE}
program test2; uses sysutils, windows;
  const
    MAX_VALUE = $7FFF;
    RANDNUMCOUNT = 1000;
  var
    topten: array[1..10] of Longint;
    i, j: integer;
    Value: Longint;
  begin
    randomize;
    FillChar(topten, Sizeof(topten), 0);
    for i := 1 to RANDNUMCOUNT do
      begin
        Value := Random(MAX_VALUE);
        j := 1;
        while j <= 10 do
          begin
            if Value > topten[j] then
              begin
                 Move(topten[j], topten[j+1], SizeOf(Longint) * (10-j));
                 topten[j] := Value;
                 break;
              end;
            inc(j);
          end;
     end;
    writeln('Top ten numbers generated were: ');
    for j := 1 to 10 do
      writeln(j:2, ': ', topten[j]);
    readln;
  end.