2015-12-17 5 views
1

У меня есть это:Получить элемент из связанного списка

type 
    PList = ^TSome; 

    TSome = record 
    next :PList; 
... 

var 
    tmp:PList; 
... 
begin 
    tmp := list; 
    while tmp^.next <> nil do 
    tmp := tmp^.next; 
end 

Есть ли способ, чтобы получить элемент на второй индекс?

Как array[2], но поскольку это не массив, это невозможно.

ответ

2

Вот как это обычно делается:

var 
    tmp: PList; 
    index: Integer; 
begin 
    index := 0; 
    tmp := list; 

    repeat 
    tmp := tmp^.next; 
    Inc(Index); 
    until (tmp = nil) or (index = 2); 
end; 
+0

именно второй объект нужен – vpe27339

+0

@fantaghirocco: Я хотел бы использовать 'while' цикл вместо' repeat' цикла, например: 'индекс: = 2; tmp: = list; в то время как (tmp <> nil) и (index> 0) начинаются tmp: = tmp^.next; Декабрь (индекс); end; 'Подумайте, что произойдет, если вызывающий хочет узел с индексом 0; Ваш цикл 'repeat' завершится неудачно. –

+0

@ vpe27339: вы хотите * второй узел в списке *, или * узел в индексе 2 *? Это разные узлы. Индексы начинаются с 0, поэтому первым узлом является индекс 0, второй - индекс 1, третий - индекс 2 и т. Д. –

1

Но это было бы sloooow! намного медленнее, чем массивы.

TSome = record 
    next :PList; 
    ... 

    function GetNext(skip: cardinal): TSome; 
    property ArrayLike[index: cardinal]: TSome read GetNext; default; 
end; 

.... 

{$T+} 
function TSome.GetNext(skip: cardinal): TSome; 
type PSome = PList; 
var candidate: PSome; 
begin 
    candidate := @Self; 
    while skip > 0 do 
    candidate := candidate.Next; 
    if candidate = nil then raise EBoundsError.Create('out of index'); 
    Dec(skip); 
    end; 
    Result := candidate^; 
end; 

... 

var x: TSome; 

x[0] = x.ArrayLike[0] = x; 

ВНИМАНИЕ: поскольку вы работаете с записями, а не с классами - вы получаете КОПИЮ записи не самой записи;

Как в var x,y: TSome; y := x; - вы делаете новую копию данных, а не второй указатель на те же данные.

Это, а также сама проблема структуры списка сделает этот вид доступа медленнее, гораздо медленнее, чем массив.

И

var x,y,z: TSome; i: integer; 

x.SomeValue := 1; 
y.SomeValue := 2; 
x.Next := @y; 

i := x[1].SomeValue; 
// i == 2 (making copy of y, then taking a SomeValue from it) 

x[1].SomeValue := 10; 
z := x[1]; 
z.SomeValue := 20; 

i := x[1].SomeValue; 
// still i == 2 - we were NOT changing the value in y itself, we were making DATA COPIES of y and changing COPIES 
+1

Указатель на 'TSome' будет лучшим значением результата для' GetNext' и 'ArrayLike'. –

+0

@LURD performance-wise - да, но: 1) тема стартера попросила «получить элемент» не ptr, а 2: он все равно будет медленным, списки не предназначены для произвольного доступа –

Смежные вопросы