Интересно, существует ли какая-то логика для изменения односвязного списка с использованием только двух указателей.
Ниже используется для изменения одного связанного списка с использованием трех указателей , а именно p
, q
, r
:
struct node {
int data;
struct node *link;
};
void reverse() {
struct node *p = first,
*q = NULL,
*r;
while (p != NULL) {
r = q;
q = p;
p = p->link;
q->link = r;
}
first = q;
}
Есть ли другой способ изменить связанный список? Что было бы лучшей логикой для переворота односвязного списка с точки зрения временной сложности?
Ответы:
Любая альтернатива? Нет, это настолько просто, насколько возможно, и принципиально другого способа сделать это не существует. Этот алгоритм уже работает O (n) раз, и вы не можете достичь большего, поскольку вы должны изменить каждый узел.
Похоже, ваш код находится на правильном пути, но он не совсем работает в приведенной выше форме. Вот рабочая версия:
источник
reverse()
, я считаю , что последняя строка в функции должна быть установлена первой. В остальном исходный код работал нормально при подключении к аккуратной тестовой обвязке. Даже в этом случае вы получаете от меня +1, но объяснение того, что вы считаете «очевидными ошибками», улучшило бы ваш ответ.Ненавижу сообщать плохие новости, но я не думаю, что ваше трехпозиционное решение действительно работает. Когда я использовал его в следующем тестовом пакете, список был сокращен до одного узла, как показано в следующем выводе:
Вы не получите более высокую временную сложность, чем ваше решение, так как это O (n), и вам нужно посетить каждый узел, чтобы изменить указатели, но вы можете довольно легко сделать решение только с двумя дополнительными указателями, как показано в следующем коде:
Этот код выводит:
что, я думаю, именно то, что вам нужно. Он действительно может это сделать, поскольку, как только вы загрузились
first
в указатель, перемещающийся по списку, вы можете повторно использовать егоfirst
по своему желанию.источник
first
указателя на самом связном список позволяет решению использовать только 2 дополнительные указатели, но 3 общих указатели по - прежнему необходимы для этого.first
. Точно так же решение трехочковый в OP имелаfirst
,p
,q
иr
.источник
Вот код , чтобы отменить однократно связанный список в C .
А вот и наклеено ниже:
источник
Да. Я уверен, что вы можете сделать это так же, как поменять местами два числа, не используя третье . Просто приведите указатели к типу int / long и несколько раз выполните операцию XOR. Это один из тех приемов C, которые создают забавный вопрос, но не имеют практического значения.
Можете ли вы уменьшить сложность O (n)? Нет, не совсем. Просто используйте двусвязный список, если вы думаете, что вам понадобится обратный порядок.
источник
Роберт Седжвик, « Алгоритмы на языке C », Addison-Wesley, 3-е издание, 1997 г., [раздел 3.4]
Если это не циклический список, значит, последняя ссылка - NULL.
источник
Просто для удовольствия (хотя оптимизация хвостовой рекурсии должна помешать ей съесть весь стек):
источник
Чтобы поменять местами две переменные без использования временной переменной,
самый быстрый способ - написать это в одну строку
Так же,
используя два свопа
решение с использованием xor
решение в одну строку
Та же логика используется для переворота связанного списка.
источник
intptr_t
). Хотя интересно - такой способ подкачки неоптимален в современных системах.Вам нужен указатель дорожки, который будет отслеживать список.
Вам понадобится два указателя:
первый указатель для выбора первого узла. второй указатель для выбора второго узла.
Обработка:
Указатель перемещения трека
Укажите второй узел на первый узел
Переместите первый указатель на один шаг, назначив второй указатель одному
Переместите второй указатель на один шаг, назначив указатель дорожки второму
}
источник
Как насчет более читабельного:
источник
Вот более простая версия на Java. Он использует только два указателя
curr
&prev
источник
Определите временную сложность алгоритма, который вы используете сейчас, и должно быть очевидно, что его нельзя улучшить.
источник
Я не понимаю, почему нужно возвращать голову, поскольку мы передаем ее в качестве аргумента. Мы передаем заголовок списка ссылок, затем мы также можем обновить. Ниже представлено простое решение.
источник
источник
Нет, ничего быстрее текущего O (n) сделать нельзя. Вам нужно изменить каждый узел, поэтому время в любом случае будет пропорционально количеству элементов, а это O (n) у вас уже есть.
источник
Использование двух указателей при сохранении временной сложности O (n), наиболее быстрого достижимого, может быть возможно только за счет преобразования числа указателей и замены их значений. Вот реализация:
источник
У меня немного другой подход. Я хотел использовать существующие функции (например, insert_at (index), delete_from (index)), чтобы перевернуть список (что-то вроде операции сдвига вправо). Сложность по-прежнему O (n), но преимущество заключается в более частом повторном использовании кода. Взгляните на метод another_reverse () и дайте мне знать, что вы все думаете.
источник
источник
источник
Да, есть способ использовать только два указателя. То есть путем создания нового связанного списка, в котором первый узел является первым узлом данного списка, а второй узел первого списка добавляется в начало нового списка и так далее.
источник
Вот моя версия:
где
источник
Я использую java для реализации этого, и подход основан на разработке на основе тестов, поэтому тестовые примеры также прилагаются.
Класс Node, представляющий один узел -
Класс обслуживания, который принимает начальный узел в качестве входных данных и резервирует его без использования дополнительного места.
И тестовый пример, который охватывает вышеуказанный сценарий. Обратите внимание, что вам потребуются банки из джунита. Я использую testng.jar; вы можете использовать все, что вам нравится ..
источник
Простой алгоритм, если вы используете связанный список как структуру стека:
На производительность может повлиять дополнительный вызов функции для add и malloc, поэтому алгоритмы перестановки адресов лучше, но этот фактически создает новый список, поэтому вы можете использовать дополнительные параметры, такие как сортировка или удаление элементов, если вы добавляете функцию обратного вызова в качестве параметра в обеспечить регресс.
источник
Вот немного другой, но простой подход в C ++ 11:
Вывод здесь
источник
Ниже приведена одна реализация с использованием 2 указателей (голова и r).
источник
sizeof(size_t) < sizeof(ListNode*)
... вы должны использоватьstd::uintptr_t
.вот небольшое простое решение ...
источник
Вы можете решить эту проблему с помощью только одного дополнительного указателя, который должен быть статическим для обратной функции. Это в O (n) сложности.
источник
В качестве альтернативы вы можете использовать рекурсию -
источник
источник
источник