Lecture 5 Sept 12, 2011 Goals: Linked list (Chapter 3) list class in STL (section 3.3) implementing with linked lists
Overview of list vs. array list can be incrementally grown. (dynamic array resizing is expensive.) inserting next to a given node takes constant time. (In arrays, this takes O(n) time where n = size of the array.) searching for a given key even in a sorted list takes O(n) time. (in sorted array, it takes O(log n) time by binary search.) accessing the k-th node takes O(k) time. (in array, this takes O(1) time.)
Abstract Data Type (ADT) oList ADT insert, find, delete (primary operations) successor, merge, reverse, … (secondary) oVariations of linked lists oCircular lists oDoubly linked lists Review of ADT List
A node class class Node { public: Node(int x) { key = x; next = 0; } void set_key(int x) { key = x; } void set_next(Node* n) { next = n; } int get_key() { return key; } Node* get_next() { return next; } static Node* copy(Node* in) { Node* tmp; if (in == 0) return 0; else { Node* tmp1 = copy(in->next); tmp = new Node(in->key); tmp->next = tmp1; return tmp; } private: int key; Node* next; };
Some list functions Consider the standard singly-linked list class: class list { private: Node* first; list(int k) { first = new Node(k);} void insert(int k, int posn); // insert k at posn Node* find(int k); // return first node containing k void delete(int k); // remove first node containing k int length(); // return the length of the list void delete_after(Node* n);// remove node after n, if it // exists void get_key(int posn); // return key in a given position void print_list(); // print the list } etc. Other functions: delete a key in a position.
Implementing some of the functions void insert(int k, int posn) { // insert k at a given position // write recursively. }
Implementing some of the functions void insert(int k, int posn) { // insert k at a given position // write recursively. if (posn length()) return; // wrong value of posn; ignore if (posn == 1) { list* temp = new list(k); temp->next = first; first = temp; } else first->next = first->next.insert(k, posn-1); }
Reverse the list We want to reverse the list using the existing nodes of the list, i.e., without creating new nodes.
Reverse the list We want to reverse the list using the existing node of the list, i.e., without creating new nodes. void reverse() { if (head == NULL || head -> next == NULL) return; Node* p = head; Node* q = p-> next; p->next = NULL; while (q != NULL) { Node* temp = q -> next; q->next = p; p = q; q = temp; } head = p; }
Remove negative items from the list Example: List: -3, 4, 5, -2, 11 becomes 4, 5, 11 We will write this one recursively.
Remove negative items from the list Example: List: -3, 4, 5, -2, 11 becomes 4, 5, 11 We will write this one recursively. void remove_negative() { // removes all the negative items from a list // Example input: ; output: if (head == NULL) return; else if (head->key >= 0) { List nList = List(head->next); nList.remove_negative(); head->next = nList.head; } else { List nList = List(head->next); nList.remove_negative(); head = nList.head; }
A problem similar to Project # 1 Generate all the subsets of a given set of numbers. Thus, if the input is {1, 2, 4} the output is: {} {1} {2} {4} {1, 2} {1, 4} {2, 4} {1, 2, 4} Our program treats all the input symbols as distinct so a pre-condition is: the input array elements are distinct.
Data structure used Array or vector of lists: Each member of the vector is a pointer to a list containing one of the subsets. null A
subsets(A, j) will generate all the subsets of the set {A[0], A[1], …, A[j – 1]}. Thus, if A = [2, 4, 6, 1], then subsets(A, 1) will generate all the subsets of {2}, build(A, 2) will generate all the subsets of {2, 4} etc. subsets(A,1) returns: null 2 subsets(A,2) returns: null
subsets (A, k) calls subsets(A,k–1). Let temp be the result from the call. It creates a copy of temp, say temp1. It inserts A[k-1] into each list of temp1. It merges temp and temp1 and returns the merged array of lists. Example: A = {1, 3, 2}. Suppose k = 2. Build(A,2) returns the collection of lists [ ], [1], [3], [1, 3]. Now inserting 2 into each of the lists gives [2], [2,1], [2,3], [2,1,3]. Merging the two lists we get: [ ], [1], [3], [1, 3], [2], [2,1], [2,3], [2,1,3]. This is the set of all subsets of {1, 3, 2}.
classes List and Node class List { public: List() { head = 0; } List(int x) { head = new Node(x); } void insert(int k) { // insert k as the first // item of the list Node* tmp = new Node(k); tmp->setNext(head); head = tmp; } void print() { Node* temp = head; cout << "{"; while (temp != NULL) { cout getKey(); if (temp->getNext()!= 0) cout << ", "; temp = temp->getNext(); } cout << "}"; cout << endl; } private: class Node { public: Node(int x) { key = x; next = NULL; } void setNext(Node* p) {next = p;} void setKey(int k) {key = k;} int getKey() { return key;} Node* getNext() { return next;} private: int key; Node* next; }; Node* head; };
The class subsets class subsets { private: vector v; public: subsets(); subsets(vector & A, int k); void insert(int k; void merge(subsets c); void subsetsPrint(); };
Algorithm for permutation problem permutation(input array A, int n, int k) { if (n == 1) // same as for combination else { temp = permutation(A, n-1, k); temp1 = permutation(A, n-1, k-1); for j from 1 to k-1 do { temp2 = copy(temp1); insert A[n-1] at position j of each list in temp2; temp = merge(temp, temp2); } return temp; }