1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion,...

74
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

Transcript of 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion,...

Page 1: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced 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

Page 2: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

2

The Assignment OperatorLast time we learned how to

construct a new class variable using the value of an existing variable.

int main(){

Circ foo(1,2,3); 

Circ bar(4,5,6);

bar = foo;}

Now lets learn how to set the value of an existing variable to the value of an another existing

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.

int main(){

Circ x(1,2,3); 

Circ y = x;}

Page 3: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

3

The Assignment Operator

int main(){

Circ foo(1,2,3); 

Circ bar(4,5,6);

bar = foo;}

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.

If you don’t define your own assignment operator…

Then C++ provides a default version that just copies each

of the members.

foo m_xm_y

m_rad

123

bar m_xm_y

m_rad

456

123

Lets see how to define our own assignment

operator.

Why isn’t bar’s copy constructor called?

Because bar was already constructed on the line

above!

The variable already exists and is already initialized!

Page 4: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

4

class Circ{public:Circ(float x, float y, float r){

m_x = x; m_y = y; m_rad = r;}

float GetArea(void){ return(3.14159*m_rad*m_rad);}

private:float m_x, m_y, m_rad;

}; 

void setMeEqualTo(const Circ &src){ m_x = src.m_x; m_y = src.m_y; m_rad = src.m_rad;}

The Assignment Operator The syntax for an assignment operator is

a bit confusing.So lets define a simpler

version first…

Here’s how we’d use our new function.

int main(){ Circ foo(1,2,3); 

Circ bar(4,5,6);

bar.setMeEqualTo(foo);

}// same as bar = foo;

bar

Hmmm.. This looks familiar, doesn’t it?

What does it remind you of?

class Circ{ ... void setMeEqualTo(const Circ &src) { m_x = src.m_x; m_y = src.m_y; m_rad = src.m_rad; } ...private: m_x m_y m_rad }

class Circ{ ... void setMeEqualTo(const Circ &src) { m_x = src.m_x; m_y = src.m_y; m_rad = src.m_rad; } ...private: m_x m_y m_rad }

1 2 31

5

2 3

When we’re done, bar is a perfect clone

of foo!

foo

4

6

Page 5: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

5

class Circ{public:Circ(float x, float y, float r){

m_x = x; m_y = y; m_rad = r;}

float GetArea(void){ return(3.14159*m_rad*m_rad);}

private:float m_x, m_y, m_rad;

}; 

The Assignment Operator

void setMeEqualTo{ m_x = src.m_x; m_y = src.m_y; m_rad = src.m_rad;

}

operator=

1. The function name is operator=

Now lets see what a real assignment operator

looks like.

2. The function return type is a reference to the class.

Circ &

3. The function returns *this when its done.

return(*this);

The const keyword guarantees that the source object (src) is not modified

during the copy.

You MUST pass a reference to the source object. This means you have to have

the & here!!!

(const Circ &src)

Page 6: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

6 The Assignment Operator

int main(){

Circ foo(1,2,3); 

Circ bar(4,5,6);

bar = foo;}

class Circ{public:Circ(float x, float y, float r){

m_x = x; m_y = y; m_rad = r;}

float GetArea(void){ return(3.14159*m_rad*m_rad);}

private:float m_x, m_y, m_rad;

}; 

void Assign (const Circ &src){ m_x = src.m_x; m_y = src.m_y; m_rad = src.m_rad;

}

operator=Circ &

return(*this);

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 }

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 }

bar

4

1 2 31

65

2 3

C++: “Ooh, the programmer is using the equal sign to set

bar equal to foo.”C++: “Since the programmer defined

an assignment operator for Circles, I’ll

use it to do the assignment.”

bar.operator=(foo);

Another way to read:bar = foo;

is:bar.operator=(foo);

i.e., we’re calling bar’s operator= member

function!

So, to summarize…

If you’ve defined an operator= function in a

class…

Then any time you use the equal sign to set an

existing variable equal to another…

C++ will call the operator= function of your target variable and pass in

the source variable!

Page 7: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

7

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 printSquares() { for (int j=0;j<n;j++) cout << m_sq[j] << endl;

}private:

int *m_sq, m_n;};

The Assignment Operator

Remember our updated Squares class…

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!

Lets see what happens if we use the

default assignment operator with it…

Page 8: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

8

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 printSquares() { for (int j=0;j<n;j++) cout << m_sq[j] << endl;

}private:

int *m_sq, m_n;};

The Assignment Operator

int main(){

Squares a(3); 

Squares b(4);

b = a;}

a m_n

m_sq

3000008000000080400000808800

149

b m_n

m_sq

4900

00000900000009040000090800000912

149

16

3800

// a’s d’tor is called, then b’s

Operating System, can you free the memory at

address 800 for me.

No sweat, homie. Consider it freed.

Operating System, can you free the memory at

address 800 for me.

You already asked me to do that! I can’t free

it twice!!!ERROR!!!!

Oh – and by the way, you never freed the memory at 900, you

know!

First a’s destructor is called.

Then b’s destructor is called.

Page 9: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

9

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 printSquares() { for (int j=0;j<n;j++) cout << m_sq[j] << endl;

}private:

int *m_sq, m_n;};

The Assignment Operator

int main(){

Squares a(3); 

Squares b(4);

b = a;}

a m_n

m_sq

3000008000000080400000808800

149

b m_n

m_sq

4900

00000900000009040000090800000912

149

16

3800

// a’s d’tor is called, then b’s

When we copy a’s members into b, we have 2 problems:

1. Our b variable forgets where it reserved its memory.

2. Both a and b point to the same memory.

When a is destructed, it frees the memory at

800.

But this memory is still being referred to by b! Utoh!

Finally, when b is destructed, it tries to free the memory at

800 – AGAIN!

But this memory was already freed by a!

And, b forgot where its original memory was, so it

forgets to free that too!

?

Page 10: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

10

The Assignment Operator

The assignment operator must:

1. Free all dynamic memory used by the target instance.

2. Re-allocate memory in the target instance to hold any member variables from the source instance.

3. Explicitly copy the contents of the source instance to the target instance.

Any time your class:

A. Allocates dynamic memoryB. Opens system resources (like opening a file)

You need to define your own assignment operator

Page 11: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

11

The Assignment Operator

General assignment operator syntax:

