CS 103 Unit 11 Linked Lists Mark Redekopp 2 NULL Pointer Just - - PowerPoint PPT Presentation

cs 103 unit 11
SMART_READER_LITE
LIVE PREVIEW

CS 103 Unit 11 Linked Lists Mark Redekopp 2 NULL Pointer Just - - PowerPoint PPT Presentation

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


slide-1
SLIDE 1

1

CS 103 Unit 11

Linked Lists Mark Redekopp

slide-2
SLIDE 2

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

slide-3
SLIDE 3

3

Arrays Review

  • Fast access: Because arrays are contiguous in

memory we can find a single value with only:

– The start address – Which element we want (e.g. index 20)

  • Index 20 lives at: start_address + 20*(size_of_int)

– If we know integer element i is at location 108 do we know where element i+1 is?

  • Can't grow (resize): Once we declare the array

(either statically on the stack or dynamically on the heap) we cannot increase its size

Memory

100

45 31 21 04 98 73 …

104 108 112 116 120 data = 100

#include<iostream> using namespace std; int main() { int data[25]; data[20] = 7; return 0; } #include<iostream> using namespace std; int main() { int size; cout << "Enter size: "; cin >> size; int *ptr = new int[size]; // What if we end up // needing more than size? } 30 51 52 53 54 1 2 3 4 5 10 6 7 8 9 10 11 30 51 52 53 54 1 2 3 4 5 10 21

Old, full array Copy over items then add value

1 2 3 4 5 6 7 8 9 10 11

Allocate new array Add one more value

slide-4
SLIDE 4

4

Analogy

  • Natural analogy when we have a

set of items that can change is to create a list

– Write down what you know now – Can add more items later (usually to the end of the list) – Remove (cross off) others when done with them

  • Can only do this with an array if

you know max size of list ahead of time (which is sometimes fine)

  • 1. Do CS 103 lab
  • 2. Join ACM or IEEE
  • 3. Play Video Games
  • 4. Watch a movie
  • 5. Exercise
  • 1. Do CS 103 lab
  • 2. Join ACM or IEEE
  • 3. Play Video Games
  • 4. Watch a movie
  • 5. Exercise
  • 6. Eat dinner
slide-5
SLIDE 5

5

BFS Queue Example

  • The size of the BFS Queue

grew and shrunk based on the data pattern

  • But we wasted a whole

LARGE array planning for the worst case

  • It'd be great to store only

what we need where our storage can grow and shrink

. . S . # . # # # # # F 5 5 1 9 5 1 9 2

head tail head tail head tail

5 1 9 2

head tail

slide-6
SLIDE 6

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)

val next

3

0x1c0 val next

9

0x168 0x148 head 0x148 0x1c0 val next

2

0x0 (Null) 0x168

slide-7
SLIDE 7

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?

val next

5

0x240 val next

8

0x0 (Null) 0x300 head 0x300 0x200 val next

4

0x3e0 0x240 val next

1

0x200 0x3e0

slide-8
SLIDE 8

8

Arrays vs. Linked List

  • If we have the start address of an

array can we get the i-th element quickly?

– Yes: start-addr + i * sizeof(data)

  • If we have the start (head) pointer

to a linked list can we find the i-th element quickly?

– No…Have to walk the linked list – Items are NOT CONTIGUOUS

  • Linked lists trade the ability to

resize (grow/shrink) for speed of access when attempting to get a specific element

Memory

100

45 31 21 04 98 73 …

104 108 112 116 120 data = 100

#include<iostream> using namespace std; int main() { int data[25]; data[20] = 7; return 0; }

val next

3

0x1c0 val next

9

0x168 0x148 head 0x148 0x1c0 val next

2

0x0 (Null) 0x168

slide-9
SLIDE 9

9

Linked List

  • Use structures/classes and pointers

to make linked data structures

  • List

– Arbitrarily sized collection of values – Can add any number of new values via dynamic memory allocation

  • Should always dynamically allocate

