More Linking Up with Linked Lists

Download Report

Transcript More Linking Up with Linked Lists

Linked Lists
Gordon College
Prof. Brinton
1
Linked List Basics
•
Why use?
1. Efficient insertion or deletion into middle of list.
(Arrays are not efficient at doing this.)
2. Dynamic creation
•
Any drawbacks?
Yes, linked lists take up extra space - remember
the pointers.
2
The Linked List Node
• Contains 2 items:
– Payload for linked list entries
– Pointer(s) to surrounding links
class Node
{
public:
Node(int p) {next=NULL; item=p; };
int item;
Node* next;
};
Note: the node class can either be private within the Linked list class or it
can stand on its own.
3
Linked List Class
class LinkedList
{
public:
LinkedList() { first=NULL; mySize=0; };
const int size() {return mySize; };
void insert(int p, int pos );
void display(ostream & out);
void erase(int value);
private:
class Node
{
public:
Node(int p) {next=NULL; item=p; };
int item;
Node* next;
};
int mySize;
Node * first;
};
4
Inserting a new node
Steps:
1. Find location within list
2. Create new node with payload and pointer to
current node’s next
3. Assign address of new node to current node’s
next
Note: order is essential
5
Inserting a new node
• Exception cases: begin and end of list
Begin Case:
1. Create new node
2. Assign address found in first to current node’s next
3. Place address of new node in first
End case:
1. Create new node
2. Put NULL in new node’s next
3. Assign address of new node to next of last node
6
Deleting a node
Steps
1. Find the node to delete (keep finger on
previous node)
2. Assign next address in previous node to
next address of node to delete
3. Delete current node
7
Deleting a node
Exception cases: begin and end of list
Begin:
1. Assign address of current next to first
2. Delete current node
End:
1. Place NULL in previous node’s next
2. Delete current node
8
Order of Magnitude
How many operations does it take?
1. Inserting at front of list - O(1)
2. Deleting at front of list - O(1)
3. Inserting at the back of list - O(n)
4. Deleting at the back of list - O(n)
What happens if we add a pointer called Back that points to the last node?
Inserting at the back of the list is now O(1)
How about deleting at the back?
9
Order of Magnitude
•
The list is still a Singly Linked List. In order to
delete at the end of a list, we still must have a
pointer to the predecessor to back.
Therefore O(n):
1. Walk to the end of the list (keep finger on
previous node)
2. Assign next address in previous node to NULL
3. Delete current node
10
Singly LL with back pointer
• Problems:
– Insert on an empty list - must update both
pointers
– Erase on one node - must update both pointers
11
Doubly Linked Lists
• New Node structure:
class Node
{
public:
Node(int p) { next=NULL; prev=NULL; item=p; };
int item;
Node* prev;
Node* next;
};
12
Doubly Linked Lists
Inserting a node at a position
1. Find place to insert: current node
2. Set new node’s prev pointer to current
node’s prev pointer
3. Set new node’s next pointer to current
node
4. Set previous node’s next to new pointer
5. Set current node’s previous to new node
13
Doubly Linked Lists
Removing a node at a position
1. Find node to remove: current node
2. Set previous node’s next to current’s next
3. Set next node’s (successor) prev to
current node’s prev
4. Delete current
14
Doubly Linked Lists
Exceptions: first and last node.
Order of Magnitude:
O(1) insert and remove at either end.
Note: also search time can be quicker if you
know which end to begin searching.
15
What’s a Head Node?
• Consider simple linked lists
– First node is different from others
– Only node that is directly accessible
– Has no predecessor
• Thus insertions and deletions must consider
two cases
– First node or not first node
– The algorithm is different for each
16
Linked Lists with Head Nodes
• Dual algorithms can be reduced to one
– Create a "dummy" head node
– Serves as predecessor holding actual first
element
• Thus even an empty list
has a head node
17
Linked Lists with Head Nodes
• For insertion at beginning of list
– Head node is predecessor for new node
newptr->next = predptr->next;
predptr->next = newptr;
18
Linked Lists with Head Nodes
• For deleting first element from a list with a
head node
– Head node is the predecessor
predptr->next = ptr->next;
delete ptr;
19
Circular Linked Lists
• Set the link in last node to point to first node
– Each node now has both predecessor and
successor
– Insertions, deletions now easier
• Special consideration required
for insertion to empty list,
deletion from single item list
20
Circular Linked Lists
• Traversal algorithm must be adjusted:
if (first != NULL) // list not empty
{ ptr = first;
do
{ // process ptr->data
ptr = ptr->next; }
while (ptr != first);
}
• How must this be different?
21
Circular
Linked Lists
Traversal
if (first!=NULL)
{
ptr = first;
//process ptr->data
ptr = ptr->next;
while (ptr != first)
{
//process ptr->data
ptr = ptr->next;
}
}
if (first!=NULL)
{
ptr = first;
do
{
//process ptr->data
ptr = ptr->next;
}
while (ptr != first);
}
22
Circular
Linked Lists
Traversal
with Head Node
ptr = first->next;
while (ptr != first)
{
//process ptr->data
ptr = ptr->next;
}
23
Polynomial Representation
x2 - 4x + 7
• Consider a polynomial of degree n
– Can be represented by an array
• For a sparse polynomial this is not efficient
5
24
Polynomial Representation
x2 - 4x + 7
• We could represent a polynomial by a list of
ordered pairs
– { (coef, exponent) … }
• Fixed capacity of
array still problematic
– Wasted space for
sparse polynomial
25
Linked Implementation of
Sparse Polynomials
• Linked list of these ordered pairs provides an
appropriate solution
– Each node has form shown
• Now whether sparse or well populated, the
polynomial is represented efficiently (with head
nodes)
26
Linked Implementation of
Sparse Polynomials
How would this class look?
27
Linked Implementation of Sparse Polynomials
class Polynomial
{
public:
Polynomial() { first=NULL; mySize=0; };
const int size() {return mySize; };
void insert(int p, int pos );
void display(ostream & out);
void erase(int value);
private:
class Term
{
public:
int coef;
unsigned expo; };
class Node
{
public:
Node(int co, int ex) {next=NULL; data.coef=co; data.expo = ex; };
Term Data;
Node* next;
};
…
};
28
Addition Operator
• Requires temporary pointers for each
polynomial (the addends and the resulting
sum)
29
Addition Operator
• As traversal takes place
– Compare exponents
– If different, node with smaller exponent and its coefficient
attached to result polynomial
– If exponents same, coefficients added, new
corresponding node attached to result polynomial
30
Doubly-Linked Lists
• Bidirectional lists
– Nodes have data part,
forward and backward link
• Facilitates both forward and backward
traversal
– Requires pointers to both first and last nodes
31
Doubly-Linked Lists
• To insert a new node
– Set forward and backward links to point to
predecessor and successor
32
Doubly-Linked Lists
• To insert a new node
– Set forward and backward links to point to
predecessor and successor
– Then reset forward link of predecessor,
backward link of successor
33
Doubly-Linked Lists
• To delete a node
– Reset forward link of predecessor, backward link
of successor
– Then delete removed node
34
The STL list<T> Class Template
• A sequential container
– Optimized for insertion and erasure at arbitrary
points in the sequence.
– Implemented as a circular doubly-linked list with
head node.
35
Comparing List<t> With Other Containers
Property
Array
vector<T> deque<T> list<T>
Direct/random access ([])
+ (exclnt) +
 (good)