class SomeClass{ public:

SomeClass & operator=(const SomeClass &src) { // 1. Free all memory in the target instance // 2. Reallocate memory for the target instance

// 3. Copy data from src into the target instance // 4. Return a reference to the target instance }};

Don’t forget the const keyword!

Don’t forget the & symbol to make src a reference!

Page 12: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

12

The Assignment Operatorclass Squares{public: Squares(int n) { … } ~ Squares(){ delete[]m_sq; }

// assignment operator: Squares &operator=(const Squares &src) { delete [] m_sq; m_n = src.m_n; m_sq = new int[m_n]; for (int j=0;j<m_n;j++) m_sq[j] = src.m_sq[j]; return(*this); }   void printSquares() { ... }

private:int *m_sq, m_n;

};

int main(){ Squares a(3); Squares b(4);  b = a; }

a m_n

m_sq

3000800000804000808800

149

b m_n

m_sq

4900

000900000904000908000912

149

16

src

Operating System, I no longer need the memory

at location 900.

Ok, I’ll free that up for someone else to use.

3

OS: Can you reserve 12 bytes of memory for me?

Sure. Here’s 12 bytes of memory for you at

address 860. 000860000864000868

860

149

Page 13: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

13

The Assignment Operatorclass Squares{public: Squares(int n) { … } ~ Squares(){ delete[]m_sq; }

// assignment operator: Squares &operator=(const Squares &src) { delete [] m_sq; m_n = src.m_n; m_sq = new int[m_n]; for (int j=0;j<m_n;j++) m_sq[j] = src.m_sq[j]; return(*this); }   void printSquares() { ... }

private:int *m_sq, m_n;

};

int main(){ Squares a(3); Squares b(4);  b = a; }

a m_n

m_sq

3000800000804000808800

149

b m_n

m_sq

4900

3 000860000864000868

860

149

// a’s d’tor is called, then b’s

Operating System, I no longer need the memory

at location 800.

Ok, I’ll free that up for someone else to use.

Operating System, you can free the memory at

address 860.

Ok, I’ll free that for you.

… and everything is freed perfectly!

Page 14: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

14

The Assignment Operatorclass CSNerd{public: ...

CSNerd &operator=(const CSNerd &src) { m_numPCs = src.m_numPCs; m_hasMac = src.m_hasMac; return(*this); }  

private: int m_numPCs; bool m_hasMac;};

Answer: So we can do multiple

assignments in the samestatement, like this…

int main(){ CSNerd sam(5,false); CSNerd ted(10,false); CSNerd tim(3,true);

tim = ted = sam;}

Question: Why do we have return(*this) at the end of the assignment operator

function?

samclass CSNerd{ CSNerd &operator= (const CSNerd &src) { m_numPCs = src.m_numPCs; m_hasMac = src.m_hasMac; return(*this); }  

m_numPCs m_hasMac};

ted class CSNerd{ CSNerd &operator= (const CSNerd &src) { m_numPCs = src.m_numPCs; m_hasMac = src.m_hasMac; return(*this); }  

m_numPCs m_hasMac};

tim class CSNerd{ CSNerd &operator= (const CSNerd &src) { m_numPCs = src.m_numPCs; m_hasMac = src.m_hasMac; return(*this); }  

m_numPCs m_hasMac}; All assignment

is performed right-to-left…

First we call ted’s assignment operator to

assign him to sam.

5 false

10 false

3 true

5 false

“this” is a special C++ pointer variable that holds the address of

the current object (i.e., ted’s address in RAM)

So if “this” is a pointer to ted, then “*this” refers to the whole ted variable.

So this line returns the ted variable itself!

Strange huh? A member function of a

variable can return the variable itself!?!?

So the statement:“ted = sam” is

just replaced by the ted variable!

ted

Next, C++ sets tim equal to ted.

5 false

And this line returns the tim variable, so if we

wanted, we could do yet another assignment!

tim

So, to sum up…The assignment

operator returns “*this” so that there’s always a variable on the right hand side of the = for the next assignment.

bill =

Page 15: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

15

The Assignment OperatorOur assignment operator has

one problem with it… Can anyone guess what it is?

class Squares{public: ...

Squares &operator=(const Squares &src) { delete [] m_sq; m_n = src.m_n; m_sq = new int[m_n]; for (int j=0;j<m_n;j++) m_sq[j] = src.m_sq[j]; return(*this); }  

private:int *m_sq, m_n;

};

void f(Squares &x,Squares &y){

... x = y; }

int main(){

Squares a(3); f(a,a); }

a m_n

m_sq

3000800000804000808800

149

Hmm... What happens if we set a

to itself?

src

Operating System, you can free the memory

at address 800.

Ok, I’ll free that up for someone else to use.

3

OS: Can you reserve 12 bytes of memory for me?

Sure. Here’s 12 bytes of memory for you at

address 420.

000420000424000428

So what values are at location 420-

428??RANDOM ones!

420-521934

So now we copy the random values over

themselves!

// really a = a; !!!

“Aliasing” is when we use two different references/pointers to

refer to the same variable.It can cause unintended

problems!

Page 16: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

16

The Assignment OperatorThe fix:

Our assignment operator function can check to see if a variable is being assigned to itself, and if so, do

nothing…class Squares{ ... Squares &operator=(const Squares &src) {

delete [] m_sq; m_n = src.m_n; m_sq = new int[m_n]; for (int j=0;j<m_n;j++) m_sq[j] = src.m_sq[j]; return(*this); }   …};

And we’re done!

if (&src == this) return(*this); // do nothing

Page 17: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

17

Copy Constructor/ Assignment Review

Question: which of the following use the copy constructor and which use the assignment

operator? int main() // #1{ Squares a(4), b(3); b = a;} int main() // #2{ Squares c(5), d(c); Squares e = d;} 

// #3Squares func(void) { Squares g(15); return(g);} int main(){ Squares f = func();}

Page 18: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

18

Challenge Write an assignment

operator for our CSNerd Class:

struct Book{ string title; string author;};

class CSNerd{public: CSNerd(string name) { m_myBook = nullptr; m_myName = name; } void giveBook(string t, string a) { m_myBook = new Book; m_myBook->title = t; m_myBook->author = a; } ~CSNerd() { delete m_myBook; }private: Book *m_myBook; string m_myName;};

Page 19: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

19

Linked Lists

Page 20: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

20

Arrays are great… But…

Arrays are great when you need to store a fixed number of items…

int main(){

int array[100];

…}

But what if you don’t know how many items you’ll have ahead of

time?int main(){

// might have 10 items or 1M int array[1000000];

…}

Then you have to reserve enough slots for the largest possible case.

What

a w

aste

of sp

ace!

And what if you need to insert a new item in the middle of an

array?

AndrewBettyDavidElaineFrank

Zappa

names[0]

names[1]

names[2]

names[3]

names[4]

names[999998] names[999999]

Carey

We have to move every item below the insertion spot down by one!

And it’s just as slow if we wantto delete an item! Yuck!

int main(){

int numItems, *ptr;

cin >> numItems; ptr = new int[numItems];

}Even new/delete don’t really help!

Still requires us to know the size ahead of time!

It takes nearly

1M steps to add a

new item!

Page 21: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

21

So Arrays Aren’t Always Great

Hmm… Can we think of an approach from “real life” that

works better than a fixed-sized array?

What can we think of that:

allows you to store an arbitrary number of items

makes it fast to insert a new item in the middle

makes it fast to delete an item from the middle

How about organizing the items as we would in a Scavenger Hunt?

?Clue:

The first item is by the tree

Clue:

The next item is by the

house

Clue:

The next item is by the

tower

Clue:

This is the last item!

Using this approach we can store an arbitrary number of items!

There’s no fixed limit to the number of chests and clues we

can have!

The hunt starts with a

clue to the location of the first

chest…

Then each

chest holds

an item and

a clue to the

location of

the next chest.

Page 22: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

22

So Arrays Aren’t Always Great

Clue:

The first item is by the tree

Clue:

The next item is by the

house

Clue:

The next item is by the

tower

Clue:

This is the last item!

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:

Clue:

The next item is by the temple

Then we

update the

previous clue to

point to our new

chest!

First we copy the

previous clue to

our new chest.

The next item is by the

house

Page 23: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

23

So Arrays Aren’t Always Great

?Clue:

The first item is by the tree

Clue:

The next item is by the temple

Clue:

The next item is by the

tower

Clue:

This is the last item!

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 next item is by the

house

The next item is by the

tower

For instance, let’s remove this chest from the hunt…

Page 24: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

24

Ok, so in our Scavenger Hunt, we had:

So here’s the question… can we simulate a Scavenger Hunt with

a C++ data structure?

A C++ Scavenger Hunt?

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.

Clue:

The first item is by the tree

Clue:

The next item is by the

house

Why not? Let’s see how. Clue:

The next item is by the tower.

Page 25: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

25

struct Chest{ };

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”.

string treasure;

The location of the next chest – let’s represent that with a pointer variable.

Chest * nextChest;

A C++ Scavenger Hunt?

We can now define a Chest variable for each of the items in our scavenger

hunt!

Clue:

The first item is by the tree

Clue:

The next item is by the

house

Clue:

The next item is by the tower.

This line basically says that each Chest variable holds a

pointer… to another Chest variable.

Page 26: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

26

treasure“books”

nextChest 3400

Clue:

The next item is by the tower.

struct Chest{ };

Well, we can use a C++ struct to represent a Chest.

Chest *first; // pointer to our 1st chest

As we know, each Chest holds two things:

A treasure – let’s use a string variable to hold our treasure, e.g., “shells”.

string treasure;

The location of the next chest – let’s represent that with a pointer variable.

Chest * nextChest;

And we can define a pointer to point to the very first chest – our first clue!

A C++ Scavenger Hunt?

Clue:

The first item is by the tree

Clue:

The next item is by the

house

treasure“shells”

nextChest 1200

first

5000

We can now define a Chest variable for each of the items in our scavenger

hunt!

OK, let’s see the C++ version of a simplified scavenger hunt data

structure!

Page 27: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

A C++ Scavenger Hunt?struct Chest{ string treasure; };

Chest * nextChest;int main(void){ Chest *first; Chest chest1, chest2, chest3;

first = &chest1;

chest1.treasure = “books"; chest1.nextChest = &chest2;

chest2.treasure = “shells"; chest2.nextChest = &chest3;

chest3.treasure = “cash";

}

chest1treasure

nextChest

chest2 treasure

nextChest

“books"1000

10201020

chest3treasure

nextChest

1040

27

“shells"

1040 “cash"

We want to link up our first chest to the

second chest…

So we’ll get the address of the second chest…

first

1000

And update our first chest so it points to it…

This data structure is called a “linked

list.”

nullptr

chest3.nextChest = nullptr;

Finally, we’ll indicate that the third chest is the last in the scavenger

hunt.

We do this by setting its nextChest pointer to nullptr.

nullptr is a special C++ constant that means

“invalid pointer value.”

We call each item in the linked list a

“node.”

…should hold the address of the first

chest!

Our first pointer …

Why? Because each element in the list is

”linked” by a pointer to the next

element.

Page 28: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

28

Normally, we don’t use local variables to create our linked list.

Linked Lists

int main(void){ Chest *first; Chest chest1, chest2, chest3;

first = &chest1;

chest1.treasure = “books"; chest1.nextChest = &chest2;

chest2.treasure = “shells"; chest2.nextChest = &chest3;

chest3.treasure = “cash";

}

chest3.nextChest = nullptr;

struct Chest{ string treasure; };

Chest * nextChest;

Instead we use dynamically-allocated variables (and

pointers!).Chest *first, *second, *third;

first = new Chest;

first

second

third

“Hey OS, can you allocate 20 bytes for

me?”

OS: “Sure – I’ve reserved some memory for you at

location 5000.”

treasure

nextChest

5000

treasure

nextChest

2200

5000

second = new Chest;

“Hey OS, can you allocate 20 bytes for

me?”

OS: “Sure – I’ve reserved some memory for you at

location 2200.”

2200

third = new Chest;

treasure

nextChest

3700

“Hey OS, can you allocate 20 bytes for

me?”

OS: “Sure – I’ve reserved some memory for you at

location 3700.”

3700

Page 29: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

29

Linked Lists

int main(void){

}

struct Chest{ string treasure; };

Chest * nextChest;

Chest *first, *second, *third;

first = new Chest;

first

second

third

treasure

nextChest

5000

treasure

nextChest

2200

5000

second = new Chest;

2200

third = new Chest;

treasure

nextChest

3700

3700

OK, now let’s add cargo and link ‘em up!

first->treasure = "books";first->nextChest = second;

"books"

2200second->treasure = "shells";second->nextChest = third;

"shells"

3700third->treasure = "cash";

"cash"third->nextChest = nullptr;

nullptr

head

head

The pointer to the top item in the linked list is traditionally called the

“head pointer.”

head

headhead

Given just the head pointer, you can reach every element in the

list…

without using your other external pointers!

Again, in our last node, we’ll set its nextChest pointer to

nullptr.

This indicates that it’s the last item in the list.treasure

first->treasurenextChest

first->nextChest second

delete head;delete second;delete third;

Oh – and let’s not forget to free our

treasure chests when we’re done with them! When we encounter a

nextChest pointer whose value is nullptr, this indicates we’re at

the end.

Page 30: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

30 struct Chest{ string treasure; };

Chest * nextChest;

Chest *head, *second, *third;

head = new Chest;second = new Chest;third = new Chest;

head->treasure = "books";head->nextChest = second;

second->treasure = "shells";second->nextChest = third;

third->treasure = "cash";third->nextChest = nullptr;

int main(void){

}

delete head;delete second;delete third;

Instead of calling them “chests", let’s call each item in

the linked list a “Node”.

Linked Lists

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

And instead of calling the value held in a node

treasure, let’s call it “value”.

And, instead of calling the linking pointer nextChest, let’s call it

“next”.

struct Node{ string treasure; };

Node * nextChest;

Node *head, *second, *third;

head = new Node;second = new Node;third = new Node;

head->treasure = "books";head->nextChest = second;

second->treasure = "shells";second->nextChest = third;

third->treasure = "cash";third->nextChest = nullptr;

int main(void){

}

delete head;delete second;delete third;

struct Node{ string value; };

Node * nextChest;

Node *head, *second, *third;

head = new Node;second = new Node;third = new Node;

head->value = "books";head->nextChest = second;

second->value = "shells";second->nextChest = third;

third->value = "cash";third->nextChest = nullptr;

int main(void){

}

delete head;delete second;delete third;

struct Node{ string value; };

Node * next;

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;

int main(void){

}

delete head;delete second;delete third;

Finally, there’s no reason a Node only needs to hold a single value!

struct Node // student node{ int studentID; string name; int phoneNumber; float gpa;

Node *next; };

Page 31: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

31

Linked ListsBefore 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”;

To make node p link to another node that’s at address q:

p->next = q;

struct Node{ string value; };

Node * next;

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;

int main(void){

}

delete head;delete second;delete third;

value

next

8000

p 8000

value

next

4000

q 4000

cout << p->value;“blah”

blah

To link node p…

to node

q.

4000

To get the address of the node after p:

Node *r = p->next;

r 4000

To make node q a “terminal” node:

q->next = nullptr;nullptr

To free your nodes:

delete p;delete q;

Note: The delete command doesn’t kill

the pointer…

it kills what the pointer points to!

Page 32: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

32

After all, some linked lists hold millions of items! That wouldn’t fit!

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.

Linked Lists

Normally, we don’t create our linked list all at once in a single

function.

struct Node{ string value; };

Node * next;

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;

int main(void){

}

delete head;delete second;delete third;

We normally don’t create

our linked list all at once like

this.

Page 33: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

33

A Linked List Class!

int main(void){

}

struct Node{ string value; };

Node *next;

delete head;delete second;delete third;

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;

First, in the simplest type of linked list class, the only member variable

we need is a head pointer.

class LinkedList{

public:

private:

};Node *head;

Why? Given just the head pointer, we can follow the links to every node in the

list.

Ok, so let’s add a head

pointer to our class.

And since we can find all the nodes, we can also link in new ones, delete them,

etc..

value

next

5000

value

next

2200

5000

value

next

3700

"books"

"shells"

"cash"

nullptr

head

2200

3700

5000

This is all our class

needs to hold!

head

Page 34: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

34

A Linked List Class!

int main(void){

}

Node *next;

Chest *head, *second, *third;

head = new Chest;second = new Chest;third = new Chest;

head->treasure = "books";head->nextChest = second;

second->treasure = "shells";second->nextChest = third;

third->treasure = "cash";third->nextChest = nullptr;

class LinkedList{

public:

private:

};

Alright, now what methods should our linked list class have?

We need a constructor to create an empty list…

LinkedList() { … }

~LinkedList() { … }

And methods to add new items…void addToFront(string v) { … }void addToRear(string v) { … }

And a method to delete items… void deleteItem(string v) { … }

And a method to find if an item is in the list…

bool findItem(string v) { … }

And a method to print all the items…

void printItems() { … }

Node *head;

And finally, we need a destructor to free all of our nodes!

Let’s consider these one at a time!

Page 35: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

35

Linked List ConstructorOK, 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?

class LinkedList{

public:

private:

};Node *head;

LinkedList() { … }

~LinkedList() { … }

void addToFront(string v) { … }void addToRear(string v) { … }void deleteItem(string v) { … }bool findItem(string v) { … }void printItems() { … }

{

}

Well, earlier I showed you how we marked the last node in a linked list…

head

5000value

next

5000"books"

value

next

2200

valuenext

3700

"shells"

"cash"nullptr

2200

3700

Indicates that there

aren’t any nodes

following this one…

We set its next value to nullptr.

Page 36: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

36

value

next

5000"books"

value

next

2200

valuenext

3700

"shells"

"cash"nullptr

2200

3700

Linked List ConstructorSo, following this logic…

We can create an empty linked list by setting our head pointer to nullptr!

class LinkedList{

public:

private:

};Node *head;

LinkedList() { … }

~LinkedList() { … }

void addToFront(string v) { … }void addToRear(string v) { … }void deleteItem(string v) { … }bool findItem(string v) { … }void printItems() { … }

{

}

head = nullptr;

head

5000nullptr

A head pointer with

a value of nullptr

means “empty

list”!

OK, next let’s learn how to print the items in our list!

Page 37: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

37

head

So let’s assume we’ve used our class to create a linked list and add some

items…

2000valuenext

2000

valuenext

1200

valuenext

3700

"books"

"shells"

"cash"nullptr

1200

3700

Printing the Items in a Linked List

class LinkedList{

public:

private:

};Node *head;

~LinkedList() { … }

void addToFront(string v) { … }void addToRear(string v) { … }void deleteItem(string v) { … }bool findItem(string v) { … }void printItems() { … }

LinkedList() { … }

int main(){

}

LinkedList myList;

// code to add nodes

myList.printItems();

nullptr

How do we go about printing the items in the list?

Page 38: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

38

head2000

Printing the Items in a Linked List

class LinkedList{

public:

private:

};Node *head;

~LinkedList() { … }

void addToFront(string v) { … }void addToRear(string v) { … }void deleteItem(string v) { … }bool findItem(string v) { … }void printItems() { … }

LinkedList() { … }

int main(){

}

LinkedList myList;

// code to add nodes

myList.printItems();void printItems()

{

}valuenext

2000

valuenext

1200

valuenext

3700

"books"

"shells"

"cash"nullptr

1200

3700

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?

Page 39: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

39

Printing the Items in a Linked List

p

head 20002000

class LinkedList{

public:

private:

};Node *head;

{

}

void printItems()

OK, so our goal is to loop through each of the nodes and print out

their values, starting with the node pointed to by “head”…

But what kind of variable should we

use?

An integer?

int i; // use this to loop?

for (i=0;i<?????;i++){ …}

Ah! Maybe we should use a Node pointer

instead!

Node *p;p = head; // p points to 1st node

while ( ){

}

p points to a valid node

print the value in the node

p = address of the next node

As with any loop, we’re going to need to use a variable to

iterate.

Now let’s just use a loop to cycle through

the nodes!

If we want to loop through the nodes from top to

bottom, we need to start by pointing p at the top

node!

But how?

Well, we know that our head pointer contains the address of the top

node…

So let’s just set p equal to it!

valuenext

2000

valuenext

1200

valuenext

3700

"books"

"shells"

"cash"nullptr

1200

3700

First of all, we don’t even know how many

items our list has…

Hmmm. That doesn’t help!

And second, our nodes are scattered randomly

throughout memory!

We need to find them one at a time to print them.

Page 40: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

40

Printing the Items in a Linked List

p

head 2000

class LinkedList{

public:

private:

};Node *head;

{

}

void printItems()

OK, so our goal is to loop through each of the nodes and print out

their values, starting with the node pointed to by “head”…

Node *p;p = head; // p points to 1st node

while ( {

}

p points to a valid node

print the value in the node

p = address of the next node

valuenext

2000

valuenext

1200

valuenext

3700

"books"

"shells"

"cash"nullptr

1200

37002000

First, how can we determine if p points at a

valid node?

It’s easy, but let’s leave this for a bit later.

)

Well, each node holds the location of the

following node in its next variable.

cout << p->value << endl;

OK, and how do we print out the value in the node?

This one’s easy! So if p points to a

node, we can find the address of the

following node in p->next.

p->next;

And finally, how do we advance p so it points to the next node in the list?Alright, let’s trace

through our loop!

Be careful!You can’t use p++ to move

forward in a linked list!

You must use the next pointer!

Page 41: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

41

Printing the Items in a Linked List

p

head 2000

class LinkedList{

public:

private:

};Node *head;

{

}

void printItems()

Node *p;p = head; // p points to 1st node

while ( {

}

p points to a valid node

print the value in the node

p = address of the next node

valuenext

2000

valuenext

1200

valuenext

3700

"books"

"shells"

"cash"nullptr

1200

37002000

cout << p->value << endl;p->next;

Well, p points to the “books” node at location

2000.

It’s certainly valid.

books

The next node is at location 1200.

1200

p points to the “shells” node at location 1200.

It’s certainly valid.

shells

The next node is at location 3700.

3700

cash The next node is at location

nullptr.nullptr

p != nullptr )

And there’s our complete printing loop!

Any time we iterate through one or more nodes like this, it’s called a

“traversal”.

p points to the “cash” node at location 3700.

It’s certainly valid.

Whoa! p now points to nullptr.

That’s not a valid node location!So this answers our question!

If p’s value is nullptr, it does NOT point to a valid node. Otherwise it

does.

This is a linked list traversal!

Alright, now let’s learn how to add nodes to our list!

When we use the condition:

while (p != nullptr) { … }

the loop will process EVERY node in the list and only stop

once it’s gone PAST the end of the list.

Page 42: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

42

Adding an Item to a Linked List

class LinkedList{

public:

private:

};Node *head;

LinkedList() { … }

~LinkedList() { … }

void addToRear(string v) { … }

bool findItem(string v) { … }void deleteItem(string v) { … }

void printItems() { … }

head

2200

value

next

2200

valuenext

3700

"shells"

"cash"nullptr

3700

There are three places you can insert a new item into a linked list:

at the top of the list at the end of the list somewhere in the middle

The algorithm to insert at the top is the easiest to code and also runs the

fastest. Let’s see this one first, and add a “ruby” to the top of our list!

Here

Here

Or somewhere

in the middle

Allocate a new nodevoid addToFront(string v) { … }

Put value v in the node

value

next

8000

{

}

OK, so what’s our algorithm?

Well, first we have to allocate a new node to hold our new

value. Second, we need to put the

new item into our new node.

And finally let’s link our head pointer to our new

node.Link the new node to theold top nodeLink the head pointer toour new top node“ruby" Then let’s link our new node

to the old top node in the list.22008000

These two steps must be in this order!

Page 43: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

43

Adding an Item to the Front

class LinkedList{

public:

private:

};Node *head;

LinkedList() { … }

~LinkedList() { … }

void addToRear(string v) { … }

bool findItem(string v) { … }void deleteItem(string v) { … }

void printItems() { … }

head

2200

value

next

2200

valuenext

3700

"shells"

"cash"nullptr

3700

OK, now let’s replace our psuedo-code with valid C++ code.

Allocate a new node

Put value v in the node

value

next

8000

{

}

Link the new node to theold top nodeLink the head pointer toour new top node“ruby"

void addToFront(string v)

Node *p;p = new Node;

p 8000

p->value = v; // put v in node

To do that, we need to setp->next equal to the address of the top node in the existing list.

p->next =

Fortunately, the head variable holds the address of the current top node!

head;

2200

Next, we want to link our new node to the current top node in

the list.Finally, we just update our head pointer so it holds the address of

our new top node!

Fortunately, our p variable holds the address of our new

node…

head = p;8000

And as you can see, our new node has been added at the top!

We’ve already seen how to do this. Let’s define a temporary

pointer and use the new command to allocate our new

node.

OK, now we just place item v (e.g., “ruby”) into our new

node. That’s easy!

Page 44: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

44

Adding an Item to the Front

class LinkedList{

public:

private:

};Node *head;

LinkedList() { … }

head

OK, but will this same algorithm work if the Linked List is empty?

{

}

…value

next

2200

valuenext

3700

"shells"

"cash"nullptr

3700

value

next

8000“ruby"

void addToFront(string v)

Node *p;p = new Node; p->value = v; // put v in nodep->next =

8000

head = p;

head;

Let’s see!

nullptr

p

value

next

8000“ruby"nullptr

8000

8000

Pretty cool – the same algorithm works whether the list is empty or

not!

Our list has no nodes! It’s

empty!2200

Alright, now let’s see how to add a node to the rear of a list!

Page 45: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

45

Adding an Item to the Rear

class LinkedList{

public:

};Node *head;

LinkedList() { … }

~LinkedList() { … }

void addToRear(string v) { … }

bool findItem(string v) { … }void deleteItem(string v) { … }

void printItems() { … }

Alright, next let’s look at how to append an item at the end of a list…

void addToRear(string v) { … }

{

}…

void addToFront(string v) { … }

We’ll add our new node

here…

There are actually two cases to consider:

Case #2: The existing list has one or more

nodes…head

8800

value

next

2200"shells"

value

next

8000“ruby"

2200

nullptr

Case #2:The list already

has some nodes!

Case #1: The existing list is totally empty!

head

nullptrCase #1:

The list has no nodes!

We’ll add the very first node

right here!

private:

Page 46: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

46

Adding an Item to the Rear

class LinkedList{

public:

};

Alright, let’s consider Case #1 first… It’s much easier!

{

}...

void addToRear(string v) head

nullptr

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.

After all, in both cases we’re adding a node right at the top of the linked list.

if our linked list is empty thenuse our addToFront() code

Which we just learned two minutes ago!

OK, so how do we determine if our linked list is empty?

if (head == nullptr)

And this one is easy, we just call our addToFront() function!

addToFront(v); // easy!!!

head

2200value

next nullptr

“ruby" 2200Adding a node to the end of

an empty list…

Is the same as adding a node to the top of an empty list!

Duh!

Well, as we learned, in an empty linked list, the head has a value of

nullptr.

Page 47: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

47

Adding an Item to the Rear

else{

}

class LinkedList{

public:

};

Alright, let’s consider Case #2 next: It’s more complex…

value

next

2200

valuenext

3700

"shells"

"cash"

3700

value

next

“ruby"value

next

8000“ruby"

2200

head

8000

if (head == nullptr)addToFront(v); // easy!!!

Here we want to add an item to the end of a linked list that already has

nodes.Well that doesn’t look too bad... Let’s

add an “iPad” to our list.OK, so what’s our algorithm?

We have to traverse down the links until we

find the current last node!

p

8000 2200

3700

Use a temp variable to

traverse to the current last node of the list

Allocate a new nodePut value v in the node

value

next

160“iPad"

Link the current last node to our new node

nullptr160

{

}...

void addToRear(string v)

Well, in order to add a new node here…

Then we want to allocate a new node and fill in its value…Next, we want to link the current last

node to the new node.

We want to add our new item right here!

nullptr

Link the last node to

nullptrNotice that p doesn’t traverse

past the last node... p points at it!

Finally, we set our new node’s next pointer to nullptr.

Page 48: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

48

Adding an Item to the Rear

else{

}

class LinkedList{

public:

};

OK, let’s see the C++ code now!

value

next

2200

valuenext

3700

"shells"

"cash"

3700

value

next

“ruby"value

next

8000“ruby"

2200

head

8000

if (head == nullptr)addToFront(v); // easy!!!

p

8000

nullptr

{

}...

void addToRear(string v)

Use a temp variable to

traverse to the current last node of the list

Allocate a new nodePut value v in the nodeLink the current last node to our new nodeLink the last node to

nullptr

Node *p;p = head; // start at top node

So what should our traversal

code look like?

Next we want to traverse until p points

directly at the last node…

while(p isn’t at the last node) p = p->next;

So what C++ code do we write here to ensure that our

loop stops when p points right at the last node?

But the next pointer in the earlier nodes

is NOT nullptr!

So we want to keep looping while p->next is not nullptr.

The moment p->next is nullptr, p points at the last

node!

We want to stop looping when p

points at this node

Well, here’s a hint:

Notice that the next pointer in the last node is nullptr.

p->next != nullptr )

