ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 11.12.2025
Просмотров: 3161
Скачиваний: 1
В т о р а я |
с т р о к а |
|
Между в т о р о й и |
т р е т ь е й с т р о к о й |
|
П о с л е д н я я с т р о к а |
||
Нажмите |
< E n t e r > |
д л я з а в е р ш е н и я п р о г р а м м ы . . . |
Обобщенную версию этого связанного списка можно найти в демонстраци онной программе G e n e r i c L i n k e d L i s t C o n t a i n e r на прилагаемом ком пакт-диске. Обратите внимание, что G e n e r i c L i n k e d L i s t C o n t a i n e r продолжает использовать интерфейс I E n u m e r a t o r , который будет рас смотрен немного позже, но в некоторых ситуациях следует применять вме сто него новую обобщенную версию I E n u m e r a t o r < T > . Однако пока не стоит начинать анализировать обобщенные классы. Кроме того, обратитесь к встроенному обобщенному классу L i n k e d L i s t , который, несомненно, превосходит написанный здесь.
Зачем нужен связанный список
Связанный список может показаться пустыми хлопотами. Его основное преимущест во заключается в большой скорости вставки и удаления узлов. "Ну хорошо, — можете сказать вы. — Но ведь добавление s t r i n g в массив из четырех или пяти строк не слож нее перемещения нескольких ссылок для освобождения места." А что вы скажете, если этот массив будет содержать несколько сотен тысяч строк, и вы должны выполнять мас су вставок и удалений из него?
Второе преимущество связанного списка в том, что он может расти и уменьшаться. Если вы думаете, что вам будут нужны 1000 объектов, то вы должны создать массив на 1000 элементов, независимо от того, будете вы их использовать или нет. Что еще хуже, если вы в действительности создадите 2000 объектов, то можете считать, что в этот раз вам крупно не повезло. (Да, конечно, можно создать второй массив с большей емкостью и скопировать в него содержимое первого, но что при этом можно сказать об эффектив ности и затратах памяти?)
На этом принципе основаны многие распространенные вирусы. Например, неко торый исполненный благих намерений программист решает, что 256 символов будет достаточно для любого имени файла, и объявляет массив c h a r [ 2 5 6 ] . Ес ли программист забудет убедиться, что имя на самом деле не длиннее, чем ожи дается, то у хакера появляется шанс сломать программу, передав ей неправдопо добно длинное имя, и переписать тем самым часть кода за массивом (это называ ется переполнением буфера). Впрочем, это проблема в первую очередь C/C++: С# автоматически проверяет выход за границы массива.
В оставшейся части главы будут проанализированы три разных подхода к общей за даче итерирования коллекции. В этом разделе будет продолжено обсуждение наиболее традиционного (как минимум, для программистов на С#) подхода с использованием ите раторов, которые реализуют интерфейс I E n u m e r a t o r . В качестве примера рассматри вается итератор для связанного списка из предыдущего раздела.
Глава 20. Работа с коллекциями |
461 |
I E n u m e r a t o r предоставляет три следующих метода.
R e s e t () — устанавливает итератор таким образом, чтобы он указывал на начало коллекции. Примечание: обобщенная версия I E n u m e r a t o r , I E n u m e r a t o r < T > , не предоставляет метод R e s e t ( ) . В случае обобщенного L i n k e d L i s t просто начинайте работу с вызова M o v e N e x t ( ) .
M o v e N e x t () — перемещает итератор от текущего объекта в контейнере к сле дующему.
C u r r e n t — свойство (не метод), которое дает объект данных, хранящийся в те кущей позиции итератора.
Описанный принцип продемонстрирован приведенной далее функцией. Про граммист класса M y C o l l e c t i o n (не показанного здесь) создает соответствующий класс итератора — скажем, I t e r a t o r M y C o n t a i n e r (применяя соглашение об именах I t e r a t o r X , упоминавшееся ранее). Прикладной программист ранее сохра нил ряд объектов C o n t a i n e d D a t a O b j e c t s в коллекции M y C o l l e c t i o n . Приве денный далее фрагмент исходного текста использует три стандартных метода I E n u m e r a t o r для чтения этих объектов:
/ / К л а с с M y C o l l e c t i o n х р а н и т о б ъ е к т ы т и п а |
|
|
||||||||
/ / C o n t a i n e d D a t a O b j e c t |
d a t a |
|
|
|
|
|
|
|||
void |
M y F u n c t i o n ( M y C o l l e c t i o n |
m y C o l l ) |
|
|
|
|||||
{ |
|
|
|
|
|
|
|
|
|
|
/ / П р о г р а м м и с т , |
с о з д а в ш и й к л а с с M y C o l l e c t i o n , |
с о з д а л т а к ж е |
||||||||
/ / и к л а с с и т е р а т о р а |
I t e r a t o r M y C o l l e c t i o n ; |
п р и к л а д н о й |
||||||||
/ / п р о г р а м м и с т |
с о з д а е т о б ъ е к т и т е р а т о р а д л я п р о х о д а п о |
|||||||||
/ / |
о б ъ е к т у m y C o l l |
|
|
|
|
|
|
|
|
|
I E n u m e r a t o r i t e r a t o r |
= |
n e w |
I t e r a t o r M y C o l l e c t i o n ( m y C o l l ) ; |
|||||||
/ / п е р е м е щ а е м и т е р а т о р в |
" с л е д у ю щ у ю п о з и ц и ю " в н у т р и |
|||||||||
/ / к о л л е к ц и и |
|
|
|
|
|
|
|
|
|
|
w h i l e ( i t e r a t o r . M o v e N e x t ( ) ) |
|
|
|
|
|
|
||||
{ |
|
|
|
|
|
|
|
|
|
|
|
/ / П о л у ч а е м с с ы л к у н а о б ъ е к т д а н н ы х в т е к у щ е й п о з и ц и и |
|||||||||
|
/ / к о л л е к ц и и |
|
|
|
|
|
|
|
|
|
|
C o n t a i n e d D a t a O b j e c t |
c o n t a i n e d D a t a ; |
/ / d a t a |
|
||||||
|
c o n t a i n e d = |
( C o n t a i n e d D a t a O b j e c t ) i t e r a t o r . C u r r e n t ; |
||||||||
|
/ / . . . и с п о л ь з у е м о б ъ е к т |
д а н н ы х |
c o n t a i n e d . . . |
|
||||||
Функция M y F u n c t i o n () |
принимает |
в |
качестве аргумента |
коллекцию C o n |
||||||
t a i n e d D a t a O b j e c t s . Она |
начинается с |
создания |
итератора |
типа I t e r a t o r M y |
||||||
C o l l e c t i o n . Функция начинает цикл с вызова M o v e N e x t ( ) . При первом вызове MoveNext () перемещает итератор к первому элементу коллекции. При каждом по следующем вызове M o v e N e x t () перемещает указатель "на одну позицию." Функ ция M o v e N e x t () возвращает f a l s e , когда коллекция исчерпана и итератор боль ше нельзя передвинуть.
Свойство C u r r e n t возвращает ссылку на объект данных в текущей позиции итера тора. Программа преобразует возвращаемый объект в C o n t a i n e d D a t a O b j e c t перед тем, как присвоить его переменной c o n t a i n e d . Вызов C u r r e n t некорректен, если предшествующий вызов метода M o v e N e x t () не вернул t r u e .
Глава 20. Работа с коллекциями |
463 |