570 likes | 712 Views
Andreas Savva. Data Structures. Chapter 6 Linked Lists. Jacky. 99-296580. Paul. Carol. Tom. 18 Feb. 99-456543. 99-785434. 99-672205. 30 Jun. 21 Jan. 28 Feb. Fred. 99-767554. 3 Oct. Lists. Like a stack or a queue, a list has a sequence of entries as its data values.
E N D
Andreas Savva Data Structures Chapter 6 Linked Lists
Jacky 99-296580 Paul Carol Tom 18 Feb 99-456543 99-785434 99-672205 30 Jun 21 Jan 28 Feb Fred 99-767554 3 Oct Lists • Like a stack or a queue, a list has a sequence of entries as its data values. • However, unlike a stack or a queue, a list permits operations that alter arbitrary entries of the sequence. A linked list
List Definition • A list of elements of type T is a finite sequence of elements of T together with the following operations: • Construct the list, leaving it empty. • Determine whether the list is empty or not. • Determine whether the list is full or not. • Find the size of the list. • Clear the list to make it empty. • Insert an entry at a specified position of the list. • Remove an entry at a specified position in the list. • Retrieve the entry from a specified position in the list. • Replace the entry at a specified position in the list. • Traverse the list, performing a given operation on each entry.
A Simple Linked List implementation structList { // data members List_entry head; List *tail; // constructors List(); List(List_entry item, List *lst = NULL); }; List::List() { tail = NULL; } List::List(List_entry item, List *lst) { head = item; tail = lst; }
List Functions List *cons(List_entry x, List *lst) { List *m = new List(x, lst); if (m == NULL) { cout << “Memory full” << endl; return lst; } elsereturn m; } List_entry head(List *lst) { return lst->head; } List *tail(List *lst) { return lst->tail; }
Insert - Sorted List *insert(List_entry x, List *lst) { if (lst == NULL) return cons(x, NULL); else if (x < head(lst)) return cons(x, lst); else return cons(head(lst), insert(x, tail(lst))); } insert(5, [1,3,4,7,9,12])
cons(1, insert(5, [3,4,7,9,12])) cons(1, cons(3, insert(5, [4,7,9,12]))) cons(1, cons(3, cons(4, insert(5, [7,9,12])))) cons(1, cons(3, cons(4, cons(5, [7,9,12])))) cons(1, cons(3, cons(4, [5,7,9,12]))) cons(1, cons(3, [4,5,7,9,12])) cons(1, [3,4,5,7,9,12]) [1,3,4,5,7,9,12] Insert insert(5, [1,3,4,7,9,12])
Garbage lst 1 3 4 7 9 12 5 4 3 1 lst Insert - Garbage insert(5, [1,3,4,7,9,12]) cons(1, insert(5, [3,4,7,9,12])) cons(1, cons(3, insert(5, [4,7,9,12]))) cons(1, cons(3, cons(4, insert(5, [7,9,12])))) cons(1, cons(3, cons(4, cons(5, [7,9,12])))) cons(1, cons(3, cons(4, [5,7,9,12]))) cons(1, cons(3, [4,5,7,9,12])) cons(1, [3,4,5,7,9,12]) [1,3,4,5,7,9,12]
Insert - Sorted List *insert(List_entry x, List *lst) { if (lst == NULL) return cons(x, NULL); else if (x < head(lst)) return cons(x, lst); else { List *temp = lst; return cons(head(lst), insert(x, tail(lst))); delete temp; } } insert(5, [1,3,4,7,9,12])
Exercises • Write the following functions: • List *remove(List_item x, List *l); • int length(List *l); • bool isin(List_item x, List *l); • int nooftimes(List_item x, List *l); • List *append(List *l, List *t); • List *reverse(List *l); • void print(List *l);
Class Templates • A C++ template construction allows us to write code to implement a class, that uses objects of an arbitrary, generic type. • In template code we utilize a parameter enclosed in angles brackets <………> to denote the generic type. List<int> first_list; List<char> second_list;
The Node Structure template <class Node_entry> structNode { Node_entry entry; Node<Node_entry> *next; Node (); Node(Node_entry item, Node<Node_entry> *n = NULL); }; template <class Node_entry> Node<Node_entry>::Node() { next = NULL; } template <class Node_entry> Node<Node_entry>::Node(Node_entry item, Node<Node_entry> *n) { entry = item; next = n; }
3 4 7 9 12 Andy Ann John Mark Paul Sorted Linked Lists • Lists are sequential (visit one node at a time) • Sequential sorting Examples of sorted linked lists:
The List Class template <class List_entry> class List { public: List(); void clear(); bool empty() const; int size() const; Error_code remove(const List_entry &item); Error_code insert(const List_entry &item); void print() const; // Safeguards ~List(); List(const List<List_entry> ©); voidoperator = (const List<List_entry>&original); protected: Node<List_entry>*head; };
head Create List Constructor: template <class List_entry> List<List_entry>::List( ) { head = NULL; }
Empty template <class List_entry> bool List<List_entry>::empty() const { return head == NULL; }
head temp 3 4 7 9 12 Size template <class List_entry> int List<List_entry>::size() const { int count = 0; Node<List_entry> *temp = head; while (temp!=NULL) { count++; temp = temp->next; } return count; } count 1 4 5 2 3 0
new_entry head else If (item<head->entry) head new_entry 4 4 5 6 8 9 Insert Numbers.insert(4); If (empty())
head head current previous current previous // If (current==NULL) new_entry new_entry 3 2 1 1 6 4 3 4 2 NULL Insert (continue) else
Insert template <class List_entry> Error_code List<List_entry>::insert(const List_entry &item) { Node<List_entry> *new_entry = new Node<List_entry>(item); if (new_entry == NULL) return overflow; // IF FULL else if (empty()) head = new_entry; else if (item < head->entry) { new_entry->next = head; head = new_entry; } else { Node<List_entry> *previous = head, *current = head->next; while (current != NULL) { if (item < current->entry) { new_entry->next = current; break; // Exit the loop } previous = current; current = current->next; } previous->next = new_entry; } return success; }
head head else current current previous 8 4 9 3 4 6 9 1 Remove Numbers.remove(4); If (item==head->entry)
Remove template <class List_entry> Error_code List<List_entry>::remove(const List_entry &item) { Node<List_entry> *current = head; if (empty()) return underflow; if (item < head->entry) returnnot_found; if (item == head->entry) { head = head->next; delete current; returnsuccess; } Node<List_entry> *previous = current; current = current->next; while (current != NULL) { if (item < current->entry) break; // Exit the loop if (item == current->entry) { previous->next = current->next; delete current; returnsuccess; } else { previous = current; current = current->next; } } returnnot_found; }
head temp Screen 3 4 7 9 12 Print template <class List_entry> void List<List_entry>::print() const { Node<List_entry> *temp = head; if (empty()) cout << "Empty List" << endl; else while (temp != NULL) { cout << temp->entry << endl; temp = temp->next; } } 3 4 7 9 12
head temp 3 4 7 9 12 Clear & ~List template <class List_entry> void List<List_entry>::clear() { Node<List_entry> *temp; while (head != NULL) { temp = head; head = head->next; delete temp; } } NULL
Size - Recursive template <class List_entry> int List<List_entry>::size_recursive(Node<List_entry> *lst) const { if (lst == NULL) return 0; else return 1 + size_recursive(lst->next); } template <class List_entry> int List<List_entry>::size() const { returnsize_recursive(head); }
Print - Recursive template <class List_entry> void List<List_entry>::print_recursive(Node<List_entry> *lst) const { if (lst != NULL) { cout << lst->entry << endl; print_recursive(lst->next); } } template <class List_entry> void List<List_entry>::print() const { if (empty()) cout << "Empty List" << endl; else print_recursive(head); }
head Cursor Dear Ann I am now living in Cyprus where I got marr|ied and bought a house. This is a great place to be. The weather is perfect and life is . . . ’D’ ’e’ ’a’ ’r’ ’ ’ ’A’ ’n’ ’n’ ’\n’ ’I’ . . . Unsorted Lists • A text editor example: • Using position (cursor) for insert, remove, replace.
The List Class template <classEntry> class List { public: . . . . . voidtraverse(void(*visit)(Entry &)); private: intcount; // Number of nodes in the list Node<Entry> *head; // Auxiliary function used to locate list position Node<Entry> *set_position(int position) const; };
Empty template <class Entry> bool List<Entry>::empty() const { return count == 0; }
Size template <class Entry> int List<Entry>::size() const { return count; }
head q ’S’ ’P’ ’A’ ’I’ ’N’ current Set Position Position starts at 0 template<class Entry> Node<Entry> *List<Entry>::set_position(int position) const { Node<Entry> *q = head; for (int i=0; i<position; i++) q = q->next; return q; } Example: current = set_position(2); 0 1 2 3 4 i 1 0 2
Traverse template <class Entry> void List<Entry>::traverse(void (*visit)(Entry &)) { Node<Entry> *current = head; for (int i=0; i<count; i++) { (*visit)(current->entry); current = current->next; } }
Example: What output will be produced by the program on the left if the list numbers is as bellow? head Screen 4 5 8 10 13 3 4 7 9 12 Calling Traverse for Printing void AddOne(int &x) { x++; } void Print(int &x) { cout << x << endl; } void main( ) { List<int> numbers; . . . . . numbers.traverse(AddOne); numbers.traverse(Print); }
Retrieve template <class Entry> Error_code List<Entry>::retrieve(int position, Entry &x) { if (empty()) return underflow; if (position < 0 || position >= count) return range_error; Node<Entry> *current; current = set_position(position); x = current->entry; return success; }
Insert template <class Entry> Error_code List<Entry>::insert(int position, const Entry &x) { if (position < 0 || position > count) return range_error; Node<Entry> *new_node, *previous, *current; if (position == 0) current = head; else { previous = set_position(position - 1); current = previous->next; } new_node = new Node<Entry>(x,current); if (new_node == NULL) return overflow; if (position == 0) head = new_node; else previous->next = new_node; count++; return success; }
head head else current current previous new_entry new_entry ’u’ ’o’ ’u’ ’s’ ’e’ ’h’ ’e’ ’s’ ’o’ ’h’ Insert if (position==0)
Remove template <class Entry> Error_code List<Entry>::remove(int position) { if (position < 0 || position >= count) return range_error; Node<Entry> *previous, *current; if (position == 0) current = head; else { previous = set_position(position - 1); current = previous->next; } if (position == 0) head = head->next; else previous->next = current->next; delete current; count--; return success; }
head head else current current previous ’s’ ’c’ ’a’ ’t’ ’p’ ’c’ ’a’ ’t’ Remove if (position==0)
Replace template <class Entry> Error_code List<Entry>::replace(int position, const Entry &x) { if (position < 0 || position >= count) return range_error; Node<Entry> *current; current = set_position(position); current->entry = x; return success; }
Keeping the Current Position template <class Entry> class List { public: . . . . . protected: int count; mutableint current_position; Node<Entry> *head; mutableNode<Entry> *current; voidset_position(int position) const; }; Mutable data members of a class can be changed, even by constant methods
Set Position template<class Entry> void List<Entry>::set_position(int position) const { if (position < current_position) { // start over at head of list current_position = 0; current = head; } for (; current_position < position; current_position++) current = current->next; }
’e’ ’H’ ’n’ ’l’ ’e’ Doubly Linked Lists • In the last section the problem of moving backwards was solved by traversing the list from its beginning until the desired node was found, but this solution is generally unsatisfactory since: • its programming is difficult, and • the running-time of the program will depend on the length of the list, which may be quite long. • Some applications of linked lists require that we move both forward and backward through the list.
’e’ ’H’ ’n’ ’l’ ’e’ 0 3 1 2 4 current Doubly Linked Lists current_position 3 Class data members Set Position: for ( ; current_position < position ; current_position++) current = current->next; for ( ; current_position > position ; current_position--) current = current->back;
The Node Structure template <classEntry> struct Node { Entry entry; Node<Entry> *back; Node<Entry> *next; Node(); Node(Entry item, Node<Entry> *b = NULL, Node<Entry> *n = NULL); }; template <class Entry> Node<Entry>::Node() { next = NULL; back = NULL; } template <class Entry> Node<Entry>::Node(Entry item, Node<Entry> *b, Node<Entry> *n) { entry = item; back = b; next = n; }
The Class List template <class Entry> class List { public: . . . . . protected: intcount; mutable intcurrent_position; mutable Node<Entry> *current; void set_position(int position) const; }
Set Position template<class Entry> void List<Entry>::set_position(int position) const { if (current_position <= position) for (; current_position < position; current_position++) current = current->next; else for (; current_position > position; current_position--) current = current->back; }
Insert template<class Entry> Error_code List<Entry>::insert(int position, const Entry &x) { Node<Entry> *new_node, *following, *preceding; if (position < 0 || position > count) return range_error; if (position == 0) { if (empty()) following = NULL; else { set_position(0); following = current; } preceding = NULL; } else { set_position(position – 1); preceding = current; following = preceding->next; } new_node = new Node<Entry>(x,preceding,following); if (new_node == NULL) return overflow; if (preceding != NULL) preceding->next = new_node; if (following != NULL) following->back = new_node; current = new_node; current_position = position; count++; return success; }
new_entry ’o’ ’M’ ’t’ ’r’ ’e’ ’h’ preceding following Insert thelist.insert(3,’h’); 0 3 1 2 4
Remove template<class Entry> void List<Entry>::remove(int position) { Node<Entry> *new_node, *following, *preceding; if (position < 0 || position >= count) return range_error; set_position(position); if (position == 0) preceding = NULL; else preceding = current->back; if (position == count-1) following = NULL; else following = current->next; if (preceding != NULL) preceding->next = following; if (following != NULL) following->back = preceding; delete current; count--; if (!empty()) if (following == NULL) { current_position = position – 1; current = preceding; } else current = following; return success; }
’l’ ’e’ ’H’ ’n’ ’e’ current preceding following Remove thelist.remove(2);