Well, as in our printItems() method, we’ll use a temp

variable to follow the links, starting at the head node.

void printItems(){

Node *p; p = head; while (p != nullptr) {

cout << p->value << endl; p = p->next; }}

Page 49: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

49

Adding an Item to the Rear

else{

}

class LinkedList{

public:

};

OK, let’s see the C++ code now!

value

next

2200

valuenext

3700

"shells"

"cash"

3700

value

next

“ruby"value

next

8000“ruby"

2200

head

8000

if (head == nullptr)addToFront(v); // easy!!!

p

2200

3700

nullptr

{

}...

void addToRear(string v)

Allocate a new nodePut value v in the nodeLink the current last node to our new nodeLink the last node to

nullptr

while(p isn’t at the last node)

Node *p;p = head; // start at top node

p = p->next;p->next != nullptr )

OK, let’s see our C++ loop in action!

OK, well so far, p->next is clearly

not nullptr!

Again, p->next isnot yet nullptr!

Oooh, p->next isfinally equal to

nullptr!

And notice that p points directly at our

last node!

Alright, let’s finish up our function!

8000

Page 50: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

50

Adding an Item to the Rear

else{

}

class LinkedList{

public:

};

OK, let’s see the C++ code now!

value

next

2200

valuenext

3700

"shells"