X
Sequential access
+
+

+
Insert/delete at front
-(poor)
-
+
+
Insert/delete at end
+
+
+
+
Insert/delete in middle
-
-
-
+
Overhead
lowest
low
low/medium
high
• Note : list<T> does not support direct access
– does not have the subscript operator [ ].
36
list<t> Iterators
• list<T>'s iterator is "weaker" than that for
vector<T>.
 vector<T>:
random access iterators
 list<T>:
bidirectional iterators
• Operations in common
 ++
Move iterator to next element
(like ptr = ptr-> next)
 --
Move iterator to preceding element
(like ptr = ptr-> prev)
 *
dereferencing operator
(like ptr-> data)
37
list<t> Iterators
• Operators in common
=
assignment
(for same type iterators)
it1 = it2 makes it1 positioned at
same element as it2
 == and !=
(for same type iterators)
checks whether iterators are positioned at
the same element
38
Example: Internet Addresses
• Consider a program that stores IP addresses
of users who make a connection with a
certain computer
– We store the connections in an
AddressCounter object
– Tracks unique IP addresses and how many
times that IP connected
39
The STL list<T> Class Template
Node structure
struct list_node
{ pointer next,
prev;
T data;
}
40
The STL list<T> Class Template
• But it's allocation/deallocation scheme is
complex
– Does not simply use new and delete
operations.
• Using the heap manager is inefficient for
large numbers of allocation/deallocations
– Thus it does it's own memory management.
41
The STL list<T> Memory Management
When a node is allocated
1. If there is a node on the free list, allocate it.
•
This is maintained as a linked stack
2. If the free list is empty:
a) Call the heap manager to allocate a block of
memory (a "buffer", typically 4K)
b) Carve it up into pieces of size required for a
node of a list<T>.
42
The STL list<T> Memory Management
• When a node is deallocated
– Push it onto the free list.
• When all lists of this type T have been
destroyed
– Return it to the heap
43
Case Study: Large-Integer
Arithmetic
• Recall that numeric representation of
numbers in computer memory places limits
on their size
– 32 bit integers, two's complement max
2147483647
• We will design a BigInt class
– Process integers of any size
– For simplicity, nonnegative integers only
44
BigInt Design
• First step : select a storage structure
– We choose a linked list
– Each node sores a block of up to 3 consecutive
digits
– Doubly linked list for traversing in both directions
45
BigInt Design
• Input in blocks of 3 integers, separated by
spaces
– As each new block entered, node added at end
• Output is traversal, left to right
46
BigInt Design
• Addition adds the groupings right to left
– Keeping track of carry digits
47
Multiply-Ordered Lists
• Ordered linked list
– Nodes arranged so data items are in
ascending/descending order
• Straightforward when based on one data
field
– However, sometimes necessary to maintain links
with a different ordering
• Possible solution
– Separate ordered linked lists – but wastes space
48
Multiply-Ordered Lists
• Better approach
– Single list
– Multiple links
49
Sparse Matrices
• Usual storage is 2D array or 2D vector
• If only a few nonzero entries
– Can waste space
• Stored more efficiently with linked structure
– Similar to sparse polynomials
– Each row is a linked list
– Store only nonzero entries for the row
50
Sparse Matrices
• For
A=
we represent with
51
Sparse Matrices
• This still may waste space
– Consider if many rows were all zeros
• Alternative implementation
– Single linked list
– Each node has row, column,
entry, link
• Resulting list
52
Sparse Matrices
• However … this loses direct access to rows
• Could replace array of pointers with
– Linked list of row head nodes
– Each contains pointer to non empty row list
53
Sparse Matrices
• If columnwise processing is desired
– Use orthogonal list
– Each node stores row, column, value, pointer to
row successor, pointer to column successor
54
Sparse Matrices
• Note the resulting
representation of
the matrix
A=
55
Generalized Lists
• Examples so far have had atomic elements
– The nodes are not themselves lists
• Consider a linked list of strings
– The strings themselves can be linked lists of
characters
This is an
example of a
generalized list
56
Generalized Lists
• Commonly represented as linked lists where
– Nodes have a tag field along with data and link
• Tag used to indicate whether data field holds
– Atom
– Pointer
to a list
57
Generalized Lists
• Lists can be
shared
– To represent
(2, (4,6), (4,6))
• For polynomials in two variables
P(x,y) = 3 + 7x + 14y2 + 25y7 – 7x2y7 + 18x6y7
58