1 CS 103 Unit 11 Linked Lists Mark Redekopp
2 NULL Pointer • Just like there was a null character in ASCII = '\0' whose value was 0 there is a NULL pointer whose value is 0 – Used to represent a pointer to "nothing" – NULL is "keyword" you can use in C/C++ that is defined to be 0 – nullptr is an equivalent keyword in C++ version 11 and onward and has some advantages best explained later… • Requires special compile flags, so we may default to NULL for now • Used to indicate that the pointer does NOT point at valid data – Nothing ever lives at address 0 of memory so we can use it to mean "pointer to nothing" – Often used as an "error" return value from functions returning pointers (See http://www.cplusplus.com/reference/cstring/strchr/ ) – char* ptr = strchr("Hello", 'h') if(ptr != NULL){ … } // it's a good pointer
3 Arrays Review • #include<iostream> Fast access: Because arrays are contiguous in using namespace std; memory we can find a single value with only: int main() { – The start address int data[25]; – Which element we want (e.g. index 20) data[20] = 7; return 0; • Index 20 lives at: start_address + 20*(size_of_int) } – If we know integer element i is at location 108 do data = 100 we know where element i+1 is? 100 104 108 112 116 120 • … Can't grow (resize): Once we declare the array 45 31 21 04 98 73 Memory (either statically on the stack or dynamically on the heap) we cannot increase its size #include<iostream> using namespace std; Add one more 21 value int main() 0 1 2 3 4 5 { Old, full array 30 51 52 53 54 10 int size; cout << "Enter size: "; 0 1 2 3 4 5 6 7 8 9 10 11 cin >> size; Allocate new int *ptr = new int[size]; array 0 1 2 3 4 5 6 7 8 9 10 11 // What if we end up Copy over items // needing more than size? 30 51 52 53 54 10 } then add value
4 Analogy • Natural analogy when we have a 1. Do CS 103 lab set of items that can change is to 2. Join ACM or IEEE 3. Play Video Games create a list 4. Watch a movie – Write down what you know now 5. Exercise – Can add more items later (usually to the end of the list) – Remove (cross off) others when done with them 1. Do CS 103 lab 2. Join ACM or IEEE • Can only do this with an array if 3. Play Video Games you know max size of list ahead of 4. Watch a movie 5. Exercise time (which is sometimes fine) 6. Eat dinner
5 BFS Queue Example . . . # • The size of the BFS Queue # S # # grew and shrunk based on # . # F the data pattern • But we wasted a whole head tail LARGE array planning for the 5 worst case head tail • It'd be great to store only 5 1 9 what we need where our head tail storage can grow and shrink 5 1 9 0 2 head tail 5 1 9 0 2
6 Linked Lists • A linked list stores values in separate chunks of memory (i.e. a dynamically allocated object) • To know where the next one is, each one stores a pointer to the next • We can allocate more or delete old ones as needed so we only use memory as needed • All we do is track where the first object is (i.e. the head pointer) 0x148 0x1c0 0x168 head 0x148 0x0 3 9 2 0x1c0 0x168 (Null) val next val next val next
7 Linked Lists • What is the order of values in this linked list? • How would you insert 6 at the front of the list? • How would you remove the value 4? 0x200 head 0x0 8 (Null) 0x300 val next 0x240 4 0x3e0 0x300 val next 5 0x240 val next 0x3e0 1 0x200 val next
8 Arrays vs. Linked List #include<iostream> using namespace std; • If we have the start address of an int main() { array can we get the i-th element int data[25]; data[20] = 7; quickly? return 0; } – Yes: start-addr + i * sizeof(data) data = 100 • If we have the start (head) pointer 100 104 108 112 116 120 … to a linked list can we find the i-th 45 31 21 04 98 73 Memory element quickly? – No…Have to walk the linked list head – Items are NOT CONTIGUOUS 0x148 • Linked lists trade the ability to 0x148 0x1c0 0x168 resize (grow/shrink) for speed of 0x0 3 9 2 0x1c0 0x168 (Null) access when attempting to get a val next val next val next specific element
9 Linked List #include<iostream> • Use structures/classes and pointers using namespace std; struct Item to make linked data structures blueprint: struct Item { • int val; List int Item * Item* next; val next – Arbitrarily sized collection of }; next val values class List { – Can add any number of new values public: via dynamic memory allocation List(); ~List(); • Should always dynamically allocate void push_back( int v); ... Items in a linked list private: – Usually supports following set of Item* head; }; operations: • Append (“ push_back ”) head 0x0 • Prepend (“ push_front ”) • Remove back item (“ pop_back ”) • Remove front item (“ pop_front ”) • Find (look for particular value) Rule of thumb : Still use ‘ structs ’ for objects that are purely collections of data and don’t really have operations associated with them. Use ‘ classes ’ when data does have associated functions/methods.
10 Linked List #include<iostream> • Use structures/classes and pointers using namespace std; to make linked data structures List::List() { • Arbitrarily sized collection of values head = NULL; } • Can add any number of new values void List::push_back( int v){ via dynamic memory allocation if( head == NULL ){ // list is empty head = new Item; – Should always dynamically allocate head->val = v; head->next = NULL; Items in a linked list } else { ... } – Why? Look at the code in } List::push_back() and ask what would int main() happen if we just declare the Item on { the stack? List mylist; mylist.push_back( 3 ); • Most operations on a linked list } require a check to determine two head 0x148 potential cases: if the list IS empty 0x0 or NOT empty: – May be necessary to avoid de- 0x148 referencing a NULL pointer (i.e. 3 NULL segfault) val next – Or if the list is empty we may need to modify head
11 Linked List #include<iostream> • Use structures/classes and pointers to using namespace std; make linked data structures List::List() { • Arbitrarily sized collection of values head = NULL; } • Can add any number of new values via void List::push_back( int v){ dynamic memory allocation if(head == NULL){ head = new Item; – Should always dynamically allocate Items in head->val = v; head->next = NULL; a linked list } else { ... } // list is not empty – Why? Look at the code in List::push_back() } and ask what would happen if we just int main() declare the Item on the stack? { • List mylist; Most operations on a linked list require mylist.push_back( 3 ); mylist.push_back( 9 ); a check to determine two potential } cases: if the list IS empty or NOT head head 0x148 empty: 0x148 – May be necessary to avoid de-referencing a NULL pointer (i.e. segfault) 0x148 0x1c0 – 0x0 Or if the list is empty we may need to modify 3 9 0x1c0 NULL NULL head val next val next
12 Linked List #include<iostream> using namespace std; • List::List() Use structures/classes and pointers to { make linked data structures head = NULL; } • Arbitrarily sized collection of values void List::push_back(int v){ • if(head == NULL){ Can add any number of new values via head = new Item; dynamic memory allocation head->val = v; head->next = NULL; } – Should always dynamically allocate Items in else { ... } a linked list } – Why? Look at the code in List::push_back() int main() { and ask what would happen if we just List mylist; declare the Item on the stack? mylist.push_back(3); mylist.push_back(9); • Most operations on a linked list require mylist.push_back(2); } a check to determine two potential cases: if the list IS empty or NOT head head 0x148 empty: 0x148 – May be necessary to avoid de-referencing a NULL pointer (i.e. segfault) 0x148 0x1c0 0x168 – 0x0 Or if the list is empty we may need to modify 3 9 2 0x1c0 0x168 (Null) head val next val next val next
13 Common Linked Task/Mistake 1 • What is the C++ code to take a step from one item to the next head 0x148 • Answer: 0x148 0x1c0 – __________________________ 0x0 3 9 0x1c0 • Lesson: To move a pointer to the NULL val next val next next item use: _____________________ 0x148 0x1c0 temp temp Before taking step After taking step
14 Common Linked Task/Mistake 2 • Why do we need a temp pointer? Before taking step After taking step Why can't we just use head to take head head 0x148 1c0 a step as in: – head = head->next; 0x148 0x1c0 0x0 • Because if we change head we 3 9 0x1c0 NULL val next val next have no ___________________ __________________________ – Once we take a step we have "amnesia" and forget where we came from and can't retrace our steps • Lesson: __________________!
Recommend
More recommend