"cash"

3700

value

next

“ruby"value

next

8000“ruby"

2200

head

8000

if (head == nullptr)addToFront(v); // easy!!!

p

nullptr

{

}...

void addToRear(string v)

Allocate a new nodePut value v in the nodeLink the current last node to our new nodeLink the last node to

nullptr

while(p isn’t at the last node)

Node *p;p = head; // start at top node

p = p->next;p->next != nullptr )

3700

Alright, let’s finish up our function!

How do we allocate a new node? That’s easy!

Node *n = new Node;

n

160value

next

160

Now let’s put our value into our new node…

n->value = v;

Now we need to link our last node to our new node…

“iPad"

We want to link this pointer…

To our new node!

p->next =n;

160

Finally, let’s terminate the linked list by setting the

last node’s next pointer to nullptr.

n->next = nullptr;

nullptr

When we use the condition:

while (p->next != nullptr) { … }

the loop continues until p points at the very last node of the list.

When you get to the line after the loop, p points at the last node!

Page 51: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

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:

void AddItem(string newItem){

}

if (our list is totally empty) Just use our addToFront() method to add the new node

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…

value

next

“bat”

nullptr

600

headnullptr600

Page 52: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

52

Here’s the basic algorithm:value

next

“dog”

value

next

“cat”

head

