CS240 Mike Lam, Professor Linked Lists Retrospective Arrays are - - PowerPoint PPT Presentation

cs240
SMART_READER_LITE
LIVE PREVIEW

CS240 Mike Lam, Professor Linked Lists Retrospective Arrays are - - PowerPoint PPT Presentation

CS240 Mike Lam, Professor Linked Lists Retrospective Arrays are great O(1) access time to any element Amortized O(1) insertion and removal Referential arrays allow arbitrary-sized objects There are still disadvantages


slide-1
SLIDE 1

CS240

Mike Lam, Professor

Linked Lists

slide-2
SLIDE 2

Retrospective

  • Arrays are great

– O(1) access time to any element – Amortized O(1) insertion and removal – Referential arrays allow arbitrary-sized objects

  • There are still disadvantages

– Occasional O(n) worst-case costs – Requires large chunks of reserved memory – Insertion/removal in the middle is expensive

slide-3
SLIDE 3

Retrospective

  • Goal: Do less work when inserting and removing in the

middle of our lists

2 3 5 8

slide-4
SLIDE 4

Retrospective

  • Goal: Do less work when inserting and removing in the

middle of our lists

  • Let's "pull apart" the array

2 3 5 8 2 3 5 8

slide-5
SLIDE 5

Retrospective

  • Goal: Do less work when inserting and removing in the

middle of our lists

  • Let's "pull apart" the array
  • And add links between all the items

2 3 5 8 2 3 5 8 2 3 5 8

slide-6
SLIDE 6

Linked Lists

  • This is a "linked list"
  • Every item has a "next" pointer/reference

– Last item has a NULL "next" pointer

  • Add and remove items by manipulating the pointers
  • Keep external pointers to the beginning ("head") and

end ("tail") of the list

2 3 5 8

slide-7
SLIDE 7

Singly-Linked Lists

  • Singly-linked list:

"a" "b" "c" NULL head tail single link per node

slide-8
SLIDE 8

Singly-Linked Lists

  • Node:

typedef struct linknode { data_t data; struct linknode *next; } linknode_t;

  • Linked list:

typedef struct { linknode_t *head; linknode_t *tail; size_t size; } linklist_t;

slide-9
SLIDE 9

Singly-Linked Lists

  • Creating new linked-list nodes:

linknode_t* malloc_node(data_t value) {

linknode_t *new_node = (linknode_t*)malloc(sizeof(linknode_t));

// TODO: check for null new_node->value = value; new_node->next = NULL; return new_node;

}

slide-10
SLIDE 10

Singly-Linked Lists

  • Inserting at the head:

linknode_t *newest = malloc_node(x); newest->next = head; head = newest;

slide-11
SLIDE 11

Singly-Linked Lists

  • Inserting at the tail:

linknode_t *newest = malloc_node(x); newest->next = NULL; tail->next = newest; tail = newest;

slide-12
SLIDE 12

Singly-Linked Lists

  • Removing from the head:

if (head == NULL) ERROR!

  • ld_head = head;

head = head->next; free(old_head);

slide-13
SLIDE 13

Singly-Linked Lists

  • Removing from the tail:

if (tail == NULL) ERROR

  • ld_tail = tail;

tail = ???

  • Problem: Can't access previous node
slide-14
SLIDE 14

Singly-Linked Lists

  • Removing from the tail:

if (tail == NULL) ERROR

  • ld_tail = tail;

tail = ???

  • Problem: Can't access previous node

– Solution: Track previous nodes as well

  • (doubly-linked lists)
slide-15
SLIDE 15

Challenge

  • Given a singly-linked list called "data", write a

snippet of code that will print out all of the values in the list

slide-16
SLIDE 16

Singly-Linked Lists

  • Insert: O(1)

– if you have a reference to the location – O(n) if the new location is index-based or the list

needs to be sorted

  • Delete: O(1)

– if you have a reference to the item – O(n) if you have to look for it

  • Indexed access or search: O(n)
slide-17
SLIDE 17

Linked Stack

  • Consider stack implementation using a singly-

linked list

slide-18
SLIDE 18

Linked Stack

  • Consider stack implementation using a singly-

linked list

– Insert and remove at the head – Push, pop, and top are O(1)

slide-19
SLIDE 19

Linked Queue

  • Consider queue implementation using a singly-

linked list

slide-20
SLIDE 20

Linked Queue

  • Consider queue implementation using a singly-

linked list

– Insert at tail, remove from head

  • Can't remove from the tail!

– Enqueue, dequeue, and first are O(1)

slide-21
SLIDE 21

Looking ahead

  • What if we kept two pointers?

– "next" and "prev" – This is a "doubly-linked list"

  • What if tail.next pointed to the head?

– This is a "circularly-linked list"

  • What if we kept multiple pointers to places

further down the list?

– This is a "skip list"

slide-22
SLIDE 22

Doubly-Linked Lists

  • Two references: prev and next

– To predecessor and successor nodes

  • Allows insert and remove at both ends

– Can now implement stacks, queues, and deques – “Deque” = “double-ended queue”

slide-23
SLIDE 23

Circularly-Linked Lists

  • Keep a single node reference
  • Useful for round-robin scheduling

– New operation: rotate()

  • Can be used to implement regular list

– No need to track both head and tail – head = tail.next

slide-24
SLIDE 24

Sentinels

  • Placeholder (“fake”) nodes at head and/or tail

2 head tail head tail Empty list: After append(2): 2 3 head tail After append(3): 2 3 5 head tail After append(5):

slide-25
SLIDE 25

Sentinels

  • Simplifies logic of insertion and removal

void list_append(list_t *a, x) { linknode_t *new = malloc_node(x); new->prev = a->tail; new->next = NULL; if (list->head == NULL) { a->head = new; } else { a->tail->next = new; } a->tail = new; } void list_append(list_t *a, x) { linknode_t *new = malloc_node(x);

new->prev = a->tail->prev; new->next = a->tail; a->tail->prev->next = new; a->tail->prev = new; }

2 3 5 head tail head tail Empty list: Populated list:

slide-26
SLIDE 26

Deques

  • Double-ended queue
  • Two sets of insert/remove methods:

– addfirst and removefirst – addlast and removelast

  • Implementation using doubly-linked list w/

sentinels

slide-27
SLIDE 27

Tradeoffs

  • Advantages of linked lists

– Worst-case O(1) bounds

  • No amortized bounds

– O(1) insertions and removals at arbitrary positions

  • No need to shift elements
  • This is a HUGE advantage!
slide-28
SLIDE 28

Tradeoffs

  • Advantages of arrays

– O(1) access to elements by index – Proportionally fewer actual operations

  • Calculation and dereference vs. memory allocation and

reference re-arranging

– Proportionally less memory usage

  • Both arrays and linked lists can be referential
  • Arrays require at most 2n space overhead, while linked

lists are at least 2n (or 3n for doubly-linked lists)