Title: Static Array
1Chapter 4 Linked Lists
Recall that linked lists enable us to dynamically
adjust the size of a list, eliminating the need
to preallocate a specific amount of memory.
Static Array
Dynamic Array
Linked List
Preallocation Required! Wasteful if you allocate
too much! Potentially fatal if you allocate too
little!
Determine the size of the list before allocating
memory! Not dynamic enough you cant change the
size once its been decided!
Completely dynamic! No space is wasted due to
excess allocation! Additional space is allocated
as needed!
2Lets review linked lists with a little example
that also refreshes our memory (so to speak)
about recursion.
In this example, were going to read text from an
input file, keeping track of how many times each
word is used in the text.
Each node in the linked list will require a
string field (to hold the word), an integer field
(to hold the count), and a pointer field (to
point to the next node).
string word
ptr next
int count
3When a word is inserted in the list, the list is
traversed to see if the words already there...
groovy
If the word is found, its node is removed, its
count is incremented, and the node is reinserted
to preserve the count/alphabetical ordering...
oops
If the word isnt found, a new node is created
with a count of one, and inserted appropriately...
4Desired linked list functionality
Default Constructor
Copy Constructor
Destructor
Make an empty list
Make a deep copy list
Delete all list nodes
INSERT member function
RETRIEVE member function
GETNODE member function
Insert a new(?) word
Find a words count
Create word/count node
Input (gtgt) friend operator
Output (ltlt) friend operator
Read a text file
Write word/count list
Recursive Find function
Recursive Insert function
Recursive Output function
Unpunctuate upper-case function
Find a word
Insert a word
Write a word/count
Edit a word
5///////////////////////////////////////// //
Class definition file linkedList.h // //
// // Each node in a
LinkedList will have // // two components an
elementType (a // // string representing a word
and an // // integer counting that word's
number // // of occurrences) and a pointer to
// // the next node in the LinkedList.
// ///////////////////////////////////////// ifnd
ef LINKED_LIST_H include ltstringgt using
namespace std struct elementType string
word int count struct node typedef node
nodePtr struct node elementType item
nodePtr next class LinkedList public
// Constructors and destructor LinkedList()
LinkedList(const LinkedList list)
LinkedList() // Member functions bool
insert(string str) int retrieve(string
str) friend istream operator gtgt
(istream sourceFile, LinkedList
list) friend ostream operator ltlt
(ostream destFile, const LinkedList
list) private // Data member nodePtr
head // Member function nodePtr
getNode(string str, int ct) void
recursiveOutput(ostream outputFile,
nodePtr ptr) nodePtr recursiveInsertPrep
(string str, nodePtr
prevPtr, nodePtr
currPtr) void recursiveInsert(nodePtr newPtr,
nodePtr prevPtr,
nodePtr currPtr) void
unpunctuate(string str) define
LINKED_LIST_H endif
6/////////////////////////////////////////////// //
Class implementation file linkedList.cpp // //
// // In
addition to standard constructor and // //
destructor members, the LinkedList class // //
has members for inserting a word into the // //
list and determining a particular word's // //
count. Friend input and output operators // //
are also included. Non-member functions // //
for enacting recursive output, insertion, // //
and search have been implemented, as well // //
as a function for removing punctuation // //
from the beginning and ending of a word, // //
and converting what's left to upper case.
// ///////////////////////////////////////////////
include "linkedList.h" include
ltiomanipgt include ltcassertgt using namespace
std // Default Constructor Sets // // up empty
LinkedList. // LinkedListLinkedList()
head NULL // Copy Constructor Makes deep
copy // // of the parameterized LinkedList.
// LinkedListLinkedList(const LinkedList
list) nodePtr currPtr, thisCurrPtr,
thisPrevPtr
if (list.head NULL) head NULL else
head getNode(list.head-gtitem.word,
list.head-gtitem.count)
thisPrevPtr head currPtr
list.head-gtnext while (currPtr ! NULL)
thisCurrPtr getNode(currPtr-gtitem.word,
currPtr-gtitem.count)
thisPrevPtr-gtnext thisCurrPtr
thisPrevPtr thisCurrPtr currPtr
currPtr-gtnext // Destructor
Deletes every // // node in LinkedList.
// LinkedListLinkedList() nodePtr
currPtr while (head ! NULL) currPtr
head head head-gtnext currPtr-gtnext
NULL delete currPtr
7// Member Function insert // //
// // This function
searches the // // LinkedList for the
parameterized // // word, removing the
corresponding // // node and incrementing its
count // // if it's found. Otherwise, a new
// // node is created containing the // // word
with a count of one. In // // any case, the
function inserts // // the node into the list
so that // // the words are sorted primarily
// // by their count, and then in // //
alphabetical order. A boolean // // is
returned, based on the // // insertion's
success. // bool LinkedListinsert(st
ring str) nodePtr insertPtr
recursiveInsertPrep(str, NULL, head) if
(insertPtr NULL) return false
recursiveInsert(insertPtr,
NULL, head) return true
// Member Function retrieve // //
// // This function
locates the // // parameterized string in
the // // LinkedList, returning the
// // corresponding count for that // // word.
Zero is returned if the // // string isn't
found in the list. // int LinkedListretrieve(str
ing str) nodePtr currPtr head while
(currPtr ! NULL) if (currPtr-gtitem.word
str) return currPtr-gtitem.count
else currPtr currPtr-gtnext return
0
8ostream operator ltlt (ostream destFile,
const LinkedList list)
recursiveOutput(destFile, list.head) return
destFile // Member Function getNode
// // // //
This function creates and returns // // a new
nodePtr, pointing to a node // // with the
parameterized string as // // its item's word,
the parameterized // // integer as its items
count, and // // NULL as its next pointer.
// nodePtr LinkedListgetNode(string str,
int ct) nodePtr
temp new node if (temp ! NULL)
temp-gtitem.word str temp-gtitem.count
ct temp-gtnext NULL return temp
// Friend Input Operator gtgt // //
// // The input
operator reads strings // // from the
parameterized input stream, // // strips off all
unnecessary punctua- // // tion, and inserts
them into the // // parameterized
LinkedList, until the // // input stream has
been depleted. // istream operator gtgt
(istream sourceFile, LinkedList
list) string nextWord sourceFile gtgt
nextWord while (!sourceFile.eof())
unpunctuate(nextWord) list.insert(nextWord)
sourceFile gtgt nextWord return
sourceFile // Friend Output Operator ltlt
// // // //
The output operator outputs the // // values
values in the LinkedList, // // each on a
separate output line in // // the parameterized
output stream, // // starting with the head
element. //
9nodePtr recursiveInsertPrep(string str,
nodePtr prevPtr,nodePtr currPtr) nodePtr
temp if (currPtr NULL) temp new
node if (temp ! NULL)
temp-gtitem.word str temp-gtitem.count
1 temp-gtnext NULL return
temp else if (currPtr-gtitem.word str)
temp currPtr if (prevPtr NULL)
currPtr currPtr-gtnext else
prevPtr-gtnext currPtr-gtnext
temp-gtitem.count temp-gtnext NULL
return temp else return
recursiveInsertPrep(str, currPtr,
currPtr-gtnext)
// Non-Member Function recursiveOutput
// //
// // This function recursively outputs the word
// // counts to the parameterized output file,
// // beginning with the node pointed to by the
// // parameterized pointer, and traversing to
// // the tail of the (implicit) linked list.
// void recursiveOutput(ostream outputFile,
nodePtr ptr) if (ptr !
NULL) outputFile ltlt setw(20) ltlt
ptr-gtitem.word ltlt " (" ltlt ptr-gtitem.count
ltlt ")" ltlt endl recursiveOutput(outputFile,
ptr-gtnext) return // Non-Member
Function recursiveInsertPrep // //
Prepares list for insertion. // This function
recursively locates the para- // // meterized
word in the (implicit) linked list // //
starting at the node to which the currPtr
// // pointer is pointing. The prevPtr pointer
is // // assumed to point to currPtr's
predecessor in // // the list. If the desired
string is located, // // its node is delinked
from the list and its // // count is
incremented by one. If the entire // // list
is searched without success, then a new // //
node containing the word (and a count of one)
// // is created. In either case, a pointer to
the // // node containing the desired word is
returned. //
10// Non-Member Function unpunctuate // //
// // This
function removes all non-alpha- // // numeric
characters from the beginning // // and ending
of the parameterized string, // // and then
converts what's left of the // // string into
upper-case. // void
unpunctuate(string str) const string
ALPHANUMERIC (string)"ABCDEFGHIJKLMNOPQRSTUVW
XYZ" (string)"abcdefghijklmnopqrstuvwxyz"
(string)"0123456789" while
(str.find_first_not_of(ALPHANUMERIC)
0) str str.substr(1,str.size()-1)
while ((str.size() gt 0)
(str.find_last_of(ALPHANUMERIC) lt
str.size()-1)) str str.substr(0,str.size()-1
) for (int i 0 i lt str.size() i)
stri toupper(stri)
// Non-Member Function recursiveInsert
// //
// // This function recursively traverses the
list // // until the currPtr parameter points to
the // // node whose contents should occur
right after // // the contents of the node to
which newPtr is // // pointing. Once this
occurs, the newPtr node // // is inserted between
currPtr's node and its // // predecessor (to
which prevPtr is pointing). // void
recursiveInsert(nodePtr newPtr,
nodePtr prevPtr, nodePtr
currPtr) if ((currPtr ! NULL)
((currPtr-gtitem.count gt newPtr-gtitem.count)
((currPtr-gtitem.count newPtr-gtitem.count)
(currPtr-gtitem.word lt newPtr-gtitem.word))))
recursiveInsert(newPtr,currPtr,currPtr-gtnext)
else if (prevPtr NULL) newPtr-gtnext
currPtr currPtr newPtr else if
(currPtr NULL) prevPtr-gtnext newPtr
else newPtr-gtnext currPtr
prevPtr-gtnext newPtr
11//////////////////////////////////////////////////
// WordCountDriver.cpp
// //
// // Driver program to test the LinkedList
class. // ////////////////////////////////////////
////////// include ltiostreamgt include
ltfstreamgt include ltstringgt include
"linkedList.h" using namespace
std ////////////////////////////////////////////
////////////////////////////////////// // The
main function uses text from a hard-coded input
file to create a linked // // list of the
distinct words in that file and how many times
each word occurs. // // The function then outputs
that list to a hard-coded output file.
// //////////////////////////////////////////////
//////////////////////////////////// void
main() LinkedList wordCountList ifstream
stringFile ofstream resultFile
stringFile.open("essay.txt")
resultFile.open("count.txt") stringFile gtgt
wordCountList resultFile ltlt wordCountList ltlt
endl return
12IBM announced today that researchers are testing
the Linux operating system on a prototype
wristwatch device in an attempt to prove that
Linux can be used as the basic software on even
the smallest devices. Designed to communicate
wirelessly with PCs, cell phones and other
wireless-enabled devices, the smart watch will
have the ability to view condensed e-mail
messages and directly receive pager-like
messages, IBM said in a statement. However, IBM
does not have plans to commercialize the Linux
watch itself, a spokeswoman said. This is just
a research prototype, said Takako Yamakura.
Some say Linux cannot be scaled down. This is
just to show Linux is capable of doing
this. The Linux operating system is seen as an
alternative to Microsoft Corp.s Windows
operating system, and is popular with programmers
for its open source code, which allows
programmers to develop and tinker with
programs. Several benefits accrue from the use
of Linux in small pervasive devices, IBM said in
the statement. The availability of source code
and a well-understood application programming
environment makes it easy for students,
researchers, and software companies to add new
features and develop applications. Linux, which
was developed by Finnish programmer Linus
Torvalds, is used for many basic functions of Web
sites, but is not yet considered mature enough
for heavier business tasks. IBM has been working
to develop the system for everything from the
wrist watch to supercomputers. With Linux
rapidly becoming an industry standard, its
important that developers be able to create new
applications across all platforms, including
pervasive devices, and the intent of IBMs
research is to further that work, IBM said.
Input File "essay.txt"
13 THE (13) TO
(12) LINUX (9)
AND (8) IS (8)
IBM (6) A (5)
FOR (5) OF (5)
DEVICES (4) IN (4)
SAID (4) SYSTEM (4)
THAT (4) WITH (4)
AN (3) BE (3)
DEVELOP (3) OPERATING (3)
THIS (3) WATCH (3)
APPLICATIONS (2) AS (2)
BASIC (2) CODE (2)
FROM (2) HAVE (2)
JUST (2) MESSAGES (2)
NEW (2) NOT (2)
ON (2) PERVASIVE (2)
PROGRAMMERS (2) PROTOTYPE (2)
RESEARCH (2) RESEARCHERS (2)
SOFTWARE (2) SOURCE (2)
STATEMENT (2) USED
(2) WHICH (2) ABILITY
(1) ABLE (1) ACCRUE
(1) ACROSS (1) ADD
(1) ALL (1) ALLOWS
(1) ALTERNATIVE (1) ANNOUNCED
(1) APPLICATION (1) ARE
(1) ATTEMPT (1) AVAILABILITY
(1) BECOMING (1) BEEN
(1) BENEFITS (1) BUSINESS
(1) BUT (1) BY
(1) CAN (1) CANNOT
(1) CAPABLE (1) CELL
(1) COMMERCIALIZE (1) COMMUNICATE
(1) COMPANIES (1) CONDENSED
(1) CONSIDERED (1) CORP.S
(1) CREATE (1) DESIGNED
(1) DEVELOPED (1) DEVELOPERS
(1) DEVICE (1) DIRECTLY
(1) DOES (1)
DOING (1) DOWN
(1) E-MAIL (1) EASY
(1) ENOUGH (1) ENVIRONMENT
(1) EVEN (1) EVERYTHING
(1) FEATURES (1) FINNISH
(1) FUNCTIONS (1) FURTHER
(1) HAS (1) HEAVIER
(1) HOWEVER (1) IBMS
(1) IMPORTANT (1) INCLUDING
(1) INDUSTRY (1) INTENT
(1) IT (1) ITS
(1) ITSELF (1) ITS
(1) LINUS (1) MAKES
(1) MANY (1) MATURE
(1) MICROSOFT (1) OPEN
(1) OTHER (1) PAGER-LIKE
(1) PCS (1) PHONES
(1) PLANS (1) PLATFORMS
(1) POPULAR (1) PROGRAMMER
(1) PROGRAMMING (1)
PROGRAMS (1) PROVE
(1) RAPIDLY (1) RECEIVE
(1) SAY (1) SCALED
(1) SEEN (1) SEVERAL
(1) SHOW (1) SITES
(1) SMALL (1) SMALLEST
(1) SMART (1) SOME
(1) SPOKESWOMAN (1) STANDARD
(1) STUDENTS (1) SUPERCOMPUTERS
(1) TAKAKO (1) TASKS
(1) TESTING (1) TINKER
(1) TODAY (1) TORVALDS
(1) USE (1) VIEW
(1) WAS (1) WEB
(1) WELL-UNDERSTOOD (1) WILL
(1) WINDOWS (1) WIRELESS-ENABLED
(1) WIRELESSLY (1) WORK
(1) WORKING (1) WRIST
(1) WRISTWATCH (1) YAMAKURA
(1) YET (1)
Output File "count.txt"
14Standard Linked Lists
- List has definite beginning and end.
- NULL pointer used to indicate empty list.
- Head and tail must be treated as special cases.
- Complicated previous pointer needed for
insertion and removal.
Circular Linked Lists
- Nice for applications requiring cycling through
list. - Pointer used to keep track of current position
in list.
- No actual head or tail in list, so watch out
for infinite loops! - Previous pointer still needed for insertion
and removal.
15Dummy Head Node Linked Lists
- Dummy head node always exists, no special head
case. - Head nodes next pointer is NULL when list is
empty.
- Wasteful use of node its data field is
usually vacuous. - Previous pointer still needed for insertion
and removal.
Doubly Linked Lists
- Eliminates need for keeping track of previous
node during traversal. - Improves efficiency when used with circularity
dummy head node.
- Rather complex maintenance of predecessor
successor pointers. - Like all of the linked list variations, linear
search is inefficient!
16Skip Lists
One possibility for improving the efficiency of
list traversals is the idea of a skip list.
Assume that the values of the data held in the
list are evenly distributed between some value ?
and some value ?, and assume that there will be
approximately N values in the list.
Each node has a data field and an array of at
most n next pointers, where n is ?log2 N?.
When a new value is inserted, randomly assign it
k next pointers in such a way that half of the
time, the node gets 1 next pointer, a quarter
of the time it gets 2 next pointers, and so on
up to (1/2n-1)th of the time it gets either n-1
or n pointers.
Yes, its pretty complicated, but it essentially
enables you to search a linked list in
logarithmic time (rather than that awful linear
time)!.