1000

1400

1400

800

1400

value

next

“rat”

nullptr

800

valuenext

“bat”600

void AddItem(string newItem){

}

else if (our new node belongs at the very top of the list) Just use our addToFront() method to add the new node

if (our list is totally empty) Just use our addToFront() method to add the new node

1000

For instance, let’s say we have an alphabetized list…

and we want to insert an item that’s smaller than the rest of the items in the

list…

600

1000In this case, our addToFront()

algorithm will add the node to the right spot in the list as well!

Not at the top, not at the bottom…bat belongs here, above cat.

Page 53: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

53

Here’s the basic algorithm:

p

value

next

“dog”

value

next

“cat”

head

1000

1400

14001400

value

next

“rat”

nullptr

800

1000

void AddItem(string newItem){

}

else if (our new node belongs at the very top of the list) Just use our addToFront() method to add the new node

if (our list is totally empty) Just use our addToFront() 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

For instance, we’re inserting an item like “fly” that belongs in the middle of an alphabetized list…

valuenext

“fly” 600

1400

1000

800

Once we’ve found the node directly above where we want to

add our new node, we can…

600800

Link the new node into the list right after the ABOVE node

Allocate and fill our new node with the item

Not at the top, not at the bottom…

First we link our new node to the node after it.

Second we link our above node to our new node.

