2 Lists
2.1 Sequences as Arrays and Lists
Many terms for same thing: sequence, field, list, stack, string, file… Yes, files are simply sequences of bytes!
three views on lists:
- abstract: \((2, 3, 5, 7)\)
- functionality: stack, queue, etc… What operations does it support?
- representation: How is the list represented in a given programming model/language/paradigm?
2.2 Applications of Lists
- Storing and processing any kinds of data
- Concrete representation of abstract data types such as: set, graph, etc…
2.3 Linked and Doubly Linked Lists
simply linked | doubly linked | |
---|---|---|
lecture | SList |
List |
c++ | std::forward_list |
std::list |
Doubly linked lists are usually simpler and require “only” double the space at most. Therefore their use is more widespread.
List Items
Class Item of T :=
e: T //Data item of type T
next: *Item //Pointer to Item
prev: *Item //Pointer to Item invariant next->prev = this = prev->next
Problem: * predeccessor of first list element? * successor of last list element?
Solution: Dummy Item with an empty data field as follows:
Advatanges of this solution:
- Invariant is always satisfied
- Exceptions are avoided, thus making the coding more:
- simple
- readable
- faster
- elegant
Disadvantages: a little more storage space.
The List Class
Class List of T :=
dummy := (
Null : T
&dummy : *T // initially list is empty, therefore next points to the dummy itself
&dummy : *T // initially list is empty, therefore prev points to the dummy itself
) : Item
// returns the address of the dummy, which represents the head of the list
Function head() : *Item :=
return address of dummy
// simple access functions
// returns true iff list empty
Function is_empty() : Bool :=
return dummy.next == dummy
// returns pointer to first Item of the list, given list is not empty
Function first() : *Item :=
assert (not is_empty())
return dummy.next
// returns pointer to last Item of the list, given list is not empty
Function last() : *Item :=
assert (not is_empty())
return dummy.prev
/* Splice is an all-purpose tool to cut out parts from a list
Cut out (a, ... b) form this list and insert after t */
Procedure splice(a, b, t : *Item) :=
assert (
b is not before a
and
t not between a and b
)
// Cut out (a, ... , b)
a->prev->next := b->next
b->next->prev := a->prev
// insert (a, ... b) after t
t->next->prev := b
b->next := t->next
t->next := a
a->prev := t
// Moving items by utilising splice
//Move item a after item b
Procedure move_after(a, b: *Item) :=
splice(a, a, b)
// Move item a to the front of the list
Procedure move_to_front(a: *Item) :=
move_after(a, dummy)
Procedure move_to_back(a: *Item) :=
move_after(b, last())
// Deleting items by moving them to a global freeList
// remove item a
Procedure remove(a: *Item) :=
move_after(b, freeList.dummy)
// remove first item
Procedure pop_front() :=
remove(first())
//remove last item
Procedure pop_back() :=
remove(last())
// Inserting Elements
// Insert an item with value x after item a
Function insert_after(x : T, a : *Item) : *Item :=
checkFreeList() //make sure freeList is non empty
b := freeList.first() // obtain an item b to hold x
move_after(b, a) // insert b after a
b->e := x // set the data item value of b to x
return b
// Manipulating whole lists
Procedure concat(L : List) :=
splice(L.first(), L.last(), last()) //move whole of L after last element of this list
Procedure clear()
freeList.concat(this) //after this operation from from first to last element of this
// list are concatenated to the freeList, leaving only the
// dummy element in this list.
Fuction get(i )
Splicing
The code for splicing of the List
class:
/* Splice is an all-purpose tool to cut out parts from a list
Cut out (a, ... b) form this list and insert after t */
Procedure splice(a, b, t : *Item) :=
assert (
b is not before a
and
t not between a and b
)
// Cut out (a, ... , b)
a->prev->next := b->next
b->next->prev := a->prev
// insert (a, ... b) after t
t->next->prev := b
b->next := t->next
t->next := a a->prev := t
- Dlist cut-out \((a,...,b)\) (see Figure 2.1):
- Dlist insert \((a,...,b)\) after \(t\) (see Figure 2.2):
Speicherverwaltung ./.FreeList
Methods (?):
- Niavely: allocate memory for each new element, deallocate memory after deleting each element:
- advantage: simplicity
- disadvantage: requires a good implementation of memory management: potentially very slow
- “global”
freeList
(e.g.static
member in C++)- doubly linked list of all not used elements
- transfer ‘deleted’ elements in
freeList
. checkFreeList
allocates, in case the list is empty
Real implementations: * naiv but with well implemented, efficient memory management * refined Free List Approach (class-agnostic, release) * implementation-specific.
Deleting Elements
Deleting elements realised by moving them to the global freeList
:
Procedure remove(a: *Item) :=
move_after(a, freeList.dummy) // item a is now a 'free' item.
Procedure pop_front() :=
remove(first())
Procedure pop_back() := remove(last())
Inserting Elements
Inserting elements into a list \(l\) also utilizes freeList
, by fetching its first element an moving it into \(l\).
Function insert_after(x : T, a : *Item) : *Item :=
checkFreeList() //make sure freeList is non empty
b := freeList.first() // obtain an item b to hold x
move_after(b, a) // insert b after a
b->e := x // set the data item value of b to x
return b
Function insert_before(x : T, b : *Item) : *Item :=
return insert_after(x, b->prev)
Procedure push_front(x : T) :=
insert_after(x, dummy)
Procedure push_back(x : T) := insert_after(x, last())
Manipulating whole Lists
// Manipulating whole lists
Procedure concat(L : List) :=
splice(L.first(), L.last(), last()) //move whole of L after last element of this list
Procedure clear()
freeList.concat(this) //after this operation from from first to last element of this
// list are concatenated to the freeList, leaving only the // dummy element in this list.
This operations require constant time - indeendent of the list size!