Список — различия между версиями
Строка 10: | Строка 10: | ||
===XOR-связный список === | ===XOR-связный список === | ||
В некоторых случаях использование двусвязного списка в явном виде является нецелесообразным. В целях экономии памяти можно хранить только результат выполнения операции Xor над адресами предыдущего и следующего элементов списка. Таким образом, зная адрес предыдущего элемента, мы можем вычислить адрес следующего элемента. | В некоторых случаях использование двусвязного списка в явном виде является нецелесообразным. В целях экономии памяти можно хранить только результат выполнения операции Xor над адресами предыдущего и следующего элементов списка. Таким образом, зная адрес предыдущего элемента, мы можем вычислить адрес следующего элемента. | ||
− | |||
==Циклический список== | ==Циклический список== | ||
Первый элемент является следующим для последнего элемента списка. | Первый элемент является следующим для последнего элемента списка. | ||
Строка 53: | Строка 52: | ||
'''delete''' tmp | '''delete''' tmp | ||
[[Файл:removeAfter.png|center|550px]] | [[Файл:removeAfter.png|center|550px]] | ||
+ | |||
+ | ==Задача на поиск цикла в списке== | ||
+ | Для начала необходимо уметь определять - список циклический или нет. Воспользуемся алгоритмом Флойда "Черепаха и заяц". Пусть за одну итерацию первый указатель(черепаха) переходит к следующему элементу списка, а второй указатель(заяц) на два элемента вперед. Тогда, если эти два указателя встретятся, то цикл найден, если дошли до конца списка, то цикла нет. | ||
+ | '''boolean''' isCycle(head) | ||
+ | firstElement = head.next | ||
+ | secondElement = head.next.next | ||
+ | '''while''' firstElement != secondElement | ||
+ | '''if''' secondElement == ''NULL'' '''or''' secondElement.next == ''NULL'' | ||
+ | '''return''' ''false'' | ||
+ | firstElement = firstElement.next | ||
+ | secondElement = secondElement.next.next | ||
+ | '''return''' ''true'' | ||
+ | |||
+ | Возможны два варианта цикла в списке. Первый вариант - сам список циклический(указатель next последнего элемента равен первому), а второй вариант - цикл внутри списка(указатель next последнего элемента равен любому другому(не первому). В первом случае найти длину цикла тривиально, во второй случай сводится к первому, если найти указатель на начало цикла. Для того, чтобы его найти, запомним момент, когда в предыдущей функции два указателя оказались равны друг другу. Теперь достаточно запустить один указатель из этого места списка, а другой из головы с одной скоростью. Элемент, где оба указателя встретятся будет началом цикла. | ||
+ | Ниже приведена функция, которая находит эту точку, а возвращает длину хвоста списка. | ||
+ | '''int''' getTail(head, pointMeeting) | ||
+ | firstElement = head.next | ||
+ | secondElement = pointMeeting.next | ||
+ | lengthTail = 1 | ||
+ | '''while''' firstElement != secondElement | ||
+ | firstElement = firstElement.next | ||
+ | secondElement = secondElement.next | ||
+ | lengthTail = lenghtTail + 1 | ||
+ | '''return''' lengthTail | ||
==См.также== | ==См.также== | ||
Строка 60: | Строка 83: | ||
* [[wikipedia:Linked_list | Wikipedia {{---}} Linked list]] | * [[wikipedia:Linked_list | Wikipedia {{---}} Linked list]] | ||
* [[wikipedia:ru:Список_(информатика) | Википедия {{---}} Список]] | * [[wikipedia:ru:Список_(информатика) | Википедия {{---}} Список]] | ||
− | * Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ | + | * Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ {{---}} 2-е изд. {{---}} М.: «Вильямс», 2007. {{---}} Глава 11.2. {{---}} ISBN 5-8489-0857-4 |
− | * Дональд Э. Кнут Искусство программирования. Том 1. Основные алгоритмы | + | * Дональд Э. Кнут Искусство программирования. Том 1. Основные алгоритмы {{---}} 2-е изд. {{---}} М.: «Вильямс», 2012. {{---}} Глава 2.2. {{---}} ISBN 0-201-89685-0 |
[[Категория: Дискретная математика и алгоритмы]] | [[Категория: Дискретная математика и алгоритмы]] | ||
[[Категория: Амортизационный анализ]] | [[Категория: Амортизационный анализ]] |
Версия 18:20, 11 июня 2014
Связный список (англ. List) — структура данных, состоящая из элементов, содержащих помимо собственных данных ссылки на следующий и/или предыдущий элемент списка. С помощью списков можно реализовать такие структуры данных как стек и очередь.
Содержание
Односвязный список
Простейшая реализация списка. В узлах хранятся данные и указатель на следующий элемент в списке.
Двусвязный список
Также хранится указатель на предыдущий элемент списка, благодаря чему становится проще удалять и переставлять элементы.
XOR-связный список
В некоторых случаях использование двусвязного списка в явном виде является нецелесообразным. В целях экономии памяти можно хранить только результат выполнения операции Xor над адресами предыдущего и следующего элементов списка. Таким образом, зная адрес предыдущего элемента, мы можем вычислить адрес следующего элемента.
Циклический список
Первый элемент является следующим для последнего элемента списка.
Операции на списке
Рассмотрим базовые операции на примере односвязного списка.
Вставка
Очевиден случай, когда необходимо добавить элемент (
) в голову списка. Установим в этом элементе ссылку на старую голову, и обновим указатель на голову.function insert(newHead) newHead.next = head head = newHead
Если же на нужно вставить элемент (
) в определенную позицию после какого-то другого элемента ( ), то просто изменим соответствующие ссылки.function insertAfter(thisElement, thatElement) thatElement.next = thisElement.next thisElement.next = thatElement
Поиск
Для того, чтобы найти элемент по значению (
), будем двигаться по списку от головы до конца и сравнивать значение в элементах с искомым. Если элемента в списке нет, то возвращаем .Node Search(value) node = head while node != NULL and value != node.value node = node.next return node
Удаление
Для того, чтобы удалить голову списка, переназначим указатель на голову на второй элемент списка, а голову удалим.
function removeHead() if head != NULL tmp = head head = head.next delete tmp
Удаление элемента после заданного (
) происходит следующим образом: изменим ссылку на следующий элемент на следующий за удаляемым, затем удалим нужный объект.function removeAfter(thisElement) if thisElement.next != NULL tmp = thisElement.next thisElement.next = thisElement.next.next delete tmp
Задача на поиск цикла в списке
Для начала необходимо уметь определять - список циклический или нет. Воспользуемся алгоритмом Флойда "Черепаха и заяц". Пусть за одну итерацию первый указатель(черепаха) переходит к следующему элементу списка, а второй указатель(заяц) на два элемента вперед. Тогда, если эти два указателя встретятся, то цикл найден, если дошли до конца списка, то цикла нет.
boolean isCycle(head) firstElement = head.next secondElement = head.next.next while firstElement != secondElement if secondElement == NULL or secondElement.next == NULL return false firstElement = firstElement.next secondElement = secondElement.next.next return true
Возможны два варианта цикла в списке. Первый вариант - сам список циклический(указатель next последнего элемента равен первому), а второй вариант - цикл внутри списка(указатель next последнего элемента равен любому другому(не первому). В первом случае найти длину цикла тривиально, во второй случай сводится к первому, если найти указатель на начало цикла. Для того, чтобы его найти, запомним момент, когда в предыдущей функции два указателя оказались равны друг другу. Теперь достаточно запустить один указатель из этого места списка, а другой из головы с одной скоростью. Элемент, где оба указателя встретятся будет началом цикла. Ниже приведена функция, которая находит эту точку, а возвращает длину хвоста списка.
int getTail(head, pointMeeting) firstElement = head.next secondElement = pointMeeting.next lengthTail = 1 while firstElement != secondElement firstElement = firstElement.next secondElement = secondElement.next lengthTail = lenghtTail + 1 return lengthTail
См.также
Источники информации
- Wikipedia — Linked list
- Википедия — Список
- Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 2-е изд. — М.: «Вильямс», 2007. — Глава 11.2. — ISBN 5-8489-0857-4
- Дональд Э. Кнут Искусство программирования. Том 1. Основные алгоритмы — 2-е изд. — М.: «Вильямс», 2012. — Глава 2.2. — ISBN 0-201-89685-0