28
1 EE 355 Unit 11b Doubly-Linked Lists and Deques Mark Redekopp

EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

Embed Size (px)

Citation preview

Page 1: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

1

EE 355 Unit 11b

Doubly-Linked Lists and Deques

Mark Redekopp

Page 2: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

2

Singly-Linked List Review

• Used structures/classes and pointers to make ‘linked’ data structures

• Singly-Linked Lists dynamically allocates each item when the user decides to add it.

• Each item includes a 'next' pointer holding the address of the following Item object

• Traversal and iteration is only easily achieved in one direction

val next

3 0x1c0

val next

9 0x168

0x148

head

0x148 0x1c0

val next

20x0

(Null)

0x168

#include<iostream>

using namespace std;

struct Item {

int val;

Item* next;

};

class List

{

public:

List();

~List();

void push_back(int v); ...

private:

Item* head;

};

int

val

Item *

next

struct Item blueprint:

0x1c0

temp

Given temp…could you ever recover the address of the previous item?

No!!!

Page 3: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

3

Doubly-Linked Lists

• Includes a previous pointer in each item so that we can traverse/iterate backwards or forward

• First item's previous field should be NULL

• Last item's next field should be NULL

#include<iostream>

using namespace std;

struct DLItem {

int val;

DLItem* prev;

DLItem* next;

};

class DLList

{

public:

DLList();

~DLList();

void push_back(int v); ...

private:

DLItem* head;

};

int

val

DLItem *

next

struct Item blueprint:

DLItem *

prev

0x148

head

3 0x1c0NULL

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 NULL0x1c0

val nextprev

0x210

Page 4: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

4

Doubly-Linked List Add Front

• Adding to the front requires you to update…– Head

– New front's next & previous

– Old front's previous

0x148

head

3 0x1c0NULL

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 NULL0x1c0

val nextprev

0x210

12

val nextprev

0x190

Page 5: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

5

Doubly-Linked List Add Front

• Adding to the front requires you to update…– Head

– New front's next & previous

– Old front's previous

0x148

head

3 0x1c00x190

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 NULL0x1c0

val nextprev

0x210

12 0x148NULL

val nextprev

0x190

Page 6: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

6

Doubly-Linked List Add Middle

• Adding to the middle requires you to update…– Previous item's next field

– Next item's previous field

– New item's next field

– New item's previous field

0x148

head

3 0x1c0NULL

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 NULL0x1c0

val nextprev

0x210

12

val nextprev

0x190

Page 7: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

7

Doubly-Linked List Add Middle

• Adding to the middle requires you to update…– Previous item's next field

– Next item's previous field

– New item's next field

– New item's previous field

0x148

head

3 0x1c0NULL

val nextprev

9 0x1900x148

val nextprev

0x148 0x1c0

6 NULL0x190

val nextprev

0x210

12 0x2100x1c0

val nextprev

0x190

Page 8: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

8

Doubly-Linked List Remove Middle

• Removing from the middle requires you to update…– Previous item's next field

– Next item's previous field

– Delete the item object

0x148

head

3 0x1c0NULL

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 NULL0x1c0

val nextprev

0x210

Page 9: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

9

Doubly-Linked List Remove Middle

• Removing from the middle requires you to update…– Previous item's next field

– Next item's previous field

– Delete the item object

0x148

head

3 0x210NULL

val nextprev

9 0x2100x148

val nextprev

0x148

0x1c0

6 NULL0x148

val nextprev

0x210

Page 10: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

10

DEQUES AND THEIR IMPLEMENTATION

Using a Doubly-Linked List to Implement a Deque

Page 11: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

11

Understanding Performance

• Recall vectors are good at some things and worse at others in terms of performance

• The Good:

– Fast access for random access (i.e. indexed access such as myvec[6])

– Allows for ‘fast’ addition or removal of items at the back of the vector

• The Bad:

– Erasing / removing item at the front or in the middle (it will have to copy all items behind the removed item to the previous slot)