Items in a linked list

– Usually supports following set of

  • perations:
  • Append (“push_back”)
  • Prepend (“push_front”)
  • Remove back item (“pop_back”)
  • Remove front item (“pop_front”)
  • Find (look for particular value)

#include<iostream> using namespace std; struct Item { int val; Item* next; }; class List { public: List(); ~List(); void push_back(int v); ... private: Item* head; };

int val Item * next struct Item blueprint: Rule of thumb: Still use ‘structs’ for objects that are purely collections of data and don’t really have

  • perations associated with them. Use ‘classes’ when

data does have associated functions/methods.

next

val

0x0 head

slide-10
SLIDE 10

10

Linked List

  • Use structures/classes and pointers

to make linked data structures

  • Arbitrarily sized collection of values
  • Can add any number of new values

via dynamic memory allocation

– Should always dynamically allocate Items in a linked list – Why? Look at the code in List::push_back() and ask what would happen if we just declare the Item on the stack?

  • Most operations on a linked list

require a check to determine two potential cases: if the list IS empty

  • r NOT empty:

– May be necessary to avoid de- referencing a NULL pointer (i.e. segfault) – Or if the list is empty we may need to modify head

#include<iostream> using namespace std; List::List() { head = NULL; } void List::push_back(int v){ if(head == NULL){ // list is empty head = new Item; head->val = v; head->next = NULL; } else { ... } } int main() { List mylist; mylist.push_back(3); }

val next 0x0 0x148

3

NULL 0x148 head

slide-11
SLIDE 11

11

NULL

Linked List

  • Use structures/classes and pointers to

make linked data structures

  • Arbitrarily sized collection of values
  • Can add any number of new values via

dynamic memory allocation

– Should always dynamically allocate Items in a linked list – Why? Look at the code in List::push_back() and ask what would happen if we just declare the Item on the stack?

  • Most operations on a linked list require

a check to determine two potential cases: if the list IS empty or NOT empty:

– May be necessary to avoid de-referencing a NULL pointer (i.e. segfault) – Or if the list is empty we may need to modify head

val next

3

0x1c0 val next

9

0x0 NULL 0x148 head 0x148 0x1c0

#include<iostream> using namespace std; List::List() { head = NULL; } void List::push_back(int v){ if(head == NULL){ head = new Item; head->val = v; head->next = NULL; } else { ... } // list is not empty } int main() { List mylist; mylist.push_back(3); mylist.push_back(9); }

0x148 head

slide-12
SLIDE 12

12

Linked List

  • Use structures/classes and pointers to

make linked data structures

  • Arbitrarily sized collection of values
  • Can add any number of new values via

dynamic memory allocation

– Should always dynamically allocate Items in a linked list – Why? Look at the code in List::push_back() and ask what would happen if we just declare the Item on the stack?

  • Most operations on a linked list require

a check to determine two potential cases: if the list IS empty or NOT empty:

– May be necessary to avoid de-referencing a NULL pointer (i.e. segfault) – Or if the list is empty we may need to modify head

val next

3

0x1c0 val next

9

0x168 0x148 head 0x148 0x1c0 val next

2

0x0 (Null) 0x168

#include<iostream> using namespace std; List::List() { head = NULL; } void List::push_back(int v){ if(head == NULL){ head = new Item; head->val = v; head->next = NULL; } else { ... } } int main() { List mylist; mylist.push_back(3); mylist.push_back(9); mylist.push_back(2); }

0x148 head

slide-13
SLIDE 13

13

Common Linked Task/Mistake 1

  • What is the C++ code to take a

step from one item to the next

  • Answer:

– __________________________

  • Lesson: To move a pointer to the

next item use: _____________________

val next

3

0x1c0 val next

9

0x0 NULL 0x148 head 0x148 0x1c0

0x148 temp Before taking step 0x1c0 temp After taking step

slide-14
SLIDE 14

14

Common Linked Task/Mistake 2

  • Why do we need a temp pointer?

