|
|
|
|
|
|
Ordered List ADTs |
|
What are they |
|
Discuss two different interpretations of an
“ordered list” |
|
Are manipulated by “position” |
|
Use of Data Structures for Ordered Lists |
|
arrays (statically & dynamically allocated) |
|
linear linked lists |
|
|
|
|
|
|
|
Now that we have seen a simple list example, and
started to examine how we can use different data structures to solve the
same problem |
|
We will move on to examine an ordered list ADT |
|
implemented using a linear linked list, circular
linked list, linked list of linked lists, doubly linked lists, etc. |
|
|
|
|
|
So, what is an ordered list? |
|
Immediately, a sorted list comes to mind |
|
But...this isn’t the only definition! |
|
think of lists ordered by time, |
|
grocery lists? In the order you think about it |
|
to-do lists? In priority order... |
|
In fact, typically an ordered list is: |
|
ordered by “position” |
|
whereas a “sorted” list is a “value oriented
list”, this is a “position oriented list” |
|
|
|
|
|
But, an ordered list has many many different
interpretations |
|
We will discuss two: |
|
absolute lists |
|
relative lists |
|
Why? Well, there are a variety of
interpretations of where data is inserted and whether or not the list has
“holes” |
|
|
|
|
|
An absolute ordered list |
|
may have holes |
|
which means if the first data inserted is at
position 12, there are 11 holes (1-11) prior |
|
may “replace” data if inserted at the same
position (another insert at position 12 could replace the previously
inserted data at that position...it never shifts the data) |
|
similar to “forms” such as a tax form |
|
|
|
|
|
A relative ordered list |
|
may not have holes |
|
which means if the first data inserted is at
position 12, it would actually be inserted at the first position! |
|
may “shift” data if inserted at the same
position (another insert at position 1 would shift what had been at
position 1 -- now to be at position 2) |
|
similar to “editors” such as vi |
|
|
|
|
|
For an absolute ordered list, what are the
operations? |
|
insert, retrieve, remove, create, destroy,
display |
|
insert, retrieve, and remove would all require
the client program to supply a position number |
|
notice we are not inserting in sorted order, or
retrieving by a “value” |
|
instead we insert at an absolute position,
retrieve the data at that position, remove data at a given position --- not
affecting the rest of the list! |
|
|
|
|
|
For a relative ordered list, what are the
operations? (the same!) |
|
insert, retrieve, remove, create, destroy,
display |
|
insert, retrieve, and remove would all require
the client program to supply a position number |
|
instead we insert at a relative position,
retrieve the data at that position, remove data at a given position ---
this time affecting the rest of the list! |
|
A remove at position 1 would require every other
piece of data to shift down (logically) |
|
|
|
|
Notice what was interesting about the last two
slides |
|
The operations for a relative and absolute list
are the same |
|
One exception is that a relative list might also
have an “append” function |
|
And, an absolute list might restrict insert from
“replacing”, and add another function to specifically “replace” |
|
|
|
|
|
Therefore, the client interface for these two
interpretations might be identical! |
|
so...how would the application writer know which
type of list the ADT supports? |
|
Documentation! Critical whenever you implement a
list |
|
What does it mean to insert? Where? |
|
What implications does insert and remove have on
the rest of the data in the list? |
|
|
|
|
class ordered_list { |
|
public: |
|
ordered_list(); |
|
~ordered_list(); |
|
int insert(int, const data & ); |
|
int retrieve(int, data &); |
|
int display(); |
|
int remove(int); |
|
|
|
|
|
With the previous class public section |
|
the constructor might be changed to have an
integer argument if we were implementing this abstraction with an array |
|
the int return types for each member function
represent the “success/failure” situation; if more than two states are used
(to represent the error-code) ints are a good choice; otherwise, select a
bool return type |
|
|
|
|
|
Now let’s examine various data structures for an
ordered list and discuss the efficiency tradeoffs, based on: |
|
run-time performance |
|
memory usage |
|
We will examine: |
|
statically/dynamically allocated arrays |
|
linked lists (linear, circular, doubly) |
|
|
|
|
|
Statically Allocated array... |
|
private: |
|
data array[SIZE]; |
|
int number_of_items; |
|
Absolute lists: |
|
direct access (insert at pos12 : array[11] =
... |
|
remove only alters one element (resetting it?) |
|
problem: memory limitations (fixed size) |
|
problem: must “guess” at the SIZE at compile
time |
|
|
|
|
|
|
|
Relative lists: (statically allocated arrays) |
|
direct access for retrieve |
|
problem: searching! Insert might cause the data
to be inserted somewhere other than what the position specifies (i.e., if
the position # is greater than the next “open” position) |
|
problem: shifting! Remove, insert alters all
subsequent data |
|
problem: memory limitations (fixed size) |
|
problem: must “guess” at the SIZE at compile
time |
|
|
|
|
|
|
|
Dynamically Allocated array... |
|
private: |
|
data * array; |
|
int number_of_items; |
|
int size_of_array; |
|
Absolute lists: |
|
direct access (insert at pos12 : array[11] =
... |
|
remove only alters one element (resetting it?) |
|
problem: memory limitations (fixed size) |
|
|
|
|
|
|
|
Relative lists: (dynamically allocated arrays) |
|
direct access for retrieve |
|
problem: searching for the correct position for
insert |
|
problem: shifting with insert and remove |
|
problem: memory limitations (fixed size) |
|
|
|
|
|
|
|
What this tells us is that a dynamically
allocated list is better than a statically allocated list (one less
problem) |
|
if the cost of memory allocation for the array
is manageable at run-time. |
|
may not be reasonable if a large quantity of
instances of an ordered_list are formed |
|
is not required if the size of the data is known
up-front at compile time (and is the same for each instance of the class) |
|
|
|
|
|
|
|
|
We also should have noticed from the previous
discussion that... |
|
absolute ordered list are well suited for array
implementations, since they are truly direct access abstractions |
|
relative ordered list are rather poorly suited
for arrays, since they require that data be shifted |
|
therefore, hopefully the array consists of pointers
to our data, so that at least when we shift we are only moving pointers
rather than the actual data!! |
|
|
|
|
|
|
|
Linear Linked list... |
|
private: |
|
node * head; |
|
node * tail; //???helpful? |
|
Absolute lists:
(a poor choice) |
|
holes: how to deal with them? add a position
number to the contents of each node....don’t really allocate nodes for each
hole!!!! |
|
insert, retrieve, removal requires traversal |
|
how can a tail pointer help? if data is entered
in order by position! |
|
|
|
|
|
|
|
Relative lists: (linear linked lists) |
|
no holes -- so no extra position needed in each
node |
|
insert, retrieve, remove requires traversal |
|
a tail pointer assists if appending at the end |
|
no shifting!! |
|
So, while we still have to “search”, and the
search may be more expensive than with an array -- this is greatly improved
for a relative list, since there is not shifting!! |
|
|
|
|
|
|
Circular Linked list... |
|
private: |
|
node * head; |
|
node * tail; //???helpful? |
|
There is nothing in an ordered list that will
benefit from the last node pointing to the first node |
|
A circular linked list will require additional
code to manage, with no additional benefits |
|
|
|
|
|
|
Doubly Linked list... |
|
private: (each node has a node *
prev) |
|
node * head; |
|
node * tail; //???helpful? |
|
Again, there is nothing in an ordered list that
will benefit from each node having a pointer to the previous node. |
|
UNLESS, there were operations to backup or go
forward from the “current” position. In this case a doubly linked list
would be ideal |
|
|
|
|
|
|
|
What about a linked list of arrays |
|
where every n items are stored in the first
node, the next n items are stored in the second node, etc. |
|
This still requires traversal to get to the
right node, but then from there direct access can be used to insert,
retrieve, remove the data |
|
May be the best of both worlds for relative
lists, limiting the amount of shifting to “n” items while at the same time
keeping the traversal to a manageable level |
|
|
|
|
|
|
|
Are there other alternatives? |
|
How about an array of linked lists? |
|
How about “marking” data in a relative list as
“empty” to avoid shifting with an array?! |
|
Given the data structures discussed, which is
best and why for: |
|
absolute ordered list |
|
relative ordered list |
|
|
|
|
|
|
Now that we have applied data structures to an
ordered list |
|
We will move on to examine stack and queue
abstractions |
|
Again, we will examine them from the standpoint
of arrays, linked list, circular linked list, linked list of linked lists,
doubly linked lists, etc. beginning next time! |
|
|
|
|
|
|
Programming Assignment Discussion |
|