1 Lecture 4 Resource Management Part 2 Assignment

  • Slides: 74
Download presentation
1 Lecture #4 • Resource Management, Part 2 – Assignment Operators • Basic Linked

1 Lecture #4 • Resource Management, Part 2 – Assignment Operators • Basic Linked Lists – Insertion, deletion, destruction, traversals, etc. • Advanced Linked Lists – Tail Pointers – Doubly-linked Lists

2 The Assignment Operator int main() { Circ x(1, 2, 3); N ew va

2 The Assignment Operator int main() { Circ x(1, 2, 3); N ew va ria } ng ti is ble Ex ria va bl e Circ y = x; int main() { Circ foo(1, 2, 3); Circ bar(4, 5, 6); bar = foo; ng ti is ble Ex ria va Ex va isti ria ng ble } Last time we learned how to construct a new variable using the value of an existing variable (via the copy constructor). Now lets learn how to change the value of an existing variable to the value of an another variable. In this example, both foo and bar have been constructed. Both have had their member variables initialized. Then we set bar equal to foo.

3 The Assignment Operator In this case, the copy constructor is NOT used to

3 The Assignment Operator In this case, the copy constructor is NOT used to copy values from foo to bar. Instead, a special member function called an assignment operator is used to copy foo’s values into bar. Why isn’t bar’s copy constructor called? int main() { Circ foo(1, 2, 3); Circ bar(4, 5, 6); bar = foo; } Lets see how to define our own assignment operator. If you don’t define your own Because bar was already constructed assignment operator… on the line above! Then C++variable provides a default The bar already exists and version that just copies each is already initialized, so it doesn’t makeof anythe sense to re-construct it! members. bar m_x m_y m_rad 41 2 5 6 3 foo m_x m_y m_rad 1 2 3

4 foo The Assignment Operator Hmmm. . This looks class Circ { familiar, doesn’t

4 foo The Assignment Operator Hmmm. . This looks class Circ { familiar, doesn’t it? class Circ . . . { void set. Me. Equal. To(const Circ &src) What does it remind { public: m_x = src. m_x; you of? Circ(float x, float y, float r) m_y = src. m_y; { m_rad = src. m_rad; m_x = x; m_y = y; m_rad = r; } }. . . private: void set. Me. Equal. To(const Circ &src) m_x m_y m_rad 1 2 3 { } 1 2 float Get. Area(void) m_x = src. m_x; m_y = src. m_y; { m_rad = src. m_rad; return(3. 14159*m_rad); } }. . . private: m_x m_y m_rad 5 float m_x, m_y, m_rad; 6 4 } }; So lets define a simpler version first… 3 m_x = src. m_x; bar class Circ m_y = src. m_y; { m_rad = src. m_rad; . . . } void set. Me. Equal. To(const Circ &src) { The syntax for an assignment operator is a bit confusing. Here’s how we’d use our new function. When we’re done, bar int main() is a perfect clone of { foo! Circ foo(1, 2, 3); Circ bar(4, 5, 6); bar. set. Me. Equal. To(foo); } // same as bar = foo;

5 The Assignment Operator class Circ Now letsa see what a real The const

5 The Assignment Operator class Circ Now letsa see what a real The const You keyword MUST guarantees pass reference to { assignment operator that the source object. (src) This is means public: like. not modified during you have the looks copy. to have Circ(float x, float y, float r) { the & here!!! m_x = x; m_y = y; m_rad = r; 1. The function name is } operator= void set. Me. Equal. To Circ & operator= (const Circ &src) { 2. The function return m_x = src. m_x; I’ll explain this type is a reference to m_y = src. m_y; more in athe bit… m_rad = src. m_rad; class. return(*this); 3. The function returns } float Get. Area(void) *this when its done. { return(3. 14159*m_rad); } private: float m_x, m_y, m_rad; };

6 foo Another way to read: The Assignment Operat bar = foo; class Circ

6 foo Another way to read: The Assignment Operat bar = foo; class Circ { . . . class Circ &operator=(const Circ &src) { { public: m_x = src. m_x; m_y = src. m_y; C++: “Since the Circ(float x, float y, float r) m_rad = src. m_rad; programmer defined an return(*this); { } assignment operator for m_x = x; m_y = y; m_rad = r; . . . Circles, I’ll use it to do } private: void Assign (const Circ &src) Circ & operator= m_x m_y m_rad the 1 2 assignment. ” 3 { } So, to summarize… If you’ve defined an operator= function in a class… Then any 1 time you 2 use the 3 equal sign to set an existing m_x = src. m_x; bar m_y = src. m_y; variable equal to another… m_rad = src. m_rad; return(*this); C++ will call the operator= } float Get. Area(void) function of your target { variable and pass in the return(3. 14159*m_rad); } source variable! private: float m_x, m_y, m_rad; }; C++: “Ooh, is: the programmer is using the int main() bar. operator=(foo); equal sign to set bar { i. e. , we’re calling equal to foo. ”bar’s Circ foo(1, 2, 3); operator= member function! Circ bar(4, 5, 6); bar = foo; bar. operator=(foo); } class Circ { . . . Circ &operator=(const Circ &src) { m_x = src. m_x; m_y = src. m_y; m_rad = src. m_rad; return(*this); }. . . private: m_x m_y m_rad 6 5 4 }

7 The Assignment Operator class Squares { public: Squares(int n) { m_n = n;

7 The Assignment Operator class Squares { public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0; j<n; j++) m_sq[j] = (j+1)*(j+1); } ~ Squares(){delete []m_sq; } void print. Squares() { for (int j=0; j<n; j++) cout << m_sq[j] << endl; } private: int *m_sq, m_n; }; Ok – so when would we ever need to write our own Assignment Operator? After all, C++ copies all of the fields for us automatically if we don’t write our own! Remember our updated Squares class… Lets see what happens if we use the default assignment operator with it…

8 The Assignment Operator And, as we saw last time, now At this point,

8 The Assignment Operator And, as we saw last time, now At this point, the built-in both variables a and b to the same array! class Squares assignment operator doespoint main() Neither a nor b now point { Operating System, can you { a shallow copy from a to b. That’s gonna cause problems! public: to our array at 900! Squares a(3); free the memory at Squares(int n) { Then b’s been destructor a’s destructor address 800 m_n = n; Andfor evenme. worse, when First our function It’s totally Squares b(4); m_sq = new int[n]; isforgotten! called. ends, we have a memory leak! for (int j=0; j<n; j++) b = a; Our array at 900 was never freed! m_sq[j] = (j+1)*(j+1); } // a’s d’tor is called, then b’s } And C++ won’t tell you about this! Whoops! We have a ~ Squares(){delete []m_sq; } problem – we’re about to void print. Squares() { forget where our original for (int j=0; j<n; j++) array is located! cout << m_sq[j] << endl; } private: int *m_sq, m_n; }; 1 00000800 00000804 already 4 asked 00000808 that!9 I can’t a m_n 3 Wait! You m_sq 800 do me to No sweat, homie. it twice!!! b m_n free 00000900 1 4 3 Consider it freed. ERROR!!!! 00000904 4 m_sq 900 800 9 16 00000908 00000912

9 Assignment Operator Carey Forsays: such classes, “Patience, grasshopper!” you must define The right

9 Assignment Operator Carey Forsays: such classes, “Patience, grasshopper!” you must define The right side your own asignment operator! requires three slots of memory! Here’s how it works for b = a; What does this mean? !? !? 1. 2. 3. 4. 5. Free any memory currently held by the target variable (b). Determine how much memory is used by the source variable (a). Allocate the same amount of memory in the target variable. Copy the contents of the source variable to the target variable. Return a reference to the target variable. This makes my brain hurt! a m_n 3 m_sq 800 b m_n 3 4 m_sq 900 700 1 4 9 00000800 00000804 00000808 1 4 9 16 00000900 00000700 00000904 00000704 00000908 00000708 00000912

10 The Assignment Operator class Squares int main() OK, first let’s add a line

10 The Assignment Operator class Squares int main() OK, first let’s add a line to { { free the memory used by much Next let’s determine how public: Squares a(3); the target object. Next we’ll a Squares b(4); statement to Operating System, Iadd no memory is required to hold the Squares(int n) { … } Now we can add statement(s) to allocate enough ~ Squares(){ delete[]m_sq; } source object’s data. so the statement Finally, we’ll addat astorage so longer need copy the memory over all thea b = a; data from the target canof hold copy of the function returns a reference OS: Can you reserve 12 locationsource 900. // assignment operator: tosource’s the target variable! data. to itself when it’s done. Squares &operator=(const Squares &src) bytes of memory for me? } { (Don’t worry, I’ll explain soon) delete [] m_sq; m_n = src. m_n; m_sq = new int[m_n]; for (int j=0; j<m_n; j++) 1 000800 src a m_n 3 12 bytes m_sq[j] = src. m_sq[j]; Sure. Here’s 000804 4 return(*this); Ok, m_sq 800 of memory for I’ll free thatyou up 9 at for 000808 } address to use. void print. Squares() {. . . } someone 000860 b m_n else 860. 000900 1 4 3 private: int *m_sq, m_n; }; 860 m_sq 900 4 9 16 000864 000904 000868 000908 000912

11 Operating. System, I no Operating you can The Assignment Operator longer need the

11 Operating. System, I no Operating you can The Assignment Operator longer need the memory at free the memory at class Squares int main() location 860. 800. address OK, let’s see if everything { { public: works properly now during Squares(int n) { … } destruction! ~ Squares(){ delete[]m_sq; } Squares a(3); Squares b(4); b = a; // assignment operator: Squares &operator=(const Squares &src) } // a’s d’tor is called, then b’s { delete [] m_sq; … and everything is m_n = src. m_n; m_sq = new int[m_n]; freed perfectly! for (int j=0; j<m_n; j++) 1 000800 a m_n 3 m_sq[j] = src. m_sq[j]; 000804 4 return(*this); m_sq 800 000808 9 } void print. Squares() {. . . } Ok, I’ll freethatup for 000860 b free 1 m_n 4 3 private: int *m_sq, m_n; }; 4 someone you. else 860 to use. m_sq 900 9 000864 000868

12

12

13 The Assignment Operator And this line returns the tim variable, so if we

13 The Assignment Operator And this line returns the tim variable, so if we class CSNerd tim { wanted, we could do yet the So this lineisreturns Question: Why do we have class CSNerd “this” a special C++ CSNerd &operator= (const CSNerd &src) another assignment! { { return(*this) at the end of the ted variable itself! pointer variable that m_num. PCs = src. m_num. PCs; So if “this” is a pointer public: assignment operator function? m_has. Mac = src. m_has. Mac; Strange huh? A member So, to sum up… holds thethen address of the return(*this); . . . to ted, “*this” So. Sothe statement: } Answer: we can do multiple function of a variable The assignment operator current object (i. e. , ted’s refers CSNerd &operator=(const CSNerd &src) m_num. PCs true to the whole ted 3 5 m_has. Mac false “tedassignment =in sam” is assignments the same All can return the variable }; returns “*this” so that { address in RAM) statement, like this… variable. just replaced by isa performed m_num. PCs = src. m_num. PCs; First we call ted’s itself!? !? there’s always ted class CSNerd variable { m_has. Mac = src. m_has. Mac; the ted variable! right-to-left… assignment CSNerd &operator= (const CSNerd &src) on the right hand side of return(*this); { Next, C++ sets operator to assign m_num. PCs = src. m_num. PCs; theint main() = for the next } m_has. Mac = src. m_has. Mac; tim equal tototed. him sam. return(*this); { assignment. private: } int m_num. PCs; m_num. PCs 10 5 m_has. Mac false }; bool m_has. Mac; }; sam class CSNerd sam(5, false); CSNerd ted(10, false); CSNerd tim(3, true); { CSNerd &operator= (const CSNerd &src) { m_num. PCs = src. m_num. PCs; m_has. Mac = src. m_has. Mac; return(*this); } bill tim = ted = sam; = m_num. PCs 5 m_has. Mac }; false }

14 The Assignment Operator Here’s hint! “Aliasing” is when we use a two different

14 The Assignment Operator Here’s hint! “Aliasing” is when we use a two different references/pointers to refer to the same variable. void f(Squares &x, Squares &y) Our assignment has one It can causeoperator unintended problems! { more problem with it… Can anyone . . . guess what it is? x = y; // really a = a; !!! } class Squares Operating System, you int main() { public: can free the memory at { . . . Squares a(3); OS: Can you reserve 12 address 800. f(a, a); bytes of memory for me? Squares &operator=(const Squares &src) } { delete [] m_sq; 1 000800 m_n = src. m_n; src a m_n 3 000804 4 m_sq = new int[m_n]; -52 000420 m_sq 420 800 000808 9 for (int j=0; j<m_n; j++) 19 000424 m_sq[j] = src. m_sq[j]; 34 000428 return(*this); } Sure. Hmm. . . Here’s What 12 bytes happens private: int *m_sq, m_n; }; Sofree nowthat we copy the So what values at Ok, I’ll upare for of memory you if we for setvalues a toatitself? random over location 420 -428? ? someone else to use. address 420. ones! themselves! RANDOM

15 The Assignment Operator The fix: Our assignment operator function must check to see

15 The Assignment Operator The fix: Our assignment operator function must check to see if a variable is being assigned toasitself, and if so, do nothing… Is the same the If the right-hand variable’s address… class Squares { . . . left-hand variable’s address… Squares &operator=(const Squares &src) { if (&src == this) return(*this); // do nothing delete [] m_sq; m_n = src. m_n; Then they’re the same variable! m_sq = new int[m_n]; for (int j=0; j<m_n; j++) We simply return a reference to m_sq[j] = src. m_sq[j]; the variable and do nothing else! return(*this); } … And we’re done! };

16 Copy Constructor/ Assignment Review Question: which of the following use the copy constructor

16 Copy Constructor/ Assignment Review Question: which of the following use the copy constructor and which use the assignment operator? int main() // #1// #3 Squares func(void) { { Squares a(4), b(3); Squares g(15); b = a; return(g); } } int main() // #2 int main() { { Squares c(5), d(c); Squares f = func(); Squares e = d; } }

17 Challenge struct Book { string title; string author; }; Write an assignment operator

17 Challenge struct Book { string title; string author; }; Write an assignment operator for our CSNerd Class: class CSNerd { public: CSNerd(string name) { m_my. Book = nullptr; m_my. Name = name; } void give. Book(string t, string a) { m_my. Book = new Book; m_my. Book->title = t; m_my. Book->author = a; } ~CSNerd() { delete m_my. Book; } private: Book *m_my. Book; string m_my. Name; };

18 Time for your favorite game! Programming Language Inventor Or Serial Killer See if

18 Time for your favorite game! Programming Language Inventor Or Serial Killer See if you can guess who uses a keyboard and who uses a chainsaw!

19 Linked Lists

19 Linked Lists

20 Arrays are great… But… Arrays are great when you need to store a

20 Arrays are great… But… Arrays are great when you need to store a fixed number of items… But what if you don’t know how many items you’ll have ahead of time? Then you have to reserve enough Still requires us slots for the largest possible to know case. the size int main() { } int array[100]; … int main() {{ int //num. Items, might have*ptr; 10 items or 1 M int>>array[1000000]; cin num. Items; ptr … = newfint[num. Items]; o }} e st a w e! a t pac names[0] Andrew And what if you need to insert a new a h s names[1] Betty W item in the middle of an array? It takes Carey ahead of time! Even new/delete don’t really help! We have to move every item below the insertion spot down by one! And it’s just as slow if we want to delete an item! Yuck! names[2] names[3] names[4] names[999998] names[999999] David 1 M nearly Elaineto steps Frank add a new … item! Zappa

21 So Arrays Aren’t Always Great Hmm… Can Twe think of an approach h

21 So Arrays Aren’t Always Great Hmm… Can Twe think of an approach h e sta life” from “real works better rts huthat n t clua fixed-sized w than array? i e t h loc to ati the a the on How about the items as we of forganizing i r c he insta Scavenger Hunt? would st… Clue: The first item is by the tree Clue: The next item is by the house Clue: This is the last item! What can we think ofstore that: an Using this approach we can arbitrary of items! allows. Tnumber you to store an ch hen arbitrary of items a es number e There’s no nfixed limit to a ite t h ch the number c makes it fast to insert ol we lu and of chests ds can have! e m aclues loa new ca toitemndin the middle th tio th a emakes n it efast to delete ch anneitemoffrom the middle es xt t. ? Clue: The next item is by the tower

22 Clue: So Arrays Aren’t Always Great Also, using this approach we can quickly

22 Clue: So Arrays Aren’t Always Great Also, using this approach we can quickly add a new item to the middle! All we have to do is add a new chest and change a few clues! For instance, let’s add a new treasure between our books and our shell. Clue: The first item is by the tree y the p o c we o our t First e u l us c previo w chest. ne Clue: This is the last item! Clue: Thenextitemis The isbybythe thetemple house we n e Th e the to at e upd us clu new vio ur pre t to o ! t n poi ches The next item is by the tower

23 Clue: The next item is by the house So Arrays Aren’t Always Great

23 Clue: The next item is by the house So Arrays Aren’t Always Great Finally, using this approach we can quickly remove an item from the middle! All we have to do is remove the target chest and change a single clue! Clue: The first item is by the tree Clue: The next item is by the temple Clue: This is the last item! ? Clue: The next item For instance, let’s by the tower remove thisischest from the hunt…

24 A C++ Scavenger Hunt? Ok, so in our Scavenger Hunt, we had: A

24 A C++ Scavenger Hunt? Ok, so in our Scavenger Hunt, we had: A clue that leads us to our first treasure chest. Each chest then holds an item (e. g. , books) and a clue that leads us to the next chest. So here’s the question… can we simulate a Scavenger Hunt with a C++ data structure? Why not? Let’s see how. Clue: The first item is by the tree Clue: The next item is by the house Clue: The next item is

25 A C++ Scavenger Hunt? Well, we can use a C++ struct to represent

25 A C++ Scavenger Hunt? Well, we can use a C++ struct to represent a Chest. As we know, each Chest holds two things: A treasure – let’s use a string variable to hold our treasure, e. g. , “shells”. The location of the next chest – let’s represent that with a pointer variable. We can now define a Chest variable for each of the items in our scavenger hunt! struct Chest { string treasure; Chest * next. Chest; }; Clue: This line basically says that The first itemeach Chest variable is by the tree holds a pointer… to another Chest variable. Clue: The next item is by the house Clue: The next item is

26 A C++ Scavenger Hunt? Well, we can use a C++ struct to represent

26 A C++ Scavenger Hunt? Well, we can use a C++ struct to represent a Chest. As we know, each Chest holds two things: A treasure – let’s use a string variable to hold our treasure, e. g. , “shells”. struct Chest { string treasure; Chest * next. Chest; }; Clue: first OK, let’s see the C++ version The first 5000 item is byhunt the tree of next a simplified The location of the chest – let’sscavenger represent that with a pointer variable. data structure! We can now define a Chest variable for each of the items in our scavenger hunt! Clue: treasure “books” The next item next. Chest is by the house 3400 And we can define a pointer to point to the very first chest – our first clue! Chest *first; // pointer to our 1 st chest treasure Clue: “shells” The next item is next. Chest 1200

27 A C++ Scavenger Hunt? And update our This data structure is. We want

27 A C++ Scavenger Hunt? And update our This data structure is. We want to link up our first struct Chestchest to the called a “linked list. ” first chest so it first second chest… { points to it… string treasure; …should hold the Why? Because each int main(void) 1000 Chest * next. Chest; chest 1 treasure “books" elementof in the first list is {}; address We”linked” call each item in the Chest *first; chest! by a pointer next. Chest chest 1, chest 2, chest 3; linked list a element. “node. ” to the next Finally, we’ll indicate that the thirdnullptr is a special C++ first = &chest 1; chest is the last in the scavenger hunt. constant that means 1020 chest 2 chest 1. treasure “books"; “invalid pointer= value. ” “shells" We do thistreasure by setting its next. Chest chest 1. next. Chest = &chest 2; pointer to nullptr. next. Chest chest 3 chest 2. treasure = “shells"; chest 2. next. Chest = &chest 3; treasure “cash" next. Chest nullptr Our= first chest 3. treasure “cash"; chest 3. next. Chest = nullptr; pointer … 1040 } So we’ll get the address of the second chest…

28 struct Chest { string treasure; Chest * next. Chest; Normally, we don’t use

28 struct Chest { string treasure; Chest * next. Chest; Normally, we don’t use local variables }; to create our linked list. “Hey OS, can you allocate int main(void) 20 OS, bytes “Hey canfor youme? ” allocate Instead we use dynamically{ “Hey can for you me? ” allocate 20 OS, bytes Chest *first; allocated variables (and pointers!). *first, *second, *third; 20 bytes for me? ” Chest chest 1, chest 2, chest 3; Linked Lists first 5000 second 2200 treasure first = new Chest; second = new Chest; first = &chest 1; third = new Chest; chest 1. treasure = “books"; chest 1. next. Chest = &chest 2; 5000 next. Chest third treasure 3700 next. Chest treasure chest 2. treasure = “shells"; chest 2. next. Chest = &chest 3; 2200 chest 3. treasure = “cash"; chest 3. next. Chest = nullptr; OS: reserved OS: “Sure –– I’ve reserved 3700 some memory for you at at location 5000. ” location 2200. ” 3700. ” next. Chest }

29 struct Chest The pointer to the top { item in the linked list

29 struct Chest The pointer to the top { item in the linked list is string treasure; traditionally called the OK, now let’s“head add cargo and link ‘em up! Chest * next. Chest; pointer. ” Given just the head }; pointer, you can reach int main(void) Again, in our last node, we’ll set every element in the list… { its next. Chest pointer to nullptr. without using your other Linked Lists head *second, *third; Chest *first, external pointers! first head 5000 second treasure "books" head = newthat Chest; This first indicates it’s the last second new Chest; item= in the list. 5000 third = new Chest; first->treasure = "books"; head first->next. Chest = second; head next. Chest 2200 treasure "shells" third Oh – and let’s not forget 3700 to free our treasure next. Chest chests when we’re done with them! 3700 treasure "cash" next. Chest second->treasure = "shells"; second->next. Chest = third; third->treasure = "cash"; When we encounter third->next. Chest = nullptr; a nullptr } next. Chest pointer whose delete head; value is nullptr, this delete second; indicates delete third; we’re at the end.

30 Linked Lists Ok, it’s time to start using the right Computer Science terms.

30 Linked Lists Ok, it’s time to start using the right Computer Science terms. Instead of calling them “chests", let’s call each item in the linked list a “Node”. And instead of calling the value held in a node treasure, let’s call it “value”. And, instead of calling the linking pointer next. Chest, let’s call it “next”. Finally, there’s no reason a Node only needs to hold a single value! Chest// student node struct Node struct {{ treasure; string value; int student. ID; string Chest**name; next. Chest; Node next. Chest; next; }; int phone. Number; float gpa; int main(void) {{ Node *next; Node Chest *head, *second, *third; }; head = new Chest; Node; second = new Chest; Node; third = new Chest; Node; head->value = "books"; head->treasure = "books"; head->next. Chest head->next = second; second->value = "shells"; second->treasure = "shells"; second->next. Chest second->next = third; third->value = "cash"; third->treasure = "cash"; third->next. Chest third->next = nullptr; delete head; delete second; delete third; }}

31 Linked Note: The Lists delete command doesn’t kill the pointer… Before we continue,

31 Linked Note: The Lists delete command doesn’t kill the pointer… Before we continue, here’s a short recap on what we’ve learned: To allocate new nodes: Node *p = new Node; Node *q = new Node; To change/access a node p’s value: p->value = “blah”; cout << p->value; To make node p link to another node that’s at address q: p->next = q; To get the address of the node after p: Node *r = p->next; To make node q a “terminal” node: nullptr q->next = nullptr; struct Nodeit kills what the { pointer points to! string value; p 8000 Node * next; value blah 8000 }; r next 4000 int main(void) { To link Node *head, *second, node *third; p… q 4000 head = new Node; second = new Node; value to node third = q. new Node; next head->value = "books"; head->next = second; second->value = "shells"; To free= your second->next third; nodes: delete p; third->value = "cash"; delete q; third->next = nullptr; delete head; delete second; delete third; } 4000

32 Linked Lists Normally, we don’t create our linked list all at once in

32 Linked Lists Normally, we don’t create our linked list all at once in a single function. After all, some linked hold Welists normally millions of items! That fit! don’twouldn’t create our linked list all at once like this. Instead, we create a dedicated class (an ADT) to hold our linked list… And then add a bunch of member functions to add new items (one at a time), process the items, delete items, etc. OK, so let’s see our new class. struct Node { string value; Node * next; }; int main(void) { Node *head, *second, *third; head = new Node; second = new Node; third = new Node; head->value = "books"; head->next = second; second->value = "shells"; second->next = third; third->value = "cash"; third->next = nullptr; delete head; delete second; delete third; }

33 A Linked List Class! First, in the simplest type of linked list class,

33 A Linked List Class! First, in the simplest type of linked list class, the only member variable we need is a head pointer. Why? Given just the head pointer, we can follow the links to every node in the list. And since we can find all the nodes, we can also link in new ones, delete them, etc. . head 5000 value This is all our class needs to hold! "books" 5000 next 2200 value "shells" next 3700 value "cash" next nullptr 2200 3700 struct Node { string value; class Linked. List Node *next; { }; public: int main(void) { Node *head, *second, *third; head = new Node; second = new Node; third = new Node; head->value = "books"; head->next = second; second->value = Ok, "shells"; so let’s add second->next = third; a head pointer to our class. third->value = "cash"; third->next = nullptr; delete head; private: delete second; delete Node third; *head; 5000 } };

34 A Linked List Class! Alright, now what methods should our linked list class

34 A Linked List Class! Alright, now what methods should our linked list class have? We need a constructor to create an empty list… And methods to add new items… And a method to delete items… And a method to find if an item is in the list… And a method to print all the items… And finally, we need a destructor to free all of our nodes! class Linked. List Node *next; { public: int main(void) { Linked. List() { … } void add. To. Front(string v) { … } Chest *head, *second, *third; void add. To. Rear(string v) { … } head = new Chest; void delete. Item(string v) { … } second = new Chest; bool=find. Item(string v) { … } third new Chest; void print. Items() { … } head->treasure = "books"; ~Linked. List() { … } head->next. Chest = second; second->treasure = "shells"; second->next. Chest = third; third->treasure = "cash"; third->next. Chest = nullptr; Let’s consider these one at a time! private: Node *head; } };

35 Linked List Constructor OK, so what should our constructor do? Well, we’ll want

35 Linked List Constructor OK, so what should our constructor do? Well, we’ll want it to create an “empty” linked list – one with no items. But how do we create an empty list? Well, earlier I showed you how we marked the last node in a linked list… We set its next value to nullptr. head 5000 class Linked. List { public: Linked. List() { … } {void add. To. Front(string v) { … } void add. To. Rear(string v) { … } void delete. Item(string v) { … } } bool find. Item(string v) { … } …void print. Items() { … } ~Linked. List() { … } value "books" 5000 next 2200 value "shells" 2200 ere h t at h next 3700 t des tes o a n c i e… any Ind nprivate: n t ’ o s 3700 are thi value "cash" g n i w. Node *head; o l l o next nullptr f };

36 Linked List Constructor So, following this logic… We can create an empty linked

36 Linked List Constructor So, following this logic… We can create an empty linked list by setting our head pointer to nullptr! class Linked. List { public: Linked. List() { … } {void add. To. Front(string v) { … } void add. To. Rear(string v) { … } head = nullptr; void delete. Item(string v) { … } } bool find. Item(string v) { … } …void print. Items() { … } ~Linked. List() { … } OK, next let’s learn how to print the items in our list! head nullptr 5000 ith w r te n i o p lptr d l a u e n t”! A h lue of s i l ty p a va value m “e "books" 5000 s n mea next 2200 value "shells" 2200 next 3700 value "cash" 3700 next nullptr private: Node *head; };

37 Printing the Items in a Linked List So let’s assume we’ve used our

37 Printing the Items in a Linked List So let’s assume we’ve used our class to create a linked list and add some items… How do we go about printing the items in the list? class Linked. List { public: Linked. List() { … } void add. To. Front(string v) { … } void add. To. Rear(string v) { … } void delete. Item(string v) { … } bool find. Item(string v) { … } void print. Items() { … } ~Linked. List() { … } int main() { Linked. List my. List; // code to add nodes } my. List. print. Items(); head nullptr 2000 value "books" 2000 next 1200 value "shells" 1200 next 3700 value "cash" 3700 next nullptr private: Node *head; };

38 Printing the Items in a Linked List So let’s assume we’ve used our

38 Printing the Items in a Linked List So let’s assume we’ve used our class to create a linked list and add some items… How do we go about printing the items in the list? class Linked. List { public: Linked. List() { … } { void add. To. Front(string v) { … } void add. To. Rear(string v) { … } void delete. Item(string v) { … } bool find. Item(string v) { … } void print. Items() { … } ~Linked. List() { … } int main() { Linked. List my. List; // code to add nodes } my. List. print. Items(); head 2000 value "books" 2000 next 1200 value "shells" 1200 next 3700 value "cash" 3700 next nullptr } private: Node *head; };

39 Printing the Items in a Linked List But what kind of First of

39 Printing the Items in a Linked List But what kind of First of all, we don’t even variable should we use? As with any loop, we’re know how many items our OK, so our goal is to loop through each class Linked. List An integer? going toout need to use a { list has… of the nodes and print their Now let’s just variable tonode iterate. public: values, starting with the use a loop to pointed to by “head”… void print. Items() cycle through Well, we know that our { the nodes! head pointer Hmmm. contains the int i; *p; // use this to loop? Node address of thehelp! top node… That doesn’t p = head; // p points to 1 st node for (i=0; i<? ? ? ; i++) while ( p points to a valid node ) {{ … } print the value in the node If. Ah! we want towe loop through Maybe use p = address of theshould next node the nodes from top to a Node pointer instead! }bottom, we need to start by } And pointing p atour thenodes top node! second, are scattered randomly But how? throughout memory! So let’s just set p equal to it! head 2000 p value "books" 2000 next 1200 value "shells" 1200 next 3700 value "cash" 3700 next nullptr We need to find them one at private: time to print them. Node a*head; };

40 Printing the Items in a Linked List And finally, how do we OK,

40 Printing the Items in a Linked List And finally, how do we OK, so our goal is to loop through each class Linked. List advance p so it points to the { First, can we determine of the nodes and print outhow their next node in the list? public: trace if the p let’s points at a valid node? values, starting. Alright, with node through our loop! pointed to by “head”… print. Items() OK, and how do we print outvoid It’s easy, but let’s leave this { the value for in the node? a bit later. Node *p; p = head; // p points to 1 st node Be careful! This one’s easy! So if p points totoa move node, You can’t use p++ forward in athe linked list! we can find address while ( p points to a valid node ) { theuse following node in Youof must the next pointer! print<<the value in node cout p->value << the endl; p->next. head 2000 value "books" 2000 next 1200 value "shells" 1200 p 2000 next 3700 value "cash" 3700 next nullptr p->next; of the next node p = address } } Well, each node holds the location of the following node in its private: next variable. Node *head; };

41 Printing the Items in a Linked List And there’s our complete printing loop!

41 Printing the Items in a Linked List And there’s our complete printing loop! So this answers our question! Any time we iterate through one or more Iflike p’s value nullptr, NOT point nodes this, isit’s calledit adoes “traversal”. When we use the condition: whilep (p != points nullptr)to {nullptr. …} now p. Whoa! points p points to the to “cash” the “books” node p. Well, points to the “shells” node class Linked. List thenode loop process EVERY at will location at location 3700. 2000. node 1200. { That’s notand a valid in the list onlynode stop location! once it’s public: It’s certainly valid. certainly gone. It’s PAST the endvalid. of the list. void print. Items() { Node *p; p = head; // p points to 1 st node to a valid node. Otherwise it does. Alright, now let’s learn how to add nodes to our list! This is a linked list traversal! to a valid node ) != nullptr while ( pppoints { print<<the value in node cout p->value << the endl; p->next; of the next node p = address head 2000 value "books" books 2000 next 1200 2000 shells 1200 value "shells" next 3700 p value "cash" cash 3700 next nullptr } } The next node is at location 1200. private: The next node is is Node *head; at at location 3700. nullptr. };

42 Adding an Item to a Linked List There are three places you can

42 Adding an Item to a Linked List There are three places you can class Linked. List insert a new item linked Well, into firsta we havelist: to allocate a { tolist hold our new value. at thenew top node of the at the end of the list Second, we middle need to put the new somewhere in the OK, soitem what’s intoour ouralgorithm? new node. public: Linked. List() { … } { void add. To. Front(string v) { … } Allocate a new node void add. To. Rear(string v) { … } void Putdelete. Item(string value v in the nodev) { … } bool find. Item(string v)the {…} Link the new node to void {…} oldprint. Items() top node ~Linked. List() { …pointer } Link the head to Then let’s top link our new node to our new node } the old top node in the list. The algorithm to insert at the top is the easiest to code and also runs the fastest. And finally let’s link our head These two steps pointer ourfirst, new node. Let’s see thistoone and add a must be in this “ruby” to the top of our list! order! head 8000 2200 value “ruby" 8000 ere next H 2200 value "shells" 2200 next 3700 … here w e m o Or s iddle m e h t in private: value "cash" 3700 e Node *head; next nullptr Her };

43 Adding an Item to the Front Next, we want to link our new

43 Adding an Item to the Front Next, we want to link our new node to the current node in the list. OK, now let’s replace ourtop psuedo-code with valid we C++just code. Finally, update our head pointer so it holds the address of And as you can see, our new node has our new top node! been added at the top! class Linked. List { public: void add. To. Front(string v) Linked. List() {…} { Node *p; a new node Allocate void v) { … } p =add. To. Rear(string new Node; void delete. Item(string v)node {…} p->value put v in Put value=vv; in// the node bool find. Item(string v)the {…} Link the new node to p->next = head; { … } void oldprint. Items() top node ~Linked. List() { …pointer } Link the to head = p; head our new top node } OK, pnow we just place item v Fortunately, our variable (e. g. , “ruby”) our new node. holds the We’ve address of ourinto already seen how to do this. That’s easy! new node… To do that, we need atotemporary set Let’s define pointer p->next equal to use the address of and new command to the top node in allocate the existing list. node. our new p 8000 head 2200 value “ruby" 8000 next … value "shells" 2200 Fortunately, the head next variable holds the address of the current top node! value 3700 "cash" next nullptr 3700 private: Node *head; };

44 Adding an Item to the Front OK, but will this same algorithm work

44 Adding an Item to the Front OK, but will this same algorithm work if the Linked List is empty? class Linked. List { public: Let’s see! void add. To. Front(string v) Linked. List() {…} { Node *p; p = new Node; p->value = v; // put v in node Pretty cool – the same algorithm works whether the list is empty or not! p->next = head; p 8000 head nullptr 8000 “ruby" Our value list has no 2200 next It’s nodes! empty! head = p; 8000 } … value "shells" 2200 3700 Alright, now let’snext see how to add a node to the rear of a list! value "cash" 3700 next nullptr private: Node *head; };

45 Adding an Item to the Rear Alright, next let’s look at how to

45 Adding an Item to the Rear Alright, next let’s look at how to append an item at the end of a list… There actually two cases to consider: class Linked. List { public: Linked. List() { … } { void add. To. Front(string v) { … } void add. To. Rear(string v) { … } void delete. Item(string v) { … } bool find. Item(string v) { … } void print. Items() { … } ~Linked. List() { … } Case #1: The existing list is totally empty! head nullptr Case We’ll #1: add the very first node The list has right here! no nodes! Case #2: The existing list has one or more nodes… head 8800 value “ruby" 8000 next 2200 value "shells" 2200 We’ll add our new node here… next nullptr Case #2: The list already has some nodes! private: } Node *head; … };

46 Adding an Item to the Rear Well, as we learned, in an empty

46 Adding an Item to the Rear Well, as we learned, in an empty linked Alright, let’s consider Casehas #1 a first… list, the head value of nullptr. class Linked. List { It’s much easier! head nullptr 2200 public: “ruby" value Is the same as adding Adding a node to the top nullptr the next end of an empty list! Duh! empty list… void add. To. Rear(string v) { OK, so how do we determine if our linked list is is easy, empty? And this one we just call our add. To. Front() function! So how do you add a new node to the end of an empty linked list? In fact, it’s the same as adding a new node to the front of an empty linked list. Which we just learned two minutes ago! After all, in both cases we’re adding a node right at the top of the linked list. } }; . . . if our linked list is empty then (head == nullptr) use add. To. Front(v); our add. To. Front() // easy!!! code

47 Adding an Item to the Rear Alright, let’s consider Case #2 next: It’s

47 Adding an Item to the Rear Alright, let’s consider Case #2 next: It’s more complex… Here we want to add an item to the end of a linked list that already has nodes. class Linked. List { public: void add. To. Rear(string v) { We have to traverse down the too linksbad. . . until we findadd the Well that doesn’t look Let’s an “i. Pad” to current our list. last node! OK, so what’s our algorithm? head 8000 p value “ruby" next 2200 Finally, we set our new next 3700 node’s next pointer to value "cash" 3700 nullptr. next nullptr 160 Notice that p doesn’t traverse past the last node. . . p points at it! { 8000 value "shells" 2200 value “i. Pad" next nullptr 160 if (head == nullptr) add. To. Front(v); // easy!!! else Use a temp variable to traverse to the current last node of the list Allocate a new node Well, in order to add value v in the node a new node. Put here… Link the current last node to our new node Then we want to Link the last node to nullptr allocate a new node } We want to in add and itsour value… Next, want to link } fillwe new item right here! the. . . current last node }; to the new node.

48 Adding an Item to the Rear OK, let’s see the C++ code now!

48 Adding an Item to the Rear OK, let’s see the C++ code now! So what should our traversal Next. But we the want to traverse next untilpointer p points in directly the codeatlook like? the last node… earlier nodes is NOT nullptr! Well, as in our print. Items() method, we’ll use a temp variable to follow the links, starting at the head node. head value “ruby" } } { So we want to keep looping public: So what C++ code do we write while p->next is not nullptr. void hereadd. To. Rear(string to ensure that ourv)loop {stops when p points right at Theifmoment p->next is nullptr, (head nullptr) the == last node? p points at the last// node! add. To. Front(v); easy!!! else { 8000 void print. Items() next 2200 { 8000 Node *p; p value "shells" 2200 p = head; while (p != nullptr)next 3700 { class Linked. List cout << p->value << endl; "cash" 3700 p = p->next; next nullptr Node Use a *p; temp variable to p = head; to // the startcurrent at top node traverse p->next != list nullptr ) last node of at the while(p isn’t the last node) p = p->next; Allocate a new node Put value v in the node Link the current last node We want to Well, stop a hint: to ourhere’s new node looping when p the last node to nullptr Link } points Notice at this node the next pointer in that }. . . the last node is nullptr. };

49 Adding an Item to the Rear OK, let’s see the C++ code now!

49 Adding an Item to the Rear OK, let’s see the C++ code now! Alright, let’s finish up our function! class Linked. List { public: Again, p->next is add. To. Rear(string OK, well so far, void v) is Oooh, p->next OK, let’s see our C++ { not yetisnullptr! p->next clearly finally equal to nullptr! loop in action! not nullptr! if (head == nullptr) add. To. Front(v); // easy!!! else { head 8000 p 8000 value “ruby" 8000 next 2200 value "shells" 2200 next 3700 value "cash" 3700 next nullptr And notice that p points directly at our last node! } . . . }; } Node *p; p = head; // start at top node != nullptr ) while(pp->next isn’t at the last node) p = p->next; Allocate a new node Put value v in the node Link the current last node to our new node Link the last node to nullptr

50 Adding an Item to the Rear OK, let’s see the C++ code now!

50 Adding an Item to the Rear OK, let’s see the C++ code now! Alright, let’s finish up our function! head 8000 p 3700 n T new o our nod e! 160 class. When Linked. List we use the condition: { How do we allocate a new That’s easy! into Now node? let’s put our value Now weour need link our last newtonode… Finally, let’s terminate the node to our new node… linked list by setting the last 8000 “ruby" to node’s value next pointer nullptr. next 2200 When you get to the 2200 line after the value "shells" next 3700 loop, p points at the last node! value "cash" 3700 next nullptr W value “i. Pad" next nullptr while (p->next != nullptr) { … } public: the loop continues until p points at void the add. To. Rear(string very last node of thev)list. { if (head == nullptr) add. To. Front(v); // easy!!! else { e wa } this nt to }lin k 160 poin ter. . . … }; Node *p; p = head; // start at top node != nullptr ) while(pp->next isn’t at the last node) p = p->next; Node *n a= new node Node; Allocate n->value Put value=vv; in the node p->next n; Link the=current last node to our new node n->next nullptr; Link the =last node to nullptr

51 Not at the top, not at the bottom… In some cases, we won’t

51 Not at the top, not at the bottom… In some cases, we won’t always want to just add our node to the top or bottom of the list… Why? Here’s the basic algorithm: Well, what if we have to maintain an alphabetized linked list, or we want to allow the user to pick the spot to put each item? In these cases, we can’t just add new items at the top or bottom… void Add. Item(string new. Item) { if (our list is totally empty) Just use our add. To. Front() method to add the new node head nullptr 600 value “bat” 600 next nullptr }

52 Not at the top, not at the bottom… For instance, let’s say we

52 Not at the top, not at the bottom… For instance, let’s say we have an alphabetized list… In this case, our add. To. Front() and wealgorithm want to insert an item will add thethat’s node smaller to the than the restspot of the in the list… in items the list as well! Here’s theright basic algorithm: bat belong s here, above cat. value next “bat” 600 1000 void Add. Item(string new. Item) { if (our list is totally empty) Just use our add. To. Front() method to add the new node else if (our new node belongs at the very top of the list) Just use our add. To. Front() method to add the new node } head 1000 600 value “cat” 1000 value “dog” 1400 next value 800 “rat” 800 next nullptr

53 Not at the top, not at the bottom… Second we link our above

53 Not at the top, not at the bottom… Second we link our above node to our new node. p For instance, we’re inserting an item Here’s the basic algorithm: First we link our new node to like “fly” that belongs in the middle of after it. the node an alphabetized void Add. Item(string new. Item)list… { Once found the node directly if (our list we’ve is totally empty) Just use our add. To. Front() add the new node above where we want to method add ourtonew head 1000 value “cat” 1000 value “dog” 1400 next 1400 800 next 600 fly belongs here, value “fly” node, belongs we can… next else if (our new node at the very top of thedog list)and rat. between 600 Just use our add. To. Front() method to add the new node else // new node belongs somewhere in the middle of the list { Use a traversal loop to find the node just ABOVE where you want to insert our new item Allocate and fill our new node with the item Link the new node into the list right after the ABOVE node } } value “rat” 800 next nullptr

54 Let’s Convert it to C++ Code This one is easy… We already did

54 Let’s Convert it to C++ Code This one is easy… We already did the head 1000 The code you write here depends on same thing in our Add. To. Rear() method. We the nature of your list… Is it to want void Add. Item(string new. Item) p 1400 alphabetized? Is it ordered set by 1000 { “cat” student ID#? valuep->next if (our (headlist == is nullptr) totally empty) Add. To. Front(new. Item); Just use our add. To. Front() method to add the new node next 1400 … Similarly, your traversal code 1400 new node belongs at the very top of the else if ((our /* decide if the new item belongs at the toplist) */ ) value “dog” the address of the willtodepend on your list latest Just use our add. To. Front() method to how add new node Add. To. Front(new. Item); 600 next 800 ourisnew node. organized… want of an the if-statement to else // new node belongs somewhere in. You’ll the middle list “fly”it 600 value { break out of the loop when We want to set next Node *p = head; // start with top node finds the node just above the Use a traversal This loop to find the node just ABOVE where latest->next… one’s easy – we’ve while (p->next != nullptr) you want to insert your new item insertion point! already learned how to the address of and fill Iinwant a new if (/* p pointsallocate just above where toto insert my item */) variable. break; // break out the loop! This one is anode bit of more complex…the node below… Second, we want to link the p = p->next; // move downour onenew node First we want to link node above our insertion point } to the node below our new Node *latest = newto. Node; // node alloc and fill our new node { } } Allocate and fill your new node with the item latest->value = new. Item; latest->next p->next; // link new node tothe the. ABOVE node below Link the new=node into the list right after node p->next = latest; // link node above to our new node value “rat” 800 next nullptr These two lines must be in this order!

55 Let’s Convert it to C++ Code head 1000 A new item belongs at

55 Let’s Convert it to C++ Code head 1000 A new item belongs at Finally, let’s fill in blanks to convert This line we the stop theensures top of the list if when our we’ve reachedthan the into that it isfunction smaller the one 1000 “bat” void Add. Item(string new. Item) value “cat” 1000 last node in current the in list. alphabetical { list’s top item. “cat” adds items order! value 1400 next This line checks if if (head == nullptr) 1400 1000 next“cat” If p->next == nullptr, p-> value Let’s check for this! new item Add. To. Front(new. Item); the it means thatshould our new 1400 p-> next be inserted between “rat” value … item is bigger than else if ( /*new. Item decide if the new the item)current belongsnode at the top“dog” */ ) < head->value and “yak” next nullptr every item in the list! Add. To. Front(new. Item); the node below it… “rat” 1400 “yak”should find In this case we addtraversal our Our updated code The if-clause would be true else // new node belongs somewhere in the middle of the list next But false for “yak”, since it item after the last node. { value for “dog” since it fits between just the right spot for our new item. comes after “rat” and “cat”. house *p = head; // start with node “cat”first and “rat”! … while (p->next != nullptr) { new. Item >= just p->value &&where new. Item <= p->next->value if ((/* p points above I want to insert my )item */) break; // break out of the loop! } } } p = p->next; // move down one node Node *latest = new Node; // alloc and fill our new node latest->value = new. Item; latest->next = p->next; // link new node to node below p->next = latest; // link above node to our new node

56 Deleting an Item in a Linked List When deleting an item from a

56 Deleting an Item in a Linked List When deleting an item from a linked list, there are two different cases to consider: Case #1: You’re deleting the first node. class Linked. List { public: Linked. List() { … } { void add. To. Front(string v) { … } void add. To. Rear(string v) { … } void delete. Item(string v) { … } bool find. Item(string v) { … } void print. Items() { … } ~Linked. List() { … } Case #2: You’re deleting an interior node or the last node. Let’s consider Case #1 first… head 1000 We want to delete the item in the first node… We want to delete the item in an interior node… value “cat” 1000 value “dog” 1400 next value or the last node. 800 “rat” 800 next nullptr } private: … Node *head; };

57 Deleting an Item in a Linked List Well, first we need to make

57 Deleting an Item in a Linked List Well, first we need to make Ok, let’s consider Case #1… deleting sure the list isn’t empty!!! topour item in a list. Then we the update head If. Next it is we empty, needthere’s to check if the OK, so nothing what’s our algorithm? pointer… tofirst delete – so we just return! node holds the our itemcat. we Let’s kill so it points toremove. the node want to after our target node. class Linked. List { public: void delete. Item(string v) { If the list’s empty then return If the first node holds the item we wish to delete then { kill. Me = address of top node head nullptr 1000 kill. Me X Finally, let’s return once 1000 we’re done! value “cat” Update head to point to the second node in the list Delete our target node 1400 next 1400 value Now If so, we wedelete createour a targetpointer node… to temporary remember where our using our kill. Me pointer! target node is located. next value “dog” 1400 } 800 “rat” 800 } … next nullptr }; Return – we’re done

58 Deleting an Item in a Linked List OK, let’s see the C++ code

58 Deleting an Item in a Linked List OK, let’s see the C++ code now! Now we can easily delete our node! if our OK, so how dotarget we determine linked list is our empty? Nownow let’show update head pointer Next, do we determine if so it points to the second node. the first node holds the value we want to delete? Now let’s create a temporary Let’s pointer copy it and intoset its value to the head 1000 our head pointer. top node’s address. kill. Me Compares this value “cat” 1000 value… next 1400 n i und o f be next! n a > c value “dog” 1400 e kill. M next 800 value “rat” 800 next nullptr class Linked. List { public: against the input parameter. “cat” void delete. Item(string v) { If if (head the list’s == nullptr) empty then return; return If the first node holds the we wish to then ifitem (head->value ==delete v) { kill. Me*kill. Me = address of top node Node = head; Update head to point to the head = kill. Me->next; second node in the list delete Delete kill. Me; our target node The second return; – we’re done Return node’s address… } } Finally, let’s add our return … statement. };

59 Deleting an Item in a Linked List Alright, let’s consider Case #2 next

59 Deleting an Item in a Linked List Alright, let’s consider Case #2 next – unfortunately it’s more complex… class Linked. List { public: Let’s kill our “rat” node! “rat” void delete. Item(string v) { … // the code we just wrote OK, so what’s our algorithm? Next we need to check if we Why the node above? our target node… even found Well, we need. Iftoso, stop we can proceed! one node above so we can relink around our target node! value “cat” 1000 head 1000 next 1400 p value “dog” 1400 next 3000 800 kill. Me. Let’s kill this node! Finally, let’s delete our target node! value next “rat” 800 3000 name “yak” 3000 next nullptr Use a temp pointer to traverse down to the node above the one we want to delete… Ok, now let’s relink our node above the target… First we need to traverse to the node below the target! down the list… If we found our target node p now pointsuntil just we above find the node above { kill. Me = addr target node our target node! the one we of want to delete. Link the node above to the node below Ok, now create another Delete ourlet’s target node } temp pointer to remember } where our target node is. … };

60 Deleting an Item in a Linked List OK, let’s see the C++ code

60 Deleting an Item in a Linked List OK, let’s see the C++ code now! As before, let’s use one of our traversal loops. p will start by pointing at our head node… class Linked. List andeach willis iterate through p->next notwe nullptr, so For node { every node in thenode list… visit through p… there is a valid public: “rat” following this one! p->next->value is “dog” “rat” –– v) this p->next->value is this void delete. Item(string to our value {isisequal not equal totarget our target … // the code we justout! wrote of “rat”! So we“rat”. break value of Use temp pointer to traverse Nodea *p = head; down the node above the while to (p != nullptr) {one we want to delete… if ( p->next != nullptr && and we break out of our loop. p->next->value == v ) 1000 value “cat” head 1000 break; // p pts to node above next 1400 If p>next p = p->next; p } is not n ullptr … we found our target node If 1400 value If so, then p points to the node above our target… sa i e r the de n e th lid no e p! va g nod win o l l fo next value next “dog” { 800 “rat” 800 3000 name “yak” 3000 next nullptr }; kill. Me = addr of target node Link the node above to Firstbelow we check whether the node there a node following If. Delete there is aistarget node following p… our node the one pointed to by p. } then we check to see if that } … next node holds our to-bedeleted value.

61 If we all the way through Deleting an Item intraversed a Linked List

61 If we all the way through Deleting an Item intraversed a Linked List the list and didn’t find our value… OK, let’s see the C++ code now! class then p will be equal to nullptr. And believe it or not, this same code works when the target node is the last indid thefind list!our target Butone if we { public: “rat” void delete. Item(string v) { … // the code we just wrote value, then p will point to the node above it, and NOT be nullptr! Node *p = head; while (p != nullptr) Let’s check for this case! Let’s remember where our target node is located using a temporary pointer… value “cat” 1000 head 1000 { p->next != link nullptr Now want to the && if (we p->next->value == v ) node above the target… break; // p pts to node above p = p->next; next 1400 p 1400 Finally, we can use the delete command to free our node… value “dog” 1400 Note: The target node’s location can next 800 p is not be found here! nullptr value “rat” 800 since we kill. Me next 3000 found our target! That address can be found in kill. Me->next! name “yak” 3000 next nullptr Linked. List } if (p nullptr) // found our value! If we!= found our target node { } … }; } Node =*kill. Me p->next; kill. Me addr of=target node Link the node above to p->next = kill. Me->next; the node below delete kill. Me; Delete our target node to the node below the target.

62 Linked List Challenge Now it’s your turn! How would you write the find.

62 Linked List Challenge Now it’s your turn! How would you write the find. Item() method? class Linked. List { public: Linked. List() { … } { void add. To. Front(string v) { … } void add. To. Rear(string v) { … } void delete. Item(string v) { … } bool find. Item(string v) { … } void print. Items() { … } ~Linked. List() { … } It should return true if it can find the passed-in item, and false otherwise. int main() { } … Linked List my. Friends; my. Friends. add. To. Front(“David”); … } if (my. Friends. find. Item(“Carey”) == true) cout << “I’m so lucky!n”; private: Node *head; };

63 Destructing a Linked List OK, so how do we completely destruct a linked

63 Destructing a Linked List OK, so how do we completely destruct a linked list once we’re done with it? class Linked. List { public: Well, perhaps we can use something like our existing print. Items() code? Linked. List() { … } { void add. To. Front(string v) { … } void add. To. Rear(string v) { … } void delete. Item(string v) { … } bool find. Item(string v) { … } delete p; void print. Items() {…} ~Linked. List() { … } Let’s see what happens! head 1000 void print. Items() 1000 { value “cat” Node *p; next 1400 p = head; 1400 while (p != nullptr) value “dog” { next 800 cout << p->value << endl; p = p->next; value “rat” 800 } next nullptr } } … private: Node *head; };

64 Destructing a Linked List OK, so how do we completely destruct a linked

64 Destructing a Linked List OK, so how do we completely destruct a linked list once we’re done with it? class Linked. List { public: Well, perhaps we can use something like our existing print. Items() code? ~Linked. List()Houston… We have { a problem! Node *p; p = head; while (p != nullptr) { delete p; p = p->next; } } There is no p->next … Let’s see what happens! head 1000 p value “cat” 1000 1400 next 123456 In fact, there could be totally different data here now! value next value anymore! “dog” 1400 That memory is no longer ours to use! 800 “rat” 800 next nullptr private: Node *head; };

65 Destructing a Linked List class Linked. List OK, let’s fix it. { public:

65 Destructing a Linked List class Linked. List OK, let’s fix it. { public: ~Linked. List() { Node *p; p = head; while (p != nullptr) { delete p; = p->next; Node *n p = p->next; delete p; } p = n; } … Finally, we can now advance our p pointer to the next node by using So we before we Then can delete our temp variable! delete node our nodethe normally… pointed to by p… head 1000 p 1000 n 800 1400 Let’s save the location of the next node in a temporary variable! value “cat” 1000 value “dog” 1400 next value 800 “rat” 800 next nullptr private: Node *head; };

66 Linked Lists Aren’t Perfect! As you can already tell, linked lists aren’t perfect

66 Linked Lists Aren’t Perfect! As you can already tell, linked lists aren’t perfect either! First of all, they’re much more complex than arrays!!! Second, to access the kth item, I have to traverse down k-1 times from the head first! No instant access!!! And to add an item at the end of the list… I have to traverse through all N existing nodes first! Well, as it turns out, we can fix this last problem… Let’s see how!

67 Linked Lists and Tail Pointers head 1000 Since we have a head pointer…

67 Linked Lists and Tail Pointers head 1000 Since we have a head pointer… Why not maintain a “tail” pointer too? A tail pointer is a pointer that always points to the last node of the list! class Linked. List { public: Linked. List() {…} void add. To. Front(string v) {…} … private: Node *head; Node *tail; }; tail 800 value “cat” next 1400 1000 1400 value “emu” next 800 value “lemur” 800 next nullptr Using the tail pointer, we can add new items to the end of our list without traversing!

68 e. g. , don’t forget to update class Linked. List Adding an Item

68 e. g. , don’t forget to update class Linked. List Adding an Item to the Rear… { Guess what add. To. Front(), – we no longer public: need delete. Item(), this traversal etc… loop! With a Tail Pointer Wait! We no longer have a p variable void add. To. Rear(string v) tail that points atpointer the lastalready node! { The Let’s see how to update our add. To. Rear() to our last node! Let’s update the tail pointer if points (head == nullptr) function once our class has a tail pointer. But we do add. To. Front(v); have our tail variable, and Not with quite!the Now our tail address of the new it else points to the last node! pointer doesn’t pointinatthe ourlist. last node WARNING: You have to update all of your last node! Let’s fix it! { other methods to use the tail pointer Node *p; (e. g. , constructor, add. To. Front()) as. So well! is that it? ? ? p = head; // start at top node Are we done? ? ? while(p->next != nullptr) head p = p->next; value “ruby" 8000 Node *n = new Node; next 2200 tail n->value = v; 3700 p->next = n; tail->next = n; value "shells" 2200 n->next = nullptr; next 3700 tail = n; Already } value "cash" 3700 points to } our last next nullptr. . . node! private: n So let’s. Node just replace 160 *head; Guess value what? n“i. Pad" points to 160 “p” with Node“tail”! *tail; thenext last node now! nullptr };

Doubly-linked Lists 69 One of the downsides with our simple linked list is that

Doubly-linked Lists 69 One of the downsides with our simple linked list is that we can only travel in one direction… down! Given a pointer to a node, I can only find nodes below it! Wouldn’t it be nice if we could move both directions in a linked list? head 8000 We can! With a doubly-linked list! Except the top node’s A doubly-linked list has both prev nextpointer… and p previous pointers in every node: 2200 It has a value of nullptr, struct Node indicating that there are { no nodes above it. }; string value; Node * next; From p, I can find my shells Node * prev; and my cash, but have no way Each prev pointer points of getting back to my ruby! to the node above… value “ruby" 8000 next 2200 prev nullptr value "shells" 2200 next prev 3700 8000 value "cash" 3700 next nullptr prev 2200

Doubly-linked Lists 70 And, if I like, I can have a tail pointer too!

Doubly-linked Lists 70 And, if I like, I can have a tail pointer too! Now I can traverse in both directions! Node *p; p = head; while (p != nullptr) { cout << p->value; p = p->next; } Node *p; p = tail; while (p != nullptr) { cout << p->value; p = p->prev; } head 8000 tail 3700 8000 Of course, now we’re going to have to link up lots of additional pointers… But nothing comes free in life! p value “ruby" 8000 next 2200 prev nullptr value "shells" 2200 3700 prev 8000 next value "cash" 3700 next nullptr prev 2200

71 Doubly-linked Lists: What Changes? Every time we insert a new node or delete

71 Doubly-linked Lists: What Changes? Every time we insert a new node or delete an existing node, we must update three sets of pointers: 1. The new node’s next and previous pointers. 2. The previous node’s next pointer. 3. The following node’s previous pointer. Data Dave Next Prev Insert here! Head Ptr Data Bill Next Prev nullptr Previous Node Data Jane Next Prev Following Node Data Myk Next nullptr Prev And of course, we still have special cases if we insert or delete nodes at the top or the bottom of the list.

72 Linked List Cheat Sheet Given a pointer to a node: Node *ptr; NEVER

72 Linked List Cheat Sheet Given a pointer to a node: Node *ptr; NEVER access a node’s data until validating its pointer: if (ptr != nullptr) cout << ptr->value; struct Node { string value; }; Node *next; Node *prev; Notice that this check: To advance ptr to the next node/end of the list: ptr != nullptr Does our traversal meet this if (ptr != nullptr) ptr = ptr->next; To see if ptr points to the last node in a list: if (ptr != nullptr && ptr->next == nullptr) then-ptr-points-to-last-node; To get to the next node’s data: Ensures that ptr&&points to a if (ptr != nullptr ptr->next != valid nullptr)node… cout << ptr->next->value; before we access its “value” “next” here. To and get the head fields node’s data: if (head != nullptr) cout << head->value; To check if a list is empty: if (head == nullptr) cout << “List is empty”; requirement? NODE *ptr = head; while (ptr != nullptr) { cout << ptr->value; ptr = ptr->next; } To check if a pointer points to the first node in a list: if (ptr == head) cout << “ptr is first node”;

73 Linked Lists vs. Arrays Which is Faster? Winner: Array We can get to

73 Linked Lists vs. Arrays Which is Faster? Winner: Array We can get to any item in an array in 1 step. Getting to the 753 rd item in a linked We have to pass thru 752 other nodes to list or an array? reach the 753 rd node in a list! Which is Faster? Inserting a new item at the front of a linked list or at the front of an array? Which is faster? Removing an item from the middle of a linked list or the middle of an array? Which is easier to program? Which data structure will take less time to program and debug? Winner: Linked List We can insert a new item in a few steps! With an array, we’d have to shift all n items down first! Winner: Linked List Once we’ve found the item we want to delete, we can remove it in a few steps! With an array, we’d have to shift all the following items up one slot! Winner: Array Let’s face it – arrays are easier to use. So only use a linked list if you really have to!

74 Class Challenge Write a function called insert that accepts two NODE pointers as

74 Class Challenge Write a function called insert that accepts two NODE pointers as arguments: b 4 node: points to a node in a doubly-linked list newnode: points to a new node you want to insert When your function is called, it should insert newnode after b 4 node in the list, properly linking all nodes. (You may assume that a valid node follows b 4 node prior to insertion. ) struct NODE { string data; NODE *next, *prev; }; newnode Data Dave Next Prev b 4 node nullptr exists