Why can't we just use head to take a step as in:

– head = head->next;

  • Because if we change head we

have no ___________________ __________________________

– Once we take a step we have "amnesia" and forget where we came from and can't retrace our steps

  • Lesson: __________________!

val next

3

0x1c0 val next

9

0x0 NULL 0x148 head 0x148 0x1c0 Before taking step After taking step 1c0 head

slide-15
SLIDE 15

15

Common Linked Task/Mistake 3

  • Mistake: Many students use the following

code to get a pointer to the first item:

– Item* temp = head->next;

  • head is special! It is NOT an actual ITEM

struct

– head is just a pointer – It just points at the first data-filled struct – head->next actually points to the 2nd item, not the 1st because head already points to the 1st item

  • Lesson: To get a pointer to the FIRST item,

just use _____________

val next

3

0x1c0 val next

9

0x0 NULL 0x148 head 0x148 0x1c0 Before taking step 0x1c0 temp Mistake: Thinking head->next is a pointer to the first Item

?

0x148 Mistake: Students

think head is an Item head Item* temp= head->next

Each car = "Item" Engine = "head"

slide-16
SLIDE 16

16

Common Linked Task/Mistake 4

  • Common errors we see is that to create a

temporary pointer students also dynamically allocate an item and then immediately point it at something else causing a memory leak

– Item* temp = _______________; – temp = head; or temp = head->next;

  • You may declare pointers w/o having to

allocate anything

– Item* temp; – Item* temp = NULL; – Item* temp = head;

  • Lesson: Only use 'new' when you really

want a new Item to come alive

val next

3

0x1c0 val next

9

0x0 NULL 0x148 head 0x148 0x1c0 Before taking step After taking step 1c0 head 0x2a0 temp Mistake: Allocating an item when you declare a temporary pointer

?

??? 0x148 0x00 Item* temp=NULL; 0x148 Item* temp=head; ??? Item* temp; 0x148 temp = head;

slide-17
SLIDE 17

17

Exercises

  • In-class exercises:

– monkey_traverse – monkey_addstart

Childs toy "Barrel of Monkeys" let's children build a chain of monkeys that can be linked arm in arm

http://www.toysrus.com/graphics/tru_prod_images/Barrel-of-Monkeys-Game----pTRU1-2907042dt.jpg

slide-18
SLIDE 18

18

Exercise

  • Write an integer linked list class
  • See sandbox-linked-lists on Vocareum
  • OR
  • Download the skeleton:

– Go to your examples directory – wget http://ee.usc.edu/~redekopp/cs103/listint.tar – tar xvf ListInt.tar

  • listint.h, listint.cpp, listint_test.cpp
  • Examine the prototypes in listint.h (complete)
  • Complete the functions in listint.cpp
  • Compile and test your program the code in listint_test.cpp
slide-19
SLIDE 19

19

Append

  • Write a function to add new item

to back of list

  • Start from head and iterate to end
  • f list

– Copy head to a temp pointer – Use temp pointer to iterate through the list until we find the tail (element with next field = NULL) – Allocate new item and fill it in – Update old tail item to point at new tail item

val next

3

0x1c0 val next

9

0x0 NULL 0x148 head 0x148 0x1c0 val next

2

0x0 (Null) 0x168 0x168 0x148 temp

I don’t know where the list ends so I have to traverse it

0x1c0 temp

slide-20
SLIDE 20

20

Remove First

  • Write a function to remove

first item

– Copy address of first item to a temp pointer – Set head to point at new first item (only second item) – Deallocate old first item

val next

3

0x1c0 val next

9

0x168 0x148 head 0x148 0x1c0 val next

2

0x0 (Null) 0x168 val next

3

0x1c0 val next

9

0x168 0x148 head 0x148 0x1c0 val next

2

0x0 (Null) 0x168 0x1c0

Before After

slide-21
SLIDE 21

21

Other Functions

  • Write a function to print all items in list

