/* LinkedList.h - V1.1 - Generic LinkedList implementation Works better with FIFO, because LIFO will need to search the entire List to find the last one; For instructions, go to https://github.com/ivanseidel/LinkedList Created by Ivan Seidel Gomes, March, 2013. Released into the public domain. */ #ifndef LinkedList_h #define LinkedList_h #include template struct ListNode { T data; ListNode *next; }; template class LinkedList{ protected: int _size; ListNode *root; ListNode *last; // Helps "get" method, by saving last position ListNode *lastNodeGot; int lastIndexGot; // isCached should be set to FALSE // everytime the list suffer changes bool isCached; ListNode* getNode(int index); ListNode* findEndOfSortedString(ListNode *p, int (*cmp)(T &, T &)); public: LinkedList(); LinkedList(int sizeIndex, T _t); //initiate list size and default value ~LinkedList(); /* Returns current size of LinkedList */ virtual int size(); /* Adds a T object in the specified index; Unlink and link the LinkedList correcly; Increment _size */ virtual bool add(int index, T); /* Adds a T object in the end of the LinkedList; Increment _size; */ virtual bool add(T); /* Adds a T object in the start of the LinkedList; Increment _size; */ virtual bool unshift(T); /* Set the object at index, with T; */ virtual bool set(int index, T); /* Remove object at index; If index is not reachable, returns false; else, decrement _size */ virtual T remove(int index); /* Remove last object; */ virtual T pop(); /* Remove first object; */ virtual T shift(); /* Get the index'th element on the list; Return Element if accessible, else, return false; */ virtual T get(int index); /* Clear the entire array */ virtual void clear(); /* Sort the list, given a comparison function */ virtual void sort(int (*cmp)(T &, T &)); // add support to array brakets [] operator inline T& operator[](int index); inline T& operator[](size_t& i) { return this->get(i); } inline const T& operator[](const size_t& i) const { return this->get(i); } }; // Initialize LinkedList with false values template LinkedList::LinkedList() { root=NULL; last=NULL; _size=0; lastNodeGot = root; lastIndexGot = 0; isCached = false; } // Clear Nodes and free Memory template LinkedList::~LinkedList() { ListNode* tmp; while(root!=NULL) { tmp=root; root=root->next; delete tmp; } last = NULL; _size=0; isCached = false; } /* Actualy "logic" coding */ template ListNode* LinkedList::getNode(int index){ int _pos = 0; ListNode* current = root; // Check if the node trying to get is // immediatly AFTER the previous got one if(isCached && lastIndexGot <= index){ _pos = lastIndexGot; current = lastNodeGot; } while(_pos < index && current){ current = current->next; _pos++; } // Check if the object index got is the same as the required if(_pos == index){ isCached = true; lastIndexGot = index; lastNodeGot = current; return current; } return NULL; } template int LinkedList::size(){ return _size; } template LinkedList::LinkedList(int sizeIndex, T _t){ for (int i = 0; i < sizeIndex; i++){ add(_t); } } template bool LinkedList::add(int index, T _t){ if(index >= _size) return add(_t); if(index == 0) return unshift(_t); ListNode *tmp = new ListNode(), *_prev = getNode(index-1); tmp->data = _t; tmp->next = _prev->next; _prev->next = tmp; _size++; isCached = false; return true; } template bool LinkedList::add(T _t){ ListNode *tmp = new ListNode(); tmp->data = _t; tmp->next = NULL; if(root){ // Already have elements inserted last->next = tmp; last = tmp; }else{ // First element being inserted root = tmp; last = tmp; } _size++; isCached = false; return true; } template bool LinkedList::unshift(T _t){ if(_size == 0) return add(_t); ListNode *tmp = new ListNode(); tmp->next = root; tmp->data = _t; root = tmp; _size++; isCached = false; return true; } template T& LinkedList::operator[](int index) { return getNode(index)->data; } template bool LinkedList::set(int index, T _t){ // Check if index position is in bounds if(index < 0 || index >= _size) return false; getNode(index)->data = _t; return true; } template T LinkedList::pop(){ if(_size <= 0) return T(); isCached = false; if(_size >= 2){ ListNode *tmp = getNode(_size - 2); T ret = tmp->next->data; delete(tmp->next); tmp->next = NULL; last = tmp; _size--; return ret; }else{ // Only one element left on the list T ret = root->data; delete(root); root = NULL; last = NULL; _size = 0; return ret; } } template T LinkedList::shift(){ if(_size <= 0) return T(); if(_size > 1){ ListNode *_next = root->next; T ret = root->data; delete(root); root = _next; _size --; isCached = false; return ret; }else{ // Only one left, then pop() return pop(); } } template T LinkedList::remove(int index){ if (index < 0 || index >= _size) { return T(); } if(index == 0) return shift(); if (index == _size-1) { return pop(); } ListNode *tmp = getNode(index - 1); ListNode *toDelete = tmp->next; T ret = toDelete->data; tmp->next = tmp->next->next; delete(toDelete); _size--; isCached = false; return ret; } template T LinkedList::get(int index){ ListNode *tmp = getNode(index); return (tmp ? tmp->data : T()); } template void LinkedList::clear(){ while(size() > 0) shift(); } template void LinkedList::sort(int (*cmp)(T &, T &)){ if(_size < 2) return; // trivial case; for(;;) { ListNode **joinPoint = &root; while(*joinPoint) { ListNode *a = *joinPoint; ListNode *a_end = findEndOfSortedString(a, cmp); if(!a_end->next ) { if(joinPoint == &root) { last = a_end; isCached = false; return; } else { break; } } ListNode *b = a_end->next; ListNode *b_end = findEndOfSortedString(b, cmp); ListNode *tail = b_end->next; a_end->next = NULL; b_end->next = NULL; while(a && b) { if(cmp(a->data, b->data) <= 0) { *joinPoint = a; joinPoint = &a->next; a = a->next; } else { *joinPoint = b; joinPoint = &b->next; b = b->next; } } if(a) { *joinPoint = a; while(a->next) a = a->next; a->next = tail; joinPoint = &a->next; } else { *joinPoint = b; while(b->next) b = b->next; b->next = tail; joinPoint = &b->next; } } } } template ListNode* LinkedList::findEndOfSortedString(ListNode *p, int (*cmp)(T &, T &)) { while(p->next && cmp(p->data, p->next->data) <= 0) { p = p->next; } return p; } #endif