In my previous post I had a number of steps given to me from the accepted answer on how I can write more production ready code. In this post I want this code to be reviewed as near production code I'd write in an interview. I'd like to know how well optimized my code is now from this improvements I've made to it. If there are other optimizations or c++11 features I could be using here please share that as well.
I also included comments on worst case run time complexity for my member functions, I'd like some feedback on this and my space complexity too.
#include <iostream>
#include <string>
class LinkedList
{
private:
struct Node
{
int data;
Node* next;
Node(int data_) : data(data_), next(nullptr) { }
};
Node* _head;
Node* _tail;
public:
LinkedList() : _head(nullptr) { }
LinkedList(int data) { // O(1)
Node* n = new Node(data);
_head = n;
_tail = n;
}
~LinkedList() { // O(n)
Node* current = _head;
Node* n;
while(current) {
n = current;
current = current->next;
delete n;
}
_head = nullptr;
}
void append(int new_data) { // O(1)
auto n = new Node(new_data);
if(!_head) {
_head = n;
_tail = n;
}
else {
_tail->next = new Node(new_data);
_tail = _tail->next;
}
}
void remove(int target_data) { // O(n)
if(!_head) { return; }
Node* previous = nullptr;
auto current = _head;
for(; current->data != target_data; current = current->next) {
if(!current->next) {
return;
}
previous = current;
}
if(!current->next) {
if(previous) {
delete current;
previous->next = nullptr;
}
else {
delete current;
_head = nullptr;
}
}
else {
auto dangling_ptr = current->next;
current->data = current->next->data;
current->next = current->next->next;
delete dangling_ptr;
}
}
friend std::ostream& operator<<(std::ostream& os, const LinkedList& linked_list) { // O(n)
Node* current = linked_list._head;
if(!current) {
os << "Linked List is empty" << std::endl;
return os;
}
else {
for(; current; current = current->next) {
os << '(' << std::to_string(current->data) << ")->";
}
os << "nullptr";
return os;
}
}
};
int main()
{
LinkedList linked_List(0);
linked_List.append(1);
linked_List.append(2);
linked_List.append(3);
linked_List.append(4);
std::cout << linked_List << std::endl;
linked_List.remove(0);
linked_List.remove(4);
linked_List.remove(2);
std::cout << linked_List << std::endl;
linked_List.remove(3);
linked_List.remove(1);
std::cout << linked_List << std::endl;
LinkedList linked_List_two;
linked_List_two.append(1);
linked_List_two.append(2);
linked_List_two.append(3);
linked_List_two.append(4);
std::cout << linked_List_two << std::endl;
linked_List_two.remove(0);
linked_List_two.remove(4);
linked_List_two.remove(2);
std::cout << linked_List_two << std::endl;
linked_List_two.remove(3);
linked_List_two.remove(1);
std::cout << linked_List_two << std::endl;
}