fly belongs here, between dog and

rat.

Page 54: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

54

Let’s Convert it to C++ Codevoid AddItem(string newItem){

}

else if (our new node belongs at the very top of the list) Just use our addToFront() 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 your new item

if (our list is totally empty) Just use our addToFront() method to add the new nodeif (head == nullptr) AddToFront(newItem);

The code you write here depends on the nature of your list… Is it alphabetized? Is it ordered by

student ID#?

else if ( /* decide if the new item belongs at the top */ ) AddToFront(newItem);

Similarly, your traversal code will depend on how your list is organized…

Node *p = head; // start with top nodewhile (p->next != nullptr){

p = p->next; // move down one node}

if (/* p points just above where I want to insert my item */) break; // break out of the loop!

Link the new node into the list right after the ABOVE node

Allocate and fill your new node with the itemNode *latest = new Node; // alloc and fill our new nodelatest->value = newItem;latest->next =

This one is easy… We already did the same thing in our AddToRear()

method.

You’ll want an if-statement to break out of the loop when it finds the node just above the

insertion point!

value

next

“dog”

value

next

“cat”

head

1000

1400

14001400

value

next

“rat”

nullptr

800

1000

valuenext

600

800

p1400

800

This one’s easy – we’ve already learned how to

allocate and fill in a new node variable.This one is a bit more complex…

First we want to link our new node to the node below

latest 600

“fly”

p->next; // link new node to the node below

We want to set latest->next…

to the address of the node below…Second, we want to link the

node above our insertion point to our new node

We want

to set p-

>next …

to the address of our new node.

p->next = latest; // link node above to our new node

600

These two lines must be in this order!

Page 55: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

55

Let’s Convert it to C++ Code

house *p = head; // start with first nodewhile (p->next != nullptr){

p = p->next; // move down one node}

else // new node belongs somewhere in the middle of the list{

}

void AddItem(string newItem){

}

if (head == nullptr) AddToFront(newItem);

else if ( /* decide if the new item belongs at the top */ ) AddToFront(newItem);

Node *latest = new Node; // alloc and fill our new nodelatest->value = newItem;latest->next = p->next; // link new node to node belowp->next = latest; // link above node to our new node

Finally, let’s fill in the blanks to convert our function into one that

adds items in alphabetical order!

A new item belongs at the top of the list if it is smaller than the list’s current top item.

Let’s check for this!

newItem < head->value )

if (/* p points just above where I want to insert my item */) break; // break out of the loop!if ( newItem >= p->value && newItem <= p->next->value ) break;

This line checks if the new item should be inserted between the current node and the node below it…

value

next

“rat”

value

next

“cat”

1000

1400

14001400

p->

“dog”

The if-clause would be true for “dog” since it fits between “cat” and “rat”!

“yak”

But false for “yak”, since it comes after “rat” and “cat”.

value

next

“cat”

head

1000

14001400

1000

“bat” This line ensures we stop when we’ve reached the last node in the list.

If p->next == nullptr, it means that our new item is bigger than every item in the list!

In this case we add our item after the last node.

“yak”

value

next

“rat”

nullptr

value

next

“cat”

1000

1400

14001400

p->

Our updated traversal code should find just the right spot for our new item.

Page 56: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

56

Deleting an Item in a Linked List

class LinkedList{

public:

};Node *head;

LinkedList() { … }

~LinkedList() { … }

void addToRear(string v) { … }

bool findItem(string v) { … }void deleteItem(string v) { … }

void printItems() { … }

void deleteItem(string v) { … }

{

}…

When deleting an item from a linked list, there are two different cases to consider:

Case #1: You’re deleting the first node.

void addToFront(string v) { … }

value

next

“dog”

value

next

“cat”

head

1000

1400

1400

800

1400

value

next

“rat”

nullptr

800

1000

Case #2: You’re deleting an interior node or the last node.

We want to delete the item

in the first node…We want to delete

the item in an interior node…

or the last node.

Let’s consider Case #1 first…

private:

Page 57: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

57

