Presentation is loading. Please wait.

Presentation is loading. Please wait.

CSE 143 Linked Lists [Chapter 8.1-8.6, 8.8] 3/30/98.

Similar presentations


Presentation on theme: "CSE 143 Linked Lists [Chapter 8.1-8.6, 8.8] 3/30/98."— Presentation transcript:

1 CSE 143 Linked Lists [Chapter , 8.8] 3/30/98

2 Linked Lists A linked list is a collection of dynamically allocated nodes Each node contains at least one member that links to another node in the list. In the simplest case, each node has two members: a data item and a link field which points to the successor node. Example: a list of 3 integers: 4 8 16 head 3/30/98

3 Creating Nodes First we’ll declare a struct which we’ll use to represent a node: struct Node { int data; Node* next; }; Now we can create new nodes: Node* p; p = new Node; p->data = 100; // shorthand for: (*p).data = 100 p->next = NULL; // shorthand for: (*p).next = NULL Note the use of the -> operator 3/30/98

4 Manipulating Nodes Draw the picture that results from the following code: Node* front, * temp; front = new Node; front->data = 1; front->next = new Node; // adding nodes front->next->data = 2; front->next->next = NULL; temp = front; // deleting nodes front = front->next; delete temp; 3/30/98

5 Using Linked Lists Let’s write a Stack ADT which uses a linked list:
struct Node; // partial or "forward" declaration. //the full decl is hidden in the impl. file class IntStack { public: IntStack(); void push(int item); int pop(); bool isEmpty(); bool isFull(); private: Node* items; }; 3/30/98

6 Stack Implementation:
struct Node { int data; Node* next; }; IntStack::IntStack() { items = NULL; } void IntStack::push(int item) { Node* temp = new Node; temp->data = item; temp->next = items; items = temp; } 3/30/98

7 Stack Implementation (2)
int IntStack::pop() { assert(!isEmpty()); Node* p = items; int rval = p->data; items = items->next; delete p; return rval; } bool IntStack::isEmpty() { return (items == NULL); } bool IntStack::isFull() { return false; } 3/30/98

8 Stack Wrapup What’s missing?
top() sizeOf() - how would you write this? Dynamic memory suite: copy constructor, destructor, assignment operator… What are advantages/disadvantages of this implementation of a stack? We’d like to separate out the linked list from the Stack. The “right” way to do this is to re-implement our List ADT using a linked list 3/30/98

9 Implementing a List ADT
Again, we’ll declare a struct to represent a node: struct Node { int data; Node* next; }; Now our List ADT will look like this: items 4 8 16 cursor 3/30/98

10 List Specification We can use the same old List specification with a minor change: struct Node; // again, a partial declaration class IntList { public: IntList(); // The public interface remains int sizeOf(); // the same! void reset(); // etc… private: Node* items; // Different representation!! Node* cursor; }; 3/30/98

11 Implementation We need to implement at least the following suite of member functions: IntList() // constructor bool isEmpty(); // predicates bool isFull(); int data(); int sizeOf(); void reset(); // cursor manipulators void advance(); bool endOfList(); void insertBefore(int item); // insertion & deletion void insertAfter(int item); void deleteItem(); 3/30/98