– Copy head to a temp pointer then use it to iterate over the items until the next pointer is NULL – Print each item as you iterate

  • Find if an item in the list (return address of struct if present or

NULL)

– Copy head to a temp pointer then use it to iterate over the items until you find an item with the desired value or until next pointer is NULL

  • Remove item with given value [i.e. find and remove]

– If found, need to change the next link of the previous item to point at the item after the item found

val next

3

0x1c0 val next

9

0x168 0x148 head 0x148 0x1c0 val next

2

0x0 (Null) 0x168

Remove VAL=9

0x168

slide-22
SLIDE 22

22

Comparing Performance

Arrays

  • Go to element at index I

– O(___)

  • Add something to the tail

(assume you have a tail index)

– O(___)

  • Adding something to the

front of the list after there are already n elements

– O(___)

Linked Lists

  • Go to element at index i

– O(__)

  • Add something to the tail

(assume you have only head pointer and n elements in the list)

– O(__)

  • Adding something to the

front of the list after there are already n elements

– O(__)

slide-23
SLIDE 23

23

SOLUTIONS

slide-24
SLIDE 24

24

Common Linked Task/Mistake 1

  • What is the C++ code to take a

step from one item to the next

  • Answer:

– temp = temp->next

  • Lesson: To move a pointer to the

next item use: 'ptr = ptr->next'

val next

3

0x1c0 val next

9

0x0 NULL 0x148 head 0x148 0x1c0

0x148 temp Before taking step 0x1c0 temp After taking step

slide-25
SLIDE 25

25

Common Linked Task/Mistake 2

  • Why do we need a temp pointer?

Why can't we just use head to take a step as in:

– head = head->next;

  • Because if we change head we

have no record of where the first item is

– Once we take a step we have "amnesia" and forget where we came from and can't retrace our steps

  • Lesson: Don't lose your head!

val next

3

0x1c0 val next

9

0x0 NULL 0x148 head 0x148 0x1c0 Before taking step After taking step 1c0 head

slide-26
SLIDE 26

26

Common Linked Task/Mistake 3

  • Mistake: Many students use the following

code to get a pointer to the first item:

– Item* temp = head->next;

  • head is special! It is NOT an actual ITEM

struct

– head is just a pointer – It just points at the first data-filled struct – head->next actually points to the 2nd item, not the 1st because head already points to the 1st item

  • Lesson: To get a pointer to the FIRST item,

just use 'head'

val next

3

0x1c0 val next

9

0x0 NULL 0x148 head 0x148 0x1c0 Before taking step 0x1c0 temp Mistake: Thinking head->next is a pointer to the first Item

?

0x148 Mistake: Students

think head is an Item head Item* temp= head->next

Each car = "Item" Engine = "head"

slide-27
SLIDE 27

27

Common Linked Task/Mistake 4

  • Common errors we see is that to create a

temporary pointer students also dynamically allocate an item and then immediately point it at something else causing a memory leak

– Item* temp = new Item; – temp = head; or temp = head->next;

  • You may declare pointers w/o having to

allocate anything

– Item* temp; – Item* temp = NULL; – Item* temp = head;

  • Lesson: Only use 'new' when you really

want a new Item to come alive

val next

3

0x1c0 val next

9

0x0 NULL 0x148 head 0x148 0x1c0 Before taking step After taking step 1c0 head 0x2a0 temp Mistake: Allocating an item when you declare a temporary pointer

?

??? 0x148 0x00 Item* temp=NULL; 0x148 Item* temp=head; ??? Item* temp; 0x148 temp = head;

slide-28
SLIDE 28

28

Comparing Performance

Arrays

  • Go to element at index I

– O(1)

  • Add something to the tail

(assume you have a tail index)

– O(1)

  • Adding something to the

front of the list after there are already n elements

– O(n)

Linked Lists

  • Go to element at index i

– O(i)

  • Add something to the tail

(assume you have only head pointer and n elements in the list)

– O(n)

  • Adding something to the

front of the list after there are already n elements

– O(1)