Deleting an Item in a Linked List

class LinkedList{

public:

};

{

}…

value

next“dog”

value

next

“cat”

head

1000

1400

1400

800

1400

value

next

“rat”

nullptr

800

void deleteItem(string v)

X

Ok, let’s consider Case #1… deleting the top item in a list.

Let’s kill our cat.OK, so what’s our algorithm?

If the list’s empty then returnIf the first node holds the item we wish to delete then {

}

If so, we create a temporary pointer to remember where our

target node is located.

killMe

killMe = address of top node1000

Update head to point to thesecond node in the list

1400

1000

headnullptr

Well, first we need to make sure the list isn’t empty!!!

If it is empty, there’s nothing to delete – so we

just return!

Then we update our head pointer…

so it points to the node after our target node.

Now we delete our target node…

using our killMe pointer!

Delete our target node

Finally, let’s return once we’re done!

Return – we’re done

Next we need to check if the first node holds the item we

want to remove.

Page 58: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

58

Deleting an Item in a Linked List

class LinkedList{

public:

};

{

}…

void deleteItem(string v)

If the list’s empty then return {

}

killMe = address of top node

Update head to point to thesecond node in the list

Delete our target node

OK, let’s see the C++ code now!

value

next“dog”

value

next“cat”

head

1000

1400

1400

800

value

next

“rat”

nullptr

800

1000

OK, so how do we determine if our linked list is empty?

if (head == nullptr) return;Next, now how do we

determine if the first node holds the value we want to delete? If the first node holds the

item we wish to delete then if (head->value == v)

Compares this value…

against the input

parameter.

Now let’s create a temporary pointer and set its value to the

top node’s address.Node *killMe = head;

“cat”

killMe

1000

Now let’s update our head pointer so it points to the

second node.

Let’s copy it into our head pointer.

head = killMe->next;

can be found in

killMe->next!

1400

delete killMe;

Now we can easily delete our target node!

Return – we’re done

Finally, let’s add our return statement.

return;The second

node’s address…

Page 59: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

59

Deleting an Item in a Linked List

class LinkedList{

public:

};

{

}…

void deleteItem(string v)

Alright, let’s consider Case #2 next – unfortunately it’s more complex…

… // the code we just wrote

value

next“dog”

value

next“cat”

1000

1400

1400

800

head 1000

Let’s kill our “rat” node!

name

next

“yak”

nullptr

3000

value

next

“rat”

3000

800

OK, so what’s our algorithm?

Why the node above?

Well, we need to stop one node above

so we can relink around our target

node!

3000

Use a temp pointer to traversedown to the node above theone we want to delete…

p

10001400

killMe

killMe = addr of target node800p now points just above our target

node!

Next we need to check if we even found our target

node…

If so, we can proceed!

If we found our target node{

}Ok, now let’s create

another temp pointer to remember where our target

node is.

Link the node above tothe node below

Finally, let’s delete our target node!

Delete our target node

Ok, now let’s relink our node above the target…

to the node below the target!

Let’s kill this

node!

“rat”

First we need to traverse down the list…

until we find the node above the one we want to

delete.

ratnoisedo not delete – sound effect

Page 60: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

60

Deleting an Item in a Linked List

class LinkedList{

public:

};

{

}…

void deleteItem(string v)

… // the code we just wrote

value

next“dog”

value

next“cat”

1000

1400

1400

800

head 1000

name

next

“yak”

nullptr

3000

value

next

“rat”

3000

800

p

10001400

OK, let’s see the C++ code now!

Use a temp pointer to traversedown to the node above theone we want to delete…

killMe = addr of target node

If we found our target node{

}

Link the node above tothe node belowDelete our target node

“rat”

Node *p = head; while (p != nullptr) {

p = p->next;}

As before, let’s use one of our traversal loops.

if ( ) break; // p pts to node above

p->next != nullptr && p->next->value == v

p will start by pointing at our head node…

and will iterate through every node in the list…

For each node we visit through p…

If so, then p points to the node above our target…

and we break out of our loop.

First we check whether there is a node following the one pointed to by p.

If there is a node following p…

then we check to see if that next node holds our to-be-

deleted value.

If p->next is not nullptr…

then there is a

valid node

following node

p!

p->next is not nullptr, so there is a valid node following this one!

p->next->value is “dog” – this is not equal to our target value of “rat”.

p->next is not nullptr, so there is a valid node following this one!p->next->value is “rat” –

this is equal to our target value of “rat”! So we

break out!

Page 61: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

61

Deleting an Item in a Linked List

class LinkedList{

public:

};

{

}…

void deleteItem(string v)

… // the code we just wrote

value

next“dog”

value

next“cat”

1000

1400

1400

800

head 1000

name

next

“yak”

nullptr

3000

value

next

“rat”

3000

800

p 1400

killMe

800

OK, let’s see the C++ code now!

killMe = addr of target node

{

}

Link the node above tothe node belowDelete our target node

“rat”

Node *p = head; while (p != nullptr) {

p = p->next;}

if ( ) break; // p pts to node above

p->next != nullptr && p->next->value == v

If we found our target nodeif (p != nullptr) // found our value!Note: The target node’s location can be found

here!

Node *killMe = p->next;

But if we did find our target value, then p will point to the

node above it, and NOT be nullptr!

Let’s check for this case!

p is not nullptr

since we found our

target!

Let’s remember where our target node is located

using a temporary pointer…

Now we want to link the node above the target…

to the node below the target.

p->next = killMe->next;

That address can be found in killMe-

>next!

3000

Finally, we can use the delete command to free

our node…

delete killMe;

And believe it or not, this same code works when the target node is the

last one in the list!

If we traversed all the way through the list and didn’t find our

value…

then p will be equal to nullptr.

Page 62: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

62 Linked List Challenge

Now it’s your turn!

Node *head;

LinkedList() { … }

~LinkedList() { … }

void addToRear(string v) { … }

bool findItem(string v) { … }void deleteItem(string v) { … }

void printItems() { … }bool findItem(string v) { … }

{

}…

void addToFront(string v) { … }

private:

How would you write the findItem() method?

It should return true if it can find the passed-in

item, and false otherwise.

int main(){

Linked List myFriends;

myFriends.addToFront(“David”); …

if (myFriends.findItem(“Carey”) == true) cout << “I’m so lucky!\n”;}

class LinkedList{

public:

};

Page 63: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

63

Destructing a Linked List

class LinkedList{

public:

};Node *head;

LinkedList() { … }

~LinkedList() { … }

void addToRear(string v) { … }

bool findItem(string v) { … }void deleteItem(string v) { … }

void printItems() { … }~LinkedList()

{

}…

OK, so how do we completely destruct a linked list once we’re done with it?

void addToFront(string v) { … }

value

next

“dog”

value

next

“cat”

head

1000

1400

1400

800

1400

value

next

“rat”

nullptr

800

1000

private:

Well, perhaps we can use something like our existing printItems() code?

void printItems(){ Node *p; p = head; while (p != nullptr) { cout << p->value << endl; p = p->next; }}

Node *p; p = head; while (p != nullptr) { cout << p->value << endl; p = p->next; }

delete p;

Let’s see what happens!

Page 64: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

64

Destructing a Linked List

class LinkedList{

public:

};Node *head;

~LinkedList(){

}…

OK, so how do we completely destruct a linked list once we’re done with it?