12 Implementation (1) IntList::IntList() { cursor = items = NULL; }
bool IntList::isEmpty() { return (items==NULL); bool IntList::isFull() { return false; // Can we do better than this? bool IntList::endOfList() { return cursor==NULL; //doesn't quite match original List semantics 3/30/98

13 Implementation (2) void IntList::advance() { assert(!endOfList());
cursor = cursor->next; } void IntList::reset() { cursor = items; } int IntList::sizeOf() { int i=0; Node* p; for (Node* p = items; p != NULL; p = p->next) i++; return i; 3/30/98

14 after implementation (1)
Inserting after the cursor. This code is a little broken... void IntList::insertAfter(int item) { Node* nodePtr = new Node; nodePtr->data = item; nodePtr->next = cursor->next; cursor->next = nodePtr; cursor = nodePtr; } For this one, try inserting 10 (with cursor at 8), FOr next two, try inserting at end (17) and beginning (2). at beginning is a problem, because "items" doesn't get updated. items 4 8 16 cursor 3/30/98 CSE 143

15 Examples items 4 8 16 cursor items 4 8 16 cursor 3/30/98

16 after implementation fixed:
void IntList::insertAfter(int item) { assert(items == NULL || !endOfList()); Node* nodePtr = new Node; nodePtr->data = item; if (items == NULL) { // empty list nodePtr->next = NULL; items = nodePtr; } else { nodePtr->next = cursor->next; cursor->next = nodePtr; cursor = nodePtr; 3/30/98

17 before Implementation
Inserting before the cursor is tricky too. void IntList::insertBefore(int item) { Node* nodePtr = new Node; nodePtr->data = item; nodePtr->next = cursor; if (cursor == items) // cursor points to head items = nodePtr; else { Node* prevPtr = Previous(); prevPtr->next = nodePtr; } cursor = nodePtr; 3/30/98

18 delete Implementation
Case 1: cursor points at first item Case 2: cursor points somewhere else void IntList::deleteItem() { assert(cursor != NULL); // cursor must be valid Node* temp = cursor; if (cursor == items) items = items->next; else { Node* previous = Previous(); previous->next = cursor->next; } cursor = cursor->next; delete temp; 3/30/98

19 before and delete helper
The above code depends on a helper member function Previous(), which we’ll make private: // return the pointer to the node previous to the // node the cursor points at... Node* IntList::Previous() { Node* p = items; while (p->next != cursor) p = p->next; return p; } 3/30/98

20 Exercise 1: Manipulations
Draw the picture that results from this code: IntList aList; for (i=0; i<4; i++) aList.insertAfter(i); for (aList.reset(); !aList.endOfList(); aList.advance()) cout << aList.data(); 3/30/98

21 Exercise 2: Traversals Count the occurrences of an item:
int occurrencesOf(List& l, int item) { int count = 0; for (l.reset(); !l.endOfList(); l.advance()) if (l.data() == item) count++; return count; } 3/30/98

22 Exercise 3: Deletion A function to find and delete an item: bool
findAndDelete(IntList& l, int item) { for (l.reset(); !l.endOfList(); l.advance()) if (l.data() == item) { l.delete(); return true; } return false; 3/30/98

23 Variations on a theme Doubly linked lists Circular lists
Makes finding the previous pointer a breeze Takes a little more space and complexity to manage the extra pointers Circular lists Can remove some special cases Head and tail pointers. Good for queues Dummy nodes 3/30/98

24 Some Issues Previous( ) is an expensive operation
Could maintain a "previous" pointer Probably want our full dynamic memory suite: Copy constructor Deep copying assignment Destructor Making deep copies of large lists is expensive. Solutions: always pass by reference. Can enforce this by making the copy constructor private... 3/30/98

25 A Bigger Issue Our list is not as generic as it could be: Solutions:
It has the name of the element type (in this case, ints) hard-coded into it. Solutions: Rewrite the code (a poor - but common - solution) Templates (cf. Lippman) Inheritance (Chapters 10 and 11) 3/30/98

26 List ADT Summary We’ve seen 2 implementations of a List ADT:
Arrays: support efficient random access, but inefficient insertion and deletion, because we need to shift elements around Linked-lists: support efficient insertion and deletion, but inefficient random access What kind of tradeoffs are we making? List as an ADT vs. a List as a data structure. 3/30/98

27 Linked-Lists Summary We’ve seen a very simple linked-list implementation. Examples: Stack ADT, List ADT (more general) Many variations: singly vs doubly linked, head and/or tail pointers, list cursors, dummy nodes Pick the structure to fit the problem being solved Common operations: traversals, insertions, deletions 3/30/98


Download ppt "CSE 143 Linked Lists [Chapter 8.1-8.6, 8.8] 3/30/98."

Similar presentations


Ads by Google