Оптимизация метода popBack для собственной реализации списка
Пишу собственную реализацию списка, написал метод popBack, но как мне кажется, он слишком перегружен условными операторами, что должно сказаться на производительности(да и в целом выглядит так себе), можно ли как нибудь его оптимизировать, чтобы выглядел не так ужасно?
void popBack() {
if (head == nullptr) {
return;
}
if (head->next == nullptr) {
delete head;
head = nullptr;
}
else {
Node* prev = nullptr;
Node* curr = head;
while(curr->next != nullptr) {
prev = curr;
curr = curr->next;
}
if(prev != nullptr) {
delete curr;
prev->next = nullptr;
}
}
size--;
}
Ответы (1 шт):
Автор решения: DmitryK
→ Ссылка
Да в принципе нормальный метод. Есть немного замечаний по стилю:
- это не метод, а просто функция. Если это метод класса (что было бы хорошо), нужно это указать
- можно догадаться по реализации, что список однонаправленный, но это же могла быть и логическая ошибка в реализации? Может список двунаправленный?
- popback() означает извлечение элемента из списка, а не просто удаление, т.е. метод наверное должен возвращать копию элемента списка. Но это просто замечание, Вы сами выстраиваете логику работы списка.
- поскольку у списка есть параметр
sizeто проверять на пустой список и список из 1 элемента можно не по указателям, а саму переменную - будет чуть-чуть быстрее - последняя проверка
if(prev != nullptr)лишняя, т.к. Вы уже проверили ситуацию когда в списке 1 элемент, т.е. это условие всегдаtrue - откуда в функции берутся переменные
headиsizeможно конечно догадаться. Это либо переменные в экземпляре класса, либо глобальные переменные. Но лучше не догадываться, а обозначить прямо. И имена им дать осмысленные, отличающиеся от локальных переменных. Что-то типаMyListHeadиMyListSize- для глобальных переменных - хоть список и однонаправленный, ничего не мешает хранить указатель не только на начало списка, но и на конец. Точнее лучше хранить указатель на предпоследний элемент (для однонаправленного списка), хотя логика усложняется. В этом случае цикл становится не нужным, сложность работы с линейной O(N) уменьшается до константной.
- использование глобальных переменных - не очень удачная мысль с точки зрения стиля и концепции инкапсуляции в ООП. Либо
popback()это метод класса, который имеет доступ только к переменным экземпляра этого класса, либо внешняя функция, и тогда список лучше передать по ссылке или указателю, как параметр.
struct Node {}
struct MyList
{
Node *Head = nullptr;
Node *Tail = nullptr;
int Size = 0;
};
Node popBack(MyList& List)
{
if(List.Head == nullptr)
{
return Node();
}
...
}
// ---- либо классом
class MyList
{
private:
Node *Head, *Tail;
int Size;
public:
MyList() : Head(nullptr), Tail(nullptr), Size(0) {}
Node popback();
};
void main()
{
MyList list;
list.popback();
}