例如:
type
  TMyArr = array of string;
var
  aMyArr: TMyArr;
begin
  SetLength(aMyArr, 10000);
  //如果我想删除第5000个元素,如何快速的删除它?
end;如果是一个链表,那么可以把第4999个元素的指针指向第5001个元素,同理第5001个元素的指针指向第4999个元素,就完成了这个删除的操作。但是在Delphi里类似这样的动作如何处理呢?

解决方案 »

  1.   

    数组没有这个功能,delphi中的数组不像java和javascript中的数组是类,不提供操作数组的方法
      

  2.   

    你是指把下标为[5000]的元素删除,当访问这个元素时得到的是[5001]的值,那就移动它后面的元素向前一个位置吧,或者新建一个一样大的数组,把旧的除了[500]之外的依次拷进去,好像C++中String类就是这样实现的
      

  3.   

    那两位的高见是如果硬要把数据从数组删除,就必须用循环来搬数据了?
    要么就用2维数组,把另一维用0和1纪录着数据是否被删除?
    要么用zhengji(看雨飞) 的方法:写个链表类,但给出按序号取元素的方法,以此来模拟数组?其他朋友还有其他的做法吗?
      

  4.   

    不是有TStringList对象么
    它有delete方法
    添加数据用add方法如果非要数组的话,也没什么好的方法
      

  5.   

    想不到大家回帖比较快,在这里谢谢大家。
    引用ctcpp的看法:那就移动它后面的元素向前一个位置吧,或者新建一个一样大的数组,把旧的除了[500]之外的依次拷进去,好像C++中String类就是这样实现的
    ==========================================================================================
    如果把数据向前移动,当要移动的数据在整个数组前端时,移动的动作很大。而且当整个数组很大时,这样移动比较费资源。
      

  6.   

    这是没办法的事情,这是数组的特点,如果想添加或者删除就要伴随着数组的移动,
    就算是TStringList也是一样的,也用到了System.Move来移动数组,他毕竟不是链表。所以,我觉得你是用System.Move来移动数组,效率还是可以得。
      

  7.   

    如果是Array of string ;就没有必要用数组了,用TStringList吧
    如果是Array of integer(Shortint,SmallInt,Byte,Word,Dword,Single,Real48,Real,Extended,Pointer);可以考虑使用内存块移动,建议看看TList的Delete(Index:integer)的实现过程,如果是对TList比较熟悉,干脆用TList来保存他们的指针,用New和Dispose来管理
    如果是Array of 结构,建议使用TList
      

  8.   

    Array of string只是打个比喻,其实数组可能是Array of TJPEG或者其他比较大的数组。
    ==========================================================================================
    引用 kiboisme(蓝色光芒) :建议看看TList的Delete(Index:integer)的实现过程,如果是对TList比较熟悉,干脆用TList来保存他们的指针,用New和Dispose来管理指针应该蛮快的,可能这个办法效率比较高。
    ==========================================================================================
    引用  flyforlove(为情飞) :
    我觉得你是用System.Move来移动数组,效率还是可以得这个方法比起上面kiboisme(蓝色光芒) 提到的方法不知效率如何呢?
      

  9.   

    提醒楼主:
    Array of TEveryObject 和 Array of DWORD 是一回事。
    唯一不同的是:前者在删除前需要作 ().Free
      

  10.   

    引用: kiboisme(蓝色光芒) 
    提醒楼主:
    Array of TEveryObject 和 Array of DWORD 是一回事。
    唯一不同的是:前者在删除前需要作 ().Free
    ==============================================================================
    受教了。那你言下之意是除了类似Array of DWORD 结构的数组,还有其他结构的数组?请问是什么结构的呢?
      

  11.   

    TList也是对数组的一个包装,所以在delete和insert的时候也会移动数组(看一下Tlist的源码就知道了)。
    我想kiboisme(蓝色光芒)的意思是让你用TList管理指针数组。
    鉴于你的问题,我觉得你用TStringList就可以了,其实它的内部实现就是用的System.Move
      

  12.   

    Array of string只是打个比喻,其实数组可能是Array of TJPEG或者其他比较大的数组。TStringList并不适合所有数组吧?
    看来大数组用指针管理应该很方便。
      

  13.   

    楼主:
    比如:
    array of TMsg;
    或者
    TXXX = Record
      ID : integer;
      Name : String;
      Sex : Boolean;
      .......
    end;
    Array of TXXX;
     flyforlove(为情飞):我想kiboisme(蓝色光芒)的意思是让你用TList管理指针数组。就是这个意思。
    这样的东西结构数组,用Move来实现是非常复杂。
    所以建议用TList来管理指针。
      

  14.   

    当然,如果你的数组里的没个单元的顺序根本就没有影响的话,可以简单的这么作:Ars : array of TXXXSetLength(Ars,10000);
    ........
    下面是删除第5000个数据:
    Ars[5000] := Ars[High(Ars)];
    SetLength(Ars,Length(Ars)-1);
    就行了,最多就是判断一下数组的长度。
      

  15.   

    TList采用的应该是动态内存管理了,而非连续的内存管理,TList自己实现了相对内存地址和物理内存地址的自动映射的方式.昨晚看了Linux部分的有关内存管理方面的知识得出来的看法,楼主所说的问题,是所有连续内存管理的缺点,是不可避免的,这种管理还容易造成存储的碎片.系统会在一定的时间里面自动清理内存碎片以及重新排列已用内存空间和空闲内存空间,但是耗用的CPU 资源是很大的!因此引入了这种动态链接式的称为页方式的内存管理方式!
      

  16.   

    用内存搬运函数move, 没有更快的办法了。代码如下:delphi5下通过。
    program Del;
    {$APPTYPE CONSOLE}
    uses
      SysUtils;
    var
      a: array[1..100] of string;
      i: Integer;
    begin
      for i:= 1 to 100 do
        a[i] := IntToStr(i);
      for i:=1 to 100 do
        Write(a[i],' ');
      Writeln;  // 删除地50个字符串
      Move(a[51],a[50],(100-51+1)*sizeof(String));
      
      for i:=1 to 99 do
        Write(a[i],' ');
      Writeln;
      Readln;
    end.
      

  17.   

    kfarvid 说得有点“玄”了。其实,TList 只是封装了一下指针数组,即“指针的数组”,仅此而已。
    如果从 TList 删除一个元素(即指针),该操作等同于从 array of pointer 中删除元素。这里提示楼主一下,array of 类 这个数组的大小 = array of pointer 。因为 Delphi 里没有对对象的引用,而只有指向对象的指针。而 array of 结构体 的大小 = sizeof(结构体) * 数组长度。
      

  18.   

    QuickKeyBoard,
      Move(a[51],a[50],(100-51+1)*sizeof(String));
    这绝对是一个错误,
    Array of String
    实际是数组是只保存了String的指针。
    你这样相当了只移动了指针,后一个指针移动到前面一个,覆盖了前一个指针,内存肯定泄露。
    Sizeof(String)=4
    看看这个程序:
    procedure TForm1.Button1Click(Sender: TObject);
    var
      SS : array of String;
      i : integer;
    begin
      Setlength(SS,2);
      SS[0] := 'A';
      SS[1] := 'B';
      for i:=0 to 22 do
        SS[0] := SS[0] + SS[0]; //让SS[0]有2^22个字符'A'
    //  Move(SS[1],SS[0],Sizeof(String));
      SetLength(SS,0);
    end;如果注释掉Move行,程序运行这个过程后,程序占用的内存,几乎不发生变化
    如果是加上这行,运行这个过程后,程序占用增加了8-9M。
      

  19.   

    kiboisme(蓝色光芒) 很不错很细心。具体原因猜测如下:
    Move(SS[1],SS[0],Sizeof(String));后,让SS[0]原来所指向的字串躲开了Delphi的内存管理。本来String是用引用计数来管理的,现在它的计数为1,而且计数不能够减少,所以delphi也就放过它了。
      

  20.   

    kiboisme(蓝色光芒) ( ) 说的对,在你进行删除的时候,一定别忘了使用System.Finalize来释放资源。
    对于上面那个例子。procedure TForm1.Button1Click(Sender: TObject);
    var
      SS : array of String;
      i : integer;
    begin
      Setlength(SS,2);
      SS[0] := 'A';
      SS[1] := 'B';
      for i:=0 to 22 do
        SS[0] := SS[0] + SS[0]; //让SS[0]有2^22个字符'A'  System.Finalize(SS[0]);   //这儿加这么一句就可以了。  Move(SS[1],SS[0],Sizeof(String));
      SetLength(SS,0);
    end;
      

  21.   

    例如:
    type
      TMyArr = array of string;
    var
      aMyArr: TMyArr;
    begin
      SetLength(aMyArr, 10000);
      //如果我想删除第5000个元素,如何快速的删除它?
    end;==================================================================================
    用内存拷贝,将5001以后的所有内容拷从5000位置开始拷贝,长度就是10000-5000
    最后别忘了长度-1测试代码procedure TForm1.FormCreate(Sender: TObject);
    var i:integer;
    begin
      SetLength(aMyArr, 10000);
      for i:=0 to 9999 do
       aMyArr[i]:=inttostr(i);
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      copymemory(@aMyArr[5000],@aMyArr[5001],5000);
      SetLength(aMyArr, 9999);
      showmessage(aMyArr[5000]);
      showmessage(aMyArr[9998]);
      showmessage(aMyArr[9999]);
    end;
      

  22.   

    明白问题所在了。:)
    多谢flyforlove(为情飞)的那句:
    System.Finalize(SS[0]);