– Adding too many items (vector allocates more memory that needed to be used for additional push_back()’s…but when you exceed that size it will be forced to allocate a whole new block of memory and copy over every item

30 51 52 53 54

0 1 2 3 4 5

10

30 51 5253 54 10

30 51 5253 54 1012 18

30 51 5253 54 10 12 18

After deleting we

have to move

everyone up

Vector may have 1

extra slot, but when

we add 2 items a

whole new block of

memory must be

allocated and items

copied over

Page 12: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

12

Deque Class

• Double-ended queues (like their name sounds) allow for efficient (fast) additions and removals from either 'end' (front or back) of the list/queue

• Performance:

– Slightly slower at random access (i.e. array style indexing access such as: data[3]) than vector

– Fast at adding or removing items at front or back

Page 13: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

13

Deque Class• Similar to vector but allows for

push_front() and pop_front() options

• Useful when we want to put things in one end of the list and take them out of the other

#include <iostream>

#include <deque>

using namespace std;

int main()

{

deque<int> my_deq;

for(int i=0; i < 5; i++){

my_deq.push_back(i+50);

}

cout << “At index 2 is: “ << my_deq[2] ;

cout << endl;

for(int i=0; i < 5; i++){

int x = my_deq.front();

my_deq.push_back(x+10);

my_deq.pop_front();

}

while( ! my_deq.empty()){

cout << my_deq.front() << “ “;

my_deq.pop_front();

}

cout << endl;

}

my_deq51

1

52 53 54 60

0 1 2 3 4

my_deq50 51 52 53 54

0 1 2 3 4

my_deq60 61 62 63 64

0 1 2 3 4

2

3

4

1

2

3

4

my_deq

after 1st iteration

after all iterations

Page 14: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

14

Deque Implementation

• Let's consider how we can implement a deque

• Could we use a singly-linked list and still get fast [i.e. O(1)] insertion/removal from both front and back?

Page 15: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

15

List class

Singly-Linked List Deque

• Recall a deque should allow for fast [i.e. O(1) ] addition and removal from front or back

• In our current singly-linked list we only know where the front is and would have to traverse the list to find the end (tail)

0x148

head

3 0x1c0

val next

9 0x210

val next

0x148 0x1c0

6 NULL

val next

0x210

Page 16: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

16

List class

Option 1: Singly-Linked List + Tail Pointer

• We might think of adding a tail pointer data member to our list class

– How fast could we add an item to the end?

0x148

head

0x210

tail

3 0x1c0

val next

9 0x210

val next

0x148 0x1c0

6 NULL

val next

0x210

Page 17: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

17

List class

Option 1: Singly-Linked List + Tail Pointer

• We might think of adding a tail pointer data member to our list class

– How fast could we add an item to the end? O(1)

– How fast could we remove the tail item?

0x148

head

0x190

tail

3 0x1c0

val next

9 0x210

val next

0x148 0x1c0

6 0x190

val next

0x210

12 NULL

val next

0x190

Page 18: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

18

List class

Option 1: Singly-Linked List + Tail Pointer

• We might think of adding a tail pointer data member to our list class

– How fast could we add an item to the end? O(1)

– How fast could we remove the tail item? O(n)

• Would have to walk to the 2nd to last item

0x148

head

0x190

tail

3 0x1c0

val next

9 0x210

val next

0x148 0x1c0

6 0x190

val next

0x210

12 NULL

val next

0x190

Page 19: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

19

List class

Option 2: Tail Pointer + Double-Linked List

• We might think of adding a tail pointer data member to our list class

– How fast could we add an item to the end?

0x148

head

3 0x1c0NULL

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 NULL0x1c0

val nextprev

0x210

0x210

tail

Page 20: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

20

List class

Option 2: Tail Pointer + Double-Linked List

• We might think of adding a tail pointer data member to our list class

– How fast could we add an item to the end? O(1)

– How fast could we remove the tail item?

0x148

head

3 0x1c0NULL

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 0x1900x1c0

val nextprev

0x210

0x190

tail

12 NULL0x210

val nextprev

0x190

0x210

Page 21: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

21

List class

Option 2: Tail Pointer + Double-Linked List

• We might think of adding a tail pointer data member to our list class

– How fast could we add an item to the end? O(1)

– How fast could we remove the tail item? O(1)

• We use the PREVIOUS pointer to update tail

0x148

head

3 0x1c0NULL

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 0x1900x1c0

val nextprev

0x210

0x210

tail

12 NULL0x210

val nextprev

0x190

0x190

Page 22: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

22

List class

Option 2: Tail Pointer + Double-Linked List

• We might think of adding a tail pointer data member to our list class

– How fast could we add an item to the end? O(1)

– How fast could we remove the tail item? O(1)

• We use the PREVIOUS pointer to update tail

0x148

head

3 0x1c0NULL

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 NULL0x1c0

val nextprev

0x210

0x210

tail

12 NULL0x210

val nextprev

0x190

0x190

Page 23: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

23

List class

Option 3: Circular Double-Linked List

• Make first and last item point at each other to form a circular list

– We know which one is first via the 'head' pointer

0x148

head

3 0x1c00x210

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 0x1480x1c0

val nextprev

0x210

Page 24: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

24

List class

Option 3: Circular Double-Linked List

• Make first and last item point at each other to form a circular list

– We know which one is first via the 'head' pointer

– What expression would yield the tail item?

0x148

head

3 0x1c00x210

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 0x1480x1c0

val nextprev

0x210

Page 25: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

25

List class

Option 3: Circular Double-Linked List

• Make first and last item point at each other to form a circular list

– We know which one is first via the 'head' pointer

– What expression would yield the tail item?

• head->prev

0x148

head

3 0x1c00x210

val nextprev

9 0x2100x148

val nextprev

0x148 0x1c0

6 0x1480x1c0

val nextprev

0x210

Page 26: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

26

One Last Point

• Can this kind of deque implementation support O(1) access to element i?

– i.e. Can you access list[i] quickly for any i?

• No!!! Still need to traverse the list

• You can use a "circular" array based dequeimplementation to get fast random access

– This is what the actual C++ deque<T> class does

– Don't worry about this though…

Page 27: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

27

Circular Buffers• Take an array but imagine it wrapping into

a circle to implement a deque

• Setup a head and tail pointer

– Head points at first occupied item, tail at first free location

– Push_front() and pop_front() update the head pointer

– Push_back() and pop_back() update the tail pointer

• To overcome discontinuity from index 0 to MAX-1, use modulo operation– Index = 7; Index++ should cause index = 0

– index = (index + 1)%MAX

– Index = 0; Index-- should cause index = 7

– if(--index < 0) index = MAX-1;

• Get item at index i– It's relative to the head pointer

– Return item at (head + i)%MAX

7

6 5

4

3

21

0

head

tail

0 1 2 3 4 5 6 7

7

6 5

4

3

21

0

head

tail

7

6 5

4

3

21

0

head

3.) Push_front()

size=2 size=3

1.) Push_back()

2.) Push_back()

tail

Page 28: EE 355 Unit 11b - USC Viterbiee.usc.edu/~redekopp/ee355/slides/Unit11b_DoublyLinkedLists.pdf · List class Option 3: Circular Double-Linked List •Make first and last item point

28

Activity: Write a 'delist' class

• Write a 'double-ended list' class to store integers that mimics a deque

• Support the following methods

– size()

– empty()

– push_back() and pop_back()

– push_front() and pop_front()

– back() and front() [returns back or front integer]