List as an Abstract Data Type
struct Node{ public: int data; Node* next; }; typedef Node* Nodeptr; class List { public: List(); // constructor List(const list& list1); // copy constructor ~List(); // destructor bool empty() const; // boolean function int headElement() const; // access functions void addHead(int newdata); // add to the head void delHead(); // delete the head int length() const; // utility function void print() const; // output private: Nodeptr head; };
void main(){ List L; // constructor called automatically here for L L.print(); { } L.addHead(30); L.print(); { 30 } L.addHead(13); L.print(); { } L.addHead(40); L.print(); { } L.addHead(50); L.print(); { } List N(L); N.print(); { } List R; R.print(); { } if(R.empty()) cout << "List R empty" << endl; L.delHead(); L.print(); { } L.delHead(); L.print(); { } if(L.empty()) cout << "List L empty" << endl; else{ cout << "List L contains " << L.length() << " nodes" << endl; cout << "Head element of list L is: " << L.headElement() << endl; } } // destructor called automatically here for L How to use it int i(0); Int j(10); Int k(j);
Motivation * list using static array int myArray[1000]; int n; We have to decide (to oversize) in advance the size of the array (list) * list using dynamic array int* myArray; int n; cin >> n; myArray = new int[n]; We allocate an array (list) of any specified size while the program is running * linked-list (dynamic size) size = ?? The list is dynamic. It can grow and shrink to any size.
Using a static array
struct Node{ public: int data; Node* next; }; typedef Node* Nodeptr; class List { public: List(); // constructor List(const List& list1); // copy constructor ~List(); // destructor bool empty() const; // boolean function int headElement() const; // access functions void addHead(int newdata); // add to the head void delHead(); // delete the head int length() const; // utility function void print() const; // output private: int head[10000]; int size; }; Or int head[DIM]; int size; cont int DIM=10000;
List::List(){ head = NULL; size = 0; } bool List::empty() const{ if(head==NULL) return true; else return false; } int List::headElement() const { if(head != NULL) return head->data; else{ cout << "error: trying to find head of empty list" << endl; exit(1); } Some simple member functions: Implementation If (size==0) return true; else return false; If (size!=0) return head[0]; else …;
List::List(const list& list1) { head = NULL; Nodeptr cur = list1.head; while(cur != NULL) { // addEnd(cur->data); addHead(cur->data); // inverse list order cur = cur->next; } (explicitly defined) copy constructor: If (list1.size!=0) for (int i=0; i<list1.size; i++) head[i]=list1.head[i];
Destructor: deallocation function List::~List(){ Nodeptr cur; while(head!=NULL){ cur = head; head = head->next; delete cur; } Nothing here as it’s static.
void List::addHead(int newdata){ Nodeptr newPtr = new Node; newPtr->data = newdata; newPtr->next = head; head = newPtr; } Adding an element to the head: If (size<10000) { for (int i=size; i>=;i--) head[i+1]=head[i]; head[0]=newdata; size++; }
void List::delHead(){ if(head != NULL){ Nodeptr cur = head; head = head->next; delete cur; } Deleting the head: for (int i=1; i<size;i++) head[i-1]=head[i]; size--;
void List::print() const{ cout << "{"; Nodeptr cur = head; while(cur != NULL){ cout data << " "; cur = cur->next; } cout << "}" << endl; } Print the list: for (int i=0; i<size;i++) cout << head[i];
int List::length() const{ int n=0; Nodeptr cur = head; while(cur != NULL){ n++; cur = cur->next; } return n; } Computing the number of elements of a given list: return size;
Using a dynamic array
struct Node{ public: int data; Node* next; }; typedef Node* Nodeptr; class List { public: List(); // constructor List(const List& list1); // copy constructor ~list(); // destructor bool empty() const; // boolean function int headElement() const; // access functions void addHead(int newdata); // add to the head void delHead(); // delete the head int length() const; // utility function void print() const; // output private: int* head; int size; };
List::List(){ … } bool List::empty() const{ } int List::headElement() const { } Some simple member functions: Implementation
List::List(const List& list1) { } (explicitly defined) copy constructor:
Other functions … List::~List(){ delete[] head; }
void main(){ List L; // constructor called automatically here for L L.print(); { } L.addHead(30); L.print(); { 30 } L.addHead(13); L.print(); { } L.addHead(40); L.print(); { } L.addHead(50); L.print(); { } List N(L); N.print(); { } List R; R.print(); { } if(R.empty()) cout << "List R empty" << endl; L.delHead(); L.print(); { } L.delHead(); L.print(); { } if(L.empty()) cout << "List L empty" << endl; else{ cout << "List L contains " << L.length() << " nodes" << endl; cout << "Head element of list L is: " << L.headElement() << endl; } } // destructor called automatically here for L Conclusion: the usage is the same!!! No matter it is linked list, static array or dynamic array!
List as a template
template class List { public: List(); // constructor List(const List& list1); // copy constructor ~list(); // destructor bool empty() const; // boolean function int headElement() const; // access functions void addHead(T newdata); // add to the head void delHead(); // delete the head int length() const; // utility function void print() const; // output private: T* head; int size; };
template List::List(){ head=NULL; size=0; } template bool List::empty() const{ } template T List::headElement() const { } Some simple member functions: Implementation
Other functions … template List::~List(){ delete T[] head; }