обход односвязного списка в C ++
-
19-09-2019 - |
Вопрос
Мне было интересно, возможно ли пройти по связанному списку следующим образом:
currentNode = randomNode;//where randomNode may or may not = firstNode
prevNode = firstNode;
while(prevNode != currentNode && prevNode->link != currentNode)
{
prevNode = prevNode->link;
}
Возможно ли это сделать на C ++, когда я пытаюсь найти узел перед currentNode в односвязном списке?
Я пытаюсь реализовать что-то подобное в консольном приложении для школьного задания, поэтому предположим, что я не могу использовать ничего необычного, например boost libraries / list / что-нибудь, что облегчает жизнь, и т.д.Таким образом, в принципе, в моем распоряжении есть только довольно примитивные типы данных и библиотеки.
Решение
Возможно, вы захотите убедиться, что prevNode-> link также не является нулевой ссылкой, на случай, если currentNode фактически не связан.
Другие советы
Это должно сработать просто отлично.Вы уже пробовали это?
Этот код будет проходить через некоторую часть вашего списка, но какая именно часть зависит от того, каким способом связан ваш список.Если он идет от головы-> хвост (читать:головной узел ссылается на узел, который ссылается на хвост), затем вы пройдете по своему списку, начиная от случайного местоположения до хвоста.Если ссылки являются головными<-хвост, затем вы пройдете от случайного местоположения к голове.В любом случае, вы не будете касаться всех узлов в списке.
Все вышесказанное предполагает некоторый список ссылок как таковой:
[head]<->[0...N Nodes]<->[Tail]
Ссылки могут быть в любом случае.
Кроме того, вы могли бы связать головной и конечный узлы и создать список с круговыми связями.В этом сценарии можно посетить все узлы, просто перемещаясь до тех пор, пока вы не вернетесь к своему исходному узлу.
Убедитесь, что вы рассмотрели все возможные крайние случаи:
- Что происходит
randomNode
равноfirstNode
?Что вы получаете взамен?Что следует ты возвращаешься? - Что происходит, когда
randomNode
является ли узел последним в списке? - Что происходит, когда
randomNode
являетсяNULL
? - Что происходит, когда
randomNode
его нет в списке?
Так вот, не все из этих случаев могут быть применимы, в зависимости от того, знаете ли вы что-нибудь о randomNode
, и некоторые из них могут быть тривиальными.Но обо всех них стоит подумать.
Если вы очень внимательно рассмотрите все это, то найдете простое и элегантное решение, которое справится со всеми ними.
Код выглядит нормально, но я бы предложил внести незначительные изменения в ваш while
состояние
while(prevNode != currentNode && prevNode != NULL)
По двум причинам
- Ваш код, как указано в настоящее время, может остановиться, если на узел, который мы ищем, указывает либо
prevNode
илиprevNode->link
(и, следовательно, мы не будем иметь ни малейшего представления, на какую именно из двух точек обратить вниманиеcurrentNode
-- если бы мы хотели знать, нам пришлось бы обратиться кif
условие).С учетом приведенного выше изменения целевой узел гарантированно будет сохранен вprevNode
(если вообще есть - смотрите следующий пункт). - В целях безопасности было бы неплохо проверить, что
prevNode
это не такNULL
.Однако, как упоминает Павел, в этом тесте нет необходимости, еслиcurrentNode
гарантированно будет в списке.
Редактировать в ответ на комментарий
Учитывая, что вам не нужно знать, является ли currentNode
находится в prevNode
или prevNode->link
, и поскольку вы хотите остановиться (если возможно) на currentNode == prevNode->link
, тогда ваш оригинальный while
все в порядке.Однако...
выше в коде есть оператор if, который предотвращает
prevNode
от нуль уже
Похоже, вы упускаете из виду, почему вы должны проверять наличие NULL
.Да, это хорошо, что вы проверили это раньше, но причина, по которой у нас есть NULL
проверка в цикле производится в том случае, когда currentNode
является нет в списке, так что в конечном итоге вы дойдете до последнего узла.Предположительно (если вы делаете это, как и большинство других связанных списков) значение link
для вашего последнего узла это NULL
.Если это так, то ваш текущий код в конечном итоге завершит вызов NULL->link
что, конечно же, приведет к сбою вашей программы.Вот почему вы все равно должны проверять наличие NULL
while(prevNode != NULL && prevNode != currentNode && prevNode->link!=currentNode)
Если вы абсолютно уверен это currentNode
будет в списке, тогда я догадываюсь в этой проверке также нет необходимости, но это действительно хорошая привычка.
Вы даже можете иметь:
while (prevNode && prevNode != currentNode)
prevNode = prevNode->link;
Но то, что у вас есть, выглядит прекрасно.
Небольшая вещь, которую я бы изменил в опубликованном коде (помимо обсуждаемой в других ответах возможности завершения конца списка, если currentNode отсутствует в списке, или другой обработки ошибок), заключается в том, что когда цикл while выполнен, вы не знаете, выполняется ли prevNode
или prevNode->link
указывает на currentNode
.Это не огромная проблема (поскольку вы можете легко проверить это), но мне кажется, что лучше всего протестировать эту особую ситуацию перед поиском, чтобы было ясно, что это особый случай.