value

next“dog”

value

next

“cat”

head

1000

1400

1400

800

1400

value

next

“rat”

nullptr

800

1000

private:

Well, perhaps we can use something like our existing printItems() code?

Let’s see what happens! Node *p; p = head; while (p != nullptr) { delete p; p = p->next; }

p

1000

Houston… We have a problem!

There is no p->next anymore!

That memory is no longer ours to use!

In fact, there could be totally different

data here now!

123456123456

Page 65: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

65

Destructing a Linked List

class LinkedList{

public:

};Node *head;

~LinkedList(){

OK, let’s fix it.

value

next“dog”

value

next

“cat”

head

1000

1400

1400

800

1400

value

next

“rat”

nullptr

800

1000

private:

Node *p; p = head; while (p != nullptr) { delete p; p = p->next;

p 1000 }}…

So before we delete the node

pointed to by p…

Let’s save the location of the next node in a temporary

variable!

Node *n = p->next;

n 1400

delete p;

Then we can delete our node

normally…

Finally, we can now advance our p pointer to the next node by

using our temp variable!

p = n;

1400

800

800

Page 66: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

66

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

either!

Well, as it turns out, we can fix this last problem… Let’s see how!

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!

Page 67: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

67

Linked Lists and Tail PointersSince we have a head pointer…

A tail pointer is a pointer that always points to the last node of the list!

class LinkedList{public: LinkedList() {…} void addToFront(string v) {…} …

private:

Node *head; };

Why not maintain a “tail” pointer too?

valuenext

“cat”

1000head

1000

valuenext

“lemur”

nullptr

800

1400

1400

valuenext

“emu”

1400

800

800

tail 800

Node *tail;Using the tail pointer, we can add new items to the end of our list without traversing!

Page 68: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

68

Adding an Item to the Rear…With a Tail Pointer

else{

class LinkedList{

public:

private: Node *head;

};

value

next

2200

valuenext

3700

"shells"

"cash"

3700

value

next

“ruby"value

next

8000“ruby"

2200

head

8000

if (head == nullptr)addToFront(v);

tail

nullptr

{

void addToRear(string v)

while(p->next != nullptr)

Node *p;p = head; // start at top node

p = p->next;

3700

Let’s see how to update our addToRear() function once our class

has a tail pointer.

Node *n = new Node;

value

next

160

n->value = v;

“iPad"

p->next =n;n->next = nullptr;

nullptr

WARNING: You have to update all of your other methods to use the tail

pointer (e.g., constructor, addToFront()) as well!

Guess what – we no longer need this traversal loop!

The tail pointer already points to our last node!

Node *tail;

Already points to our last

node!n160

Wait! We no longer have a p variable that points at the last

node!

But we do have our tail variable, and it points to the last node!

So let’s just replace “p” with “tail”!

tail->next = n;

160

So is that it???

Are we done???

Not quite! Now our tail pointer doesn’t point at our

last node! Let’s fix it!

Let’s update the tail pointer with the address of the new

last node in the list.

Guess what? n points to the last node now!160

e.g., don’t forget to update addToFront(), deleteItem(), etc…

tail = n; }}...

Node *n = new Node;n->value = v;

n->next = nullptr;tail->next = n;

tail = n; }}...

Page 69: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

69

Doubly-linked Lists

A doubly-linked list has both next and previous pointers in every node:

struct Node{ string value; 

Node * next; Node * prev;};

One of the downsides with our simple linked list is that we can only travel in one direction… down!

value

next

2200

valuenext nullptr

3700

"shells"

"cash"

3700

value

next

“ruby"value

next

8000“ruby"

2200

head

8000

Given a pointer to a node, I can only find nodes below it!

p

2200

From p, I can find my shells and my cash, but have no way of getting back to my

ruby!

Wouldn’t it be nice if we could move both directions in a linked

list?We can! With a doubly-linked

list!

value

next

2200

valuenext nullptr

3700

"shells"

"cash"

3700

value

next

“ruby"value

next

8000“ruby"

2200

head

8000

prev

prev

prev

Each prev pointer points to the node above…

Except the top node’s prev pointer…

It has a value of nullptr, indicating that

there are no nodes above it.

2200

8000

nullptr

Page 70: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

70

Doubly-linked Lists

value

next

2200

valuenext nullptr

3700

"shells"

"cash"

3700

value

next

“ruby"value

next

8000“ruby"

2200

head

8000

p

8000value

next

2200

valuenext nullptr

3700

"shells"

"cash"

3700

value

next

“ruby"value

next

8000“ruby"

2200

head

8000

prev nullptr

prev 8000

prev 2200

Now I can traverse in both directions!

And, if I like, I can have a tail pointer too!

tail

3700

Node *p;

p = tail;while (p != nullptr){ cout << p->value; p = p->prev;}

Node *p;

p = head;while (p != nullptr){ cout << p->value; p = p->next;}

Of course, now we’re going to have to link up lots of additional pointers…

But nothing comes free in life!

Page 71: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

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.

And of course, we still have special cases if we insert or delete nodes at

the top or the bottom of the list.

Head Ptr

DataNextPrev

Bill DataNextPrev

Jane DataNextPrev

Myknullptr

DataNextPrev

Dave

nullptr

Insert here!

PreviousNode

FollowingNode

Page 72: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

72

Linked List Cheat Sheet struct Node{ string value;

Node *next; Node *prev;};

Given a pointer to a node: Node *ptr;

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:if (ptr != nullptr && ptr->next != nullptr)

cout << ptr->next->value;

Does our traversal meet this requirement?

NODE *ptr = head; while (ptr != nullptr) { cout << ptr->value; ptr = ptr->next; }

To get the head node’s data: if (head != nullptr) cout << head->value;

To advance ptr to the next node/end of the list: if (ptr != nullptr)

ptr = ptr->next;

NEVER access a node’s data until validating its pointer: if (ptr != nullptr)

cout << ptr->value;

To check if a list is empty: if (head == nullptr) cout << “List is empty”;

Notice that this check:

ptr != nullptr

To check if a pointer points to the first node in a list:

if (ptr == head) cout << “ptr is first node”;

Ensures that ptr points to a valid node…

before we access its “value” and “next” fields here.

Page 73: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

73

Which is Faster?Getting to the 753rd item in a linked

list or an array?

Linked Lists vs. ArraysWinner: Array

We can get to any item in an array in 1 step. We have to pass thru 752 other

nodes to reach the 753rd 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?

Winner: Linked ListWe can insert a new item in a few steps! With an array, we’d have to

shift all n items down first!

Which is faster?Removing an item from the middle of a linked list or the middle of an

array?

Winner: Linked ListOnce 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!

Which is easier to program?Which data structure will take

less time to program and debug?

Winner: ArrayLet’s face it – arrays are easier to use. So only use a linked list if you

really have to!

Page 74: 1 Lecture #4 Resource Management, Part 2 –Assignment Operators Basic Linked Lists –Insertion, deletion, destruction, traversals, etc. Advanced Linked.

74

Class ChallengeWrite a function called insert that accepts two NODE pointers as arguments:

b4node: 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 b4node in the list, properly linking all nodes.

(You may assume that a valid node follows b4node prior to insertion.)

struct NODE{ string data; NODE *next, *prev;};

b4node

newnodeDataNextPrev

Dave

exists

nullptrnullptr