Что-то не так при рекурсивном изменении связанного списка

Я пытаюсь решить задачу кода, которая требует отменить связанный список. Дан указатель на головной узел.

Вот моя попытка:

struct ListNode* reverseList(struct ListNode* head) {
    if (head==NULL || head->next==NULL) return head;
    struct ListNode* p=reverseList(head->next);
    p->next=head;
    return head;
}

Когда я запускаю всухую, кажется, все работает нормально. Но когда я отправляю код для тестирования, возникает ошибка превышения срока (TLE).

Почему это происходит? Что я делаю не так?

p->next=head; вообще не имеет смысла. p — это перевернутый список (исключая заголовок), и вы хотите установить следующий элемент этого списка в заголовок?
john 05.05.2024 11:44

Очевидно, что если вы собираетесь в какой-то момент перевернуть список, вам нужно установить для head->next значение null, поскольку теперь это будет последний элемент в перевернутом списке. Ваш код этого не делает.

john 05.05.2024 11:46

проверка имеет смысл, рекурсивный вызов тоже. но строки после неверны. Я рекомендую запустить его на простом примере с тремя узлами и работать над ним построчно (ровно рисуя кадры стека), чтобы попытаться найти проблему.

Uriel.Gi 05.05.2024 11:46

Обучение программированию на пути, состоящем из шагов, которые одинаково хорошо работают для C и C++, является узким и запутанным. Позже будет полезно и нетривиально узнать различия. Но сейчас лучше выбрать один из двух языков, и выучить его будет гораздо проще.

Yunnosch 05.05.2024 13:15

Предполагаете ли вы использовать рекурсивную функцию? В противном случае TLE можно было бы объяснить гораздо более быстрым циклом по списку и ожидаемым решением.

BoP 05.05.2024 14:08

Вы используете C или C++? Вам следует использовать оба тега только в том случае, если речь идет о чем-то вроде сравнения между ними. В противном случае укажите тег конкретного языка, который вы используете.

Barmar 05.05.2024 23:48
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
6
81
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

С вашей обратной функцией есть две отдельные проблемы:

  • Он введет цикл в связанный список, если он имеет более одного узла. Это означает, что если есть код, который не ожидает цикла, а просто наивно перебирает все узлы результирующего списка, он попадет в бесконечный цикл. Это может объяснить полученную вами ошибку ограничения времени.

  • Он возвращает исходный заголовок списка. Вместо этого он должен вернуть хвост исходного списка, поскольку это будет первый узел перевернутого списка.

Давайте возьмем простой пример связанного списка всего с двумя узлами со значениями 1 и два. Затем, когда вызывается reverseList, мы можем визуализировать состояние следующим образом:

 head
  ↓
┌────────────┐     ┌────────────┐
│ val: 1     │     │ val: 2     │
│ next: ──────────►│ next: NULL │
└────────────┘     └────────────┘ 

Затем у нас есть рекурсивный вызов, в котором в качестве аргумента передается ссылка на второй узел. Внутри этого рекурсивного вызова этот указатель — head. Я назову это head' (с апострофом) здесь:

 head               head'
  ↓                  ↓
┌────────────┐     ┌────────────┐
│ val: 1     │     │ val: 2     │
│ next: ──────────►│ next: NULL │
└────────────┘     └────────────┘ 

Здесь мы используем базовый случай, и рекурсивный вызов возвращает ссылку на второй узел, которому в контексте вызова присвоена p:

 head                p
  ↓                  ↓
┌────────────┐     ┌────────────┐
│ val: 1     │     │ val: 2     │
│ next: ──────────►│ next: NULL │
└────────────┘     └────────────┘ 

Затем выполняется p->next=head и мы получаем:

     head                p
      ↓                  ↓
    ┌────────────┐     ┌────────────┐
    │ val: 1     │     │ val: 2     │
 ┌─►│ next: ──────────►│ next: ─┐   │
 │  └────────────┘     └────────│───┘ 
 └──────────────────────────────┘

Цикл создан. И теперь, когда return head выполняется, мы видим, что возникают две проблемы: возвращается неверная ссылка на узел, и цикл не прерывается.

Следующий адаптированный код исправляет обе проблемы:

struct ListNode* reverseList(struct ListNode* head) {
    if (head == NULL || head->next == NULL) return head;
    struct ListNode* newHead = reverseList(head->next);
    // The tail of the recursively reversed list is at head->next.
    //    Append the current node (head) at that tail
    head->next->next = head;
    // And terminate the list at the new tail:
    head->next = NULL;
    // Return the new head, not the old head
    return newHead;
}

Другие вопросы по теме

Свести многомерный массив неизвестной глубины к индексированному массиву с ассоциативными строками
Выполнение кода Python слишком медленное из-за узкого места — поиск оптимизации производительности
Поддерживается ли взаимная рекурсия в Котлине?
Проверка рекурсивной структуры данных (например, дерева) с помощью Python Cerberus (v1.3.5)
Как написать SQL-запрос к групповым учетным записям, которые прямо или косвенно имеют одинаковые номера телефонов рекурсивным способом?
Как передать значения при преобразовании рекурсивной функции в итеративную со стеком и циклом while
Обновление таблицы с представлением и получение «бесконечная рекурсия, обнаруженная в правилах для отношения «сотрудники»
Как предсказать переполнение стека? Как и какая память хранится в стеке?
Дочерние реквизиты Infer React в интерфейсе TypeScript
Перемещение четных элементов в начало массива с сохранением относительного порядка