Во-первых, использование operator<
для обозначения «предшествует» - это странно . Я знаю, что это упражнение, я просто не хочу, чтобы вы думали, что это нормально.
Теперь ваш круговой список хранит начало и конец в объекте контейнера верхнего уровня, поэтому нет возможности для самого узла чтобы сказать, голова это или след, или разворот. Это может сказать только контейнер.
Обычное решение для кольцевых списков - установить контрольный узел между головой и хвостом. Тогда sentinel.next
- это голова, sentinel.prev
- это хвост, и вам нужен какой-то способ пометить самого часового (либо значение magi c, равное data
, либо дополнительный флаг). Затем этот контрольный узел может заменить два указателя в вашем объекте-контейнере (так что вы не тратите впустую место).
У часового есть дополнительное преимущество, заключающееся в том, что вам никогда не придется беспокоиться о nullptr в пустом списке.
Между прочим, мне очень странно, что инструкторы оставляют использование двусвязных списков и не показывает расположение дозорных. Он описан на нескольких страницах в копии книги Элсона о структурах данных, которую я унаследовал и которая была опубликована в 1975 году. Какой смысл намеренно обучать плохому двусвязному списку?
Если они хотят, чтобы вы выяснили это сами, им следовало бы попросить вас проработать основные операции со списком, а не эти нечетные операторы «предшествует / завершается», поскольку базовые c операции могут действительно работать без дозорного, но заметно улучшены с его дополнением.