// linked_list.h
#ifndef LINKED_LIST_H_INCLUDED
#define LINKED_LIST_H_INCLUDED
// note: implementation required for pass
class linked_list
{
linked_list(linked_list&& rhs) = delete;
linked_list(const linked_list& rhs) = delete;
linked_list& operator=(const linked_list &rhs) = delete;
linked_list& operator=(linked_list&& rhs) = delete;
struct node
{
node();
node(int value, node* next);
int value_ = 0;
node* next_ = nullptr;
};
public:
linked_list();
~linked_list();
void push_front(int value);
void push_back(int value);
void insert(int value, int index);
void pop_front();
void pop_back();
void remove(int index);
void clear();
int size() const noexcept;
int front() const noexcept;
int back() const noexcept;
int at(int index) const noexcept;
node* getNodeAt(int index) const noexcept;
bool empty() const noexcept;
bool isInRange(int index) const noexcept;
private:
int count_;
node *head_;
node *tail_;
};
#endif // !LINKED_LIST_H_INCLUDED
// linked_list.cpp
#include "linked_list.h"
linked_list::node::node(int value, node *next)
: value_(value)
, next_(next)
{
}
linked_list::linked_list()
: count_(0)
, head_(nullptr)
, tail_(nullptr)
{
}
linked_list::~linked_list()
{
clear();
}
void linked_list::push_front(int value) {
head_ = new node{ value, head_ };
if (empty()){
tail_ = head_;
}
count_++;
}
void linked_list::push_back(int value) {
node* Tmp_Node = new node{ value, nullptr };
if (empty()) {
head_ = Tmp_Node;
}else{
tail_->next_ = Tmp_Node;
}
tail_ = Tmp_Node;
count_++;
}
void linked_list::insert(int value, int index)
{
if (!(isInRange(index) || index == count_)){ //WARNING, count_ should not be valid. The test is wrong.
return;
}
if (index == 0){
return push_front(value);
}
if (index == count_) { // If index is after tail. TODO: probably a logic error.
return push_back(value);
}
node* infront = getNodeAt(index - 1);
node* after = infront->next_;
infront->next_ = new node{ value, after };
count_++;
}
void linked_list::pop_front()
{
if (empty()) {
return; //TODO: do we want pop_front on empty containers to be allowed? consider exceptions
}
if (count_ == 1) // If the list has only 1 node.
{
delete head_;
head_ = nullptr;
tail_ = nullptr;
count_--;
return;
}
else // If the list has more than 1 node.
{
node* Tmp_Node;
Tmp_Node = head_->next_;
delete head_;
head_ = Tmp_Node;
count_--;
return;
}
}
void linked_list::pop_back(){
if (empty()) {
return;//TODO: pop back on empty should be undefined behavior
}
/*node* secondToLast = getNodeAt(size() - 1);
delete tail_;
secondToLast->next_ = nullptr;
tail_ = secondToLast;
count_--;
if (empty()) {
head_ = nullptr;
tail_ = nullptr;
}*/
if (count_ == 1) // If the list has 1 node.
{
delete tail_;
tail_ = nullptr;
head_ = nullptr;
count_--;
return;
}
else // If list has more than 1 node.
{
node* Tmp_CurrentNode = head_;
node* Tmp_PreviousNode = head_; // Initialized as head just to avoid warnings.
int IterationCounter = 0;
while (Tmp_CurrentNode != tail_)
{
if (IterationCounter == (count_ - 2)) // Captures the before last node.
{
Tmp_PreviousNode = Tmp_CurrentNode;
}
Tmp_CurrentNode = Tmp_CurrentNode->next_;
IterationCounter++;
}
delete Tmp_CurrentNode;
Tmp_PreviousNode->next_ = nullptr;
tail_ = Tmp_PreviousNode;
count_--;
return;
}
}
void linked_list::remove(int index)
{
if (isInRange(index)) // Validates if index exists in the list.
{
node* Tmp_Node;
if (index == 0) // If index is head.
{
if (head_->next_ == nullptr) // If there is nothing after the head.
{
delete head_;
head_ = nullptr;
tail_ = nullptr;
count_--;
return;
}
else // If there is something after the head.
{
Tmp_Node = head_->next_;
delete head_;
head_ = Tmp_Node;
count_--;
return;
}
}
node* Tmp_CurrentNode = head_;
node* Tmp_PreviousNode = head_; // Initialized as head just to avoid warnings.
int IterationCounter = 0;
if (index == (count_ - 1)) // If index is tail.
{
while (IterationCounter != index)
{
if (IterationCounter == (index - 1)) // Captures the previous node.
{
Tmp_PreviousNode = Tmp_CurrentNode;
}
Tmp_CurrentNode = Tmp_CurrentNode->next_;
IterationCounter++;
}
delete Tmp_CurrentNode;
Tmp_PreviousNode->next_ = nullptr;
tail_ = Tmp_PreviousNode;
count_--;
return;
}
else // If index is in the middle.
{
while (IterationCounter != index)
{
if (IterationCounter == (index - 1)) // Captures the previous node.
{
Tmp_PreviousNode = Tmp_CurrentNode;
}
Tmp_CurrentNode = Tmp_CurrentNode->next_;
IterationCounter++;
}
Tmp_Node = Tmp_CurrentNode->next_;
delete Tmp_CurrentNode;
Tmp_PreviousNode->next_ = Tmp_Node;
count_--;
return;
}
}
}
void linked_list::clear(){
while (!empty()) {
pop_back(); //assumes pop_back assigns nullptr to members when empty
}
}
int linked_list::size() const noexcept {
return count_;
}
int linked_list::front() const noexcept {
if (head_ == nullptr){
return -1; //WARNING: error sentinel value is a valid int value.
}
return head_->value_;
}
int linked_list::back() const noexcept {
if (tail_ == nullptr){
return -1; //WARNING: error sentinel value is a valid int value.
}
return tail_->value_;
}
int linked_list::at(int index) const noexcept {
if (!isInRange(index)) {
return -1; //WARNING: error sentinel value is a valid value.
//invalid indexes should perhaps throw an exception, or assert.
}
node* tmp = getNodeAt(index);
return tmp ? tmp->value_ : -1;
}
linked_list::node* linked_list::getNodeAt(int index) const noexcept {
if (!isInRange(index)) {
return nullptr;
}
node* temp = head_;
for (int i = 0; i < index && temp->next_; i++) {
temp = temp->next_;
}
return temp;
}
bool linked_list::empty() const noexcept{
return count_ <= 0; //TODO: change count_ to std::size_t
}
bool linked_list::isInRange(int index) const noexcept{
return !empty() && index > -1 && index < size();
}
Comments
0 B
|0 👍
/0 👎