Linked Lists

advertisement
ICS 220 – Data Structures
and Algorithm Analysis
Dr. Ken Cosh
Week 3
Review
• Week 2
– Complexity Analysis
• Computational & Asymptotic Analysis
• Big-O Notation
• Properties of Big-O
– Big Ω and Big Θ
• Amortized Analysis
• NP-Complete Problems
This Week
• Our First Data Structure
– Linked Lists
•
•
•
•
•
•
Singly
Doubly
Circular
Skip Lists
Self Organising Lists
Sparse Tables
Linked Lists
• We came across linked lists in Computer
Programming II, this week we continue to
look at linked lists.
– Why to use linked lists?
– How to use linked lists?
– Different Types of linked list.
Arrays
• But first, lets review arrays.
– A very useful structure provided by
programming languages
– However, arrays have at least 2 limitations;
• The size has to be known at compilation.
• The data in the array are separated in the
computers memory by the same distance.
– These limitations make ‘inserting’ an item
inside the array difficult.
Linked Lists
• Linked Lists can be used to get around the
limitations of arrays by linking data
independently from where it is stored in
the computers memory.
• To create a linked list, each piece of data
in the set of data, simply has to also store
the address of the next piece of data in the
set.
A Simple Linked List
P
Data
Data
Data
Data
Data
0
Singly Linked Lists
• The example on the previous page was an
example of a singly linked list.
– A pointer (P) to the first element in the list
– Each element stores some data, and a pointer to the
next element in the list
– The final element points towards NULL (0), to indicate
it is the final element.
• The data stored in a linked list can be anything
from a simple integer to a user defined class.
Node Code
class Node {
public:
Node() {
next = 0;
}
Node(int i, Node *in=0) {
info = i; next = in;
}
int info;
Node *next;
};
• This basic node has an
integer (info), and a
pointer to the next node
in the linked list.
• There are 2 constructors,
– One for creating an empty
list, which points towards
NULL
– One for creating a new
node in a list, with info i,
again pointing towards
NULL
Creating a linked list of Node
Node *p = new Node(1);
• Creates a pointer ‘p’ pointing to a new dynamic
object of Node type
p->next = new Node(2);
• Creates the second node in the list.
p->next->next = new Node(3);
• Creates the third node in the list.
->next
• We need a way to avoid needing excessive and
error-prone use of;
…->next->next->next->next->next->next->next…
• So we need to add some useful member
functions, to perform tasks such as;
– Insertion
– Deletion
– Searching
Insertion
• For a basic Linked list, we have two
choices for insertion;
– head_insert()
– tail_insert()
• Otherwise known as;
– push_front()
– push_back()
head_insert
p
Step 1
Data
Step 2
p
Data
Data
Data
0
p
Data
Data
Data
0
Step 3
Data
0
p
Data
Step 4
Data
Data
0
tail_insert
• To insert a node at the end (tail) of a list,
we first need a pointer to the last node in
the list.
– It is often a good idea to maintain 2 pointers,
one to the head of a linked list, and one to the
tail of a linked list.
• Using the tail pointer, the steps are similar
to head_insert.
Deletion
• Deleting Nodes from a list is another important
function.
– Deleting from the head of the list
– Deleting from the tail of the list
– Deleting from somewhere in the middle of the list.
• For each it is important not to lose the list – i.e.
maintain a pointer to the rest of the list when
deleting the head node etc.
• Discuss how you would solve each function.
Considerations
• Will the code work in all of these cases?
– Attempting to delete a node from an empty
list.
– Deleting the only node from a one node list.
– Attempting to delete a node which isn’t in the
list.
Searching
• Searching a singly linked list involves
starting at the head and following the
pointers through the list until either the
node is found or the tail is reached.
• A temporary pointer is used, tmp, where at
each step it is pointed to the following
node, tmp->next.
Doubly Linked Lists
• The delete from tail function highlighted a
difficulty inherent in singly linked lists.
– In order to find the last element in a list, we
have to scan through the entire list till we find
the element pointing to NULL, we then have
to delete this element, while tracking the
previous element and pointing that to NULL.
• If we are dealing with a long list, or
frequent tail_delete function calls, it may
be useful to have a Doubly Linked List.
Doubly Linked List
Tail
Head
Data
Data
Data
0
0
Doubly Linked Lists
• The two key changing functions for Doubly
Linked are to add and delete from the tail
of a doubly linked list.
– Work through each of these functions taking
care not to lose the list.
Circular Linked Lists
• Another type of Linked List is a circular
linked list
– Here the final node in the list points back to
the first node.
– This can be useful for tracking things
continually in sequence
Doubly Circular Linked Lists
Tail
Data
Data
Data
Note that only one entry point (Tail) is required
Searching Inefficiency
• With the linked lists we have encountered
so far, there is a certain searching
inefficiency.
– If we want to find a particular node we have to
start at a position and work through every
node in the list until either we find the node
we are looking for, or we reach the end of the
list.
• Skip Lists were introduced to offer an
alternative searching structure.
Skip Lists
• In a Skip List, each node can have a
different number of pointers – some may
have 1, some have 2 etc.
• Using different pointers we can skip
different nodes in the list until we find the
element we are searching for.
Skip List
1
2
5
12
13
16
19
23
27
33
39
47
54
Suppose we were to search the above Skip List for the
number 17. Starting at the top level, with node #1 – we
reach node #27. Returning to the next level, we go from
node #1 to node #13 to node #27. Next the third level from
node #13 reaches node #19, and finally the fourth level is
nodes #13, #16, #19, so we can then tell that the node is not
in the list.
67
Skip Lists
• Skip Lists are efficient for searching,
assuming they are configured correctly.
• However, there are difficulties when it
comes to other functionality
– Adding or deleting a node from part way
through a skip list would demand a redesign
of the whole skip list to maintain efficiencies.
Arrays vs Linked Lists
• Linked Lists have the advantage over arrays as they
allow dynamic allocation of the necessary amount of
memory;
– Memory can be added or deleted at any point in a linked list
• Arrays have advantages over linked lists firstly because
they allow random access;
– We can access the 10th element in an array quicker than the 10th
element in a linked list.
• Arrays can also sometimes take up less memory;
– Linked lists can take up more space to store all the necessary
pointers
– Sometimes Arrays can waste memory if the array isn’t full
• So how would you choose between an array and a
linked list?
List Organisation
• Clearly a list which is better organised will be more
efficient than a disorganised list.
• Therefore there are ways to reorder the linked list to
maximise its efficiency.
– Items that are more likely to be searched for can be placed at the
start of the linked list, so they will be found first.
– Options include;
•
•
•
•
Move-To-Front
Transpose
Count
Ordering
– Amortised Cost Analysis can be used to predict which method
should be used.
List Organisation Methods
• Move-To-Front
– Each time a node is searched for it is moved to the head of the
list.
• Transpose
– Each time a node is searched, swap it with the previous node.
• Count
– Add a data element to each node, containing a count of the
number of times it has been accessed – then order the list by the
count.
• Ordering
– Use a natural criteria for list ordering, such as alphabetic order.
• The first 3 methods aim to self organise the list,
rearranging its order dynamically – new additions are
automatically tail_inserted.
<list>
• The Standard Template Library contains a
library called <list>, which contains many
of the functions we have discussed, and
more.
• The contents of the library are introduced
on page 111 of the course text.
• Take some time to familiarise yourselves
with the list library.
Deque
• A Deque is a double ended Queue – i.e. a
list which allows access to both ends of
the list, or a doubly linked list.
• The STL also contains a deque class,
which extends the functionality of the
<list> library.
• The <deque> class excludes some
functions from the list class, including the
merge function.
Homework
• As a gentle reintroduction to programming;
– Write a ‘merge’ function, which takes as
parameters pointers to the heads of two
deques.
– The function should merge the two deques
leaving the first list as a sorted version of both
lists.
– There are several ways this can be done!
Calculate big-O for your algorithm.
Download