28
CS240 Mike Lam, Professor Linked Lists

Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

CS240

Mike Lam, Professor

Linked Lists

Page 2: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Retrospective

● Arrays are great

– O(1) access time to any element

– Amortized O(1) implementation of stacks and queues

– “Referential” (pointer) arrays allow arbitrary-sized elements

● There are still disadvantages

– Occasional O(n) worst-case costs

– Requires large chunks of reserved memory

– Insertion/removal in the middle is expensive

Page 3: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Retrospective

● Goal: Do less work when inserting and removing in themiddle of our lists

2 3 5 8

Page 4: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Retrospective

● Goal: Do less work when inserting and removing in themiddle of our lists

● Let's "pull apart" the array

2 3 5 8

2 3 5 8

Page 5: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Retrospective

● Goal: Do less work when inserting and removing in themiddle 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

Page 6: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Linked Lists

● This is a "linked list"

● Every item enclosed in a "node"

● Every node has a "next" pointer/reference

– Last node has a NULL "next" pointer

● Add and remove items by manipulating the nodes andpointers

● Keep external pointers to the beginning ("head") and end("tail") of the list

2 3 5 8 X

Page 7: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Singly-Linked Lists

● Singly-linked list:

"a" "b" "c" NULL

head tail

single linkper node

Page 8: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

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;

Page 9: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

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->data = value;

new_node->next = NULL;

return new_node;

}

Page 10: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Singly-Linked Lists

● Inserting at the head:

linknode_t *new = malloc_node(x);

new->next = head;

head = new;

Page 11: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Singly-Linked Lists

● Inserting at the tail:

linknode_t *new = malloc_node(x);

if (tail != NULL) {

tail->next = newest;

}

tail = newest;

Page 12: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Singly-Linked Lists

● Removing from the head:

if (head == NULL)

ERROR!

old_head = head;

head = head->next;

free(old_head);

Page 13: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Singly-Linked Lists

● Removing from the tail:

if (tail == NULL)

ERROR

old_tail = tail;

tail = ???

Page 14: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Singly-Linked Lists

● Removing from the tail:

if (tail == NULL)

ERROR

old_tail = tail;

tail = ???

● Problem: Can't access previous node

Page 15: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Singly-Linked Lists

● Removing from the tail:

if (tail == NULL)

ERROR

old_tail = tail;

tail = ???

● Problem: Can't access previous node

– This is a problem – you can't remove from the tail of asingly-linked list in O(1) operations!

– Solution: Track previous nodes as well (doubly-linked lists)

Page 16: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Challenge

● Given a singly-linked list called "foo", write asnippet of code that will print out all of thevalues in the list

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

} linknode_t;

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

} linklist_t;

Page 17: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Singly-Linked Lists

● Insert: O(1)

– if you have a reference to the location

– O(n) if the new location is index-based

● Delete: O(1)

– if you have a reference to the location

– O(n) if the location is index-based

– O(n) if you have to look for an item

● Indexed access or search: O(n)

Page 18: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Linked Stack

● Consider stack implementation using a singly-linked list

Page 19: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Linked Stack

● Consider stack implementation using a singly-linked list

– Insert and remove at the head

– Push, pop, and top are O(1)

Page 20: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Linked Queue

● Consider queue implementation using a singly-linked list

Page 21: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Linked Queue

● Consider queue implementation using a singly-linked list

– Insert at head, remove from tail● Can't remove from the tail!

– Insert at tail, remove from head● Enqueue, dequeue, and first are O(1)

Page 22: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Advanced Linked Lists

● What if tail->next pointed to the head?

– This is a "circularly-linked list"

● What if we kept two pointers per node?

– "next" and "prev"

– This is a "doubly-linked list"

● What if we kept multiple pointers to placesfurther down the list?

– This is a "skip list"

– (Much) more on this one in PA3!

Page 23: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

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

Page 24: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

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 ADT = “double-ended queue”

– Two sets of insert/remove methods:● addfirst and removefirst● addlast and removelast

Page 25: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Sentinels

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

2head tail

head tailEmpty list:

After addlast(2):

2 3head tailAfter addlast(3):

2 3 5head tailAfter addlast(5):

Page 26: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Sentinels

● Simplifies logic of insertion and removal

void list_addlast(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_addlast(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 5head tail

head tailEmpty list:

Populated list:

Page 27: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Tradeoffs

● Advantages of linked lists

– Worst-case O(1) bounds● No amortized bounds

– O(1) insertions/removals at arbitrary positions● No need to shift elements if we know where we want to

insert or remove● This is a HUGE advantage!

Page 28: Mike Lam, Professor · 2015-10-02 · Doubly-Linked Lists Two references: prev and next – To predecessor and successor nodes Allows insert and remove at both ends – Can now implement

Tradeoffs

● Advantages of arrays

– O(1) access to elements by index● This is a HUGE advantage!

– 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)