Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Linked Lists: Data Structures and Algorithms I

Download as pdf or txt
Download as pdf or txt
You are on page 1of 26

Linked Lists

Data Structures and Algorithms I


Dr. Tim Margush University of Akron

The Concept
Sequentially related information can be stored in non-sequential storage locations
List Nodes are the containers that hold the information

Links are stored with the information to determine the location of the next item
Links are usually array subscripts or pointers

The position of the first item is stored separately

Where are the Nodes


Stored in an Array
Array subscripts represent the location of a node Links are simply ints (subscript values)

Dynamically Allocated (from heap)


Node locations are actual addresses Links are pointers to nodes (Node *)

Linked Lists in an Array


An array of Nodes (Node store[MAX];) provides storage for the linked list
class Node contains members data and

next

In this example, the first node in the list is at 3 first 3 List contents: 1092, 9873, 198, 983,
40932, 76

sub 0 1 2 3 4 5

data 198 40932 983 1092 76 9873

next 2 4 1 5 End -1 of list 0

Dynamic Linked Lists


A pointer to a Node Node * head; (Node * head;) provides access to the 4357 first item in the list
class Node contains members data and 76 10956

9822
NULL pointer

next

126

Head
List contents: 10956, 76, 4357, 9822, 126

Self-Referential Structures
A struct or class that contains a member that refers to another object of the same type
Note: class X cannot have a member of type X, but it can have a member of type X* or X& class Node{ ITEM_TYPE data; Node * next; }

Each Node object contains a pointer that can contain the address of another Node object

Array or Dynamic?
Array Implementation User manages free store (in the array)
but more code Array size limits storage

Dynamic Implementation System manages free store (via new and delete) More efficient (faster),
Easy to use Storage is limited only by heap size

Array takes storage Storage used even if not completely proportional to used number of nodes

A Typical (Dynamic) Node Class


#define E_TYPE Fraction class Node{ public: Node(const E_TYPE &, Node * = NULL); E_TYPE & getData(); Node * getNext() const; void setNext(Node *); private: E_TYPE data; Node * next; };

For efficiency, Node may make class List a friend


Omit access functions

E_TYPE is any type that has a copy constructor


We must initialize data in the constructor's member initializer list

A Simple Linked List


//Create empty list Node * head = NULL; //Add first node 1 4 2 x 3 Fraction x(1,2); head = new Node(x, head); //Add node to position 1 x.setFraction(3,4); head = new Node(x, head);
head

1 2

3 4

Insert at Beginning
This is the easiest case
It is a special case in a more general insert routine //x to the front of the list! Node * temp; temp = new Node(x); temp->next = head; head = temp; or more simply: head=new Node(x, head);

The new node must point to the address found in head pointer head must then point to the new node

Repeat 10 Times: Insert at End


If new items are to be added at the end of a linked list, keep a pointer to the last item for efficiency
Node *head=NULL, *last=NULL; //First node is special: last = head = new Node(x); //Then for each new x: last = last->next = new Node(x); Note that each Node's next member is set to NULL by default
This is the correct value for the last Node in the list

A Distinguished List Element


Many linked list operations are applied to a "current element" in the list
insert before/after current, remove current

It is customary to have another pointer (besides head) to specify the location of the current list item
Surprisingly, it usually does not point directly to the current item!

Current Pointer
3 5 2 7 1 3 4 1

curr points to the node before the curr current node


Fraction 1/3 is "current"

curr==NULL means first node is current

This idea reduces the complexity of many linked list algorithms Next we look at how you would insert a new node at the current position

Insert At (Before) Current


3 5
curr

2 7

1 3

4 1

//Insert 11/4 at current Node *temp; temp Fraction x(11,4); temp = new Node(x,curr->next); curr->next = temp;

11 4

x 11 4

Illegal Dereferencing
Just remember two things: 1. Never dereference a NULL pointer 2. Never dereference a NULL pointer if (curr == NULL){ temp = new Node(x,head); head = temp; } else { temp = new Node(x,curr->next);

The beginning of the list is usually a special case in code

curr->next = temp;
}

Removing Current
3 5
curr

2 7

1 3

4 1

// 1/3 is to be removed Node *temp = curr->next; curr->next = temp->next; delete temp;

temp

Did we dereference a NULL pointer? Removing the first item is a special case!

Could temp be NULL?

List Disposal
Node *temp; //delete all nodes while(head){ temp=head; head=head->next; delete temp; } //head is now NULL

Each Node must be deleted individually A temporary pointer is required for this operation
temp holds the address of the head node while head is set to the next (if any)

List ADT - Linked Implementation (LI)


class List{ public: //No changes here! private: Node *head; Node *current; };

Only the implementation changes


head points to first item (if any) current points to node before current item

List clients will never suspect things are different

List ADT (LI) Con/Destructor & next()


List::List(){ void List::next(){ current=head=NULL; if (current==NULL) } current=head; List::~List(){ else if (current->next !=NULL) Node *temp; current=current->next; while(temp=head){ } head=head->next; Note: When current points at the last Node, the position at delete temp; the end of the list is current } (not the last element) }

List ADT (LI) length()


int List::length(){ int n = 0; Node *temp=head; while(temp){ n++; temp=temp->next; } return n; }

Since we do not explicitly store the number of items in the list, it is expensive to determine the current list length!
You could improve efficiency by storing the list size

List ADT (LI) setPos()


void List::setPos(int n){ if (n<1) return; if (n==1) { current=NULL; return;} Node * temp=head; while(--n>1 && temp) temp=temp->next; if (temp) current=temp; }

current changes only in n is legal


If n is too big, temp will become NULL For example:
if length is 3 L.setPos(4); //OK L.setPos(5); //illegal

head

1st

2nd
temp

3rd

List ADT (LI) prev()


void List::prev(){ if (current==head){ current=NULL; return;} Node * t=head; while(t->next!=current) t=t->next; current=t; }

Going backwards in a linked list is costly!


t searches for a Node that points to the same address current points to

Could t ever become NULL in this code?

List ADT (LI) insert()


int List::insert(type & elt){ if (current == NULL) head = new Node(x,head); else current->next = new Node(x,curr->next); }

There is no limit to the number of items we can insert


We may run out of memory

Inserting at first location is a special case This is easier than the array implementation!

List ADT (LI) remove()


int List::remove(){ Node * temp=head; if (current) temp=current->next; if (temp == NULL) return 0; if (current == NULL) head = temp->next; else current->next=temp->next; delete temp; return 1; }

temp points to the Node to be deleted


If current is at end of list, temp will be NULL remove fails in this case

Deleting the first item is a special case


current cannot be dereferenced (see underlines)

Advantages of Linked Implementation


No limit to number of items (up to memory limits) Insert and remove operations are very efficient
There is no shuffling of the remaining list items

Storage required is proportional to the number of elements currently in the list


An empty list is very small

Access via pointer is faster than accessing an array component


No computation

Disadvantages of Linked Implementation


SetPos, prev, and length are very inefficient
length could be easily made efficient by adding one data member SetPos is inherently inefficient since a linked list is not a random access structure

Linked lists are designed to be processed in forward order


prev cannot be improved in a simple linked list

Each Node contains a pointer which requires additional storage

You might also like