C Structures in Action: Linked-lists No

advertisement
C Structures in Action: Linked-lists
No programming language discussion is complete without discussing data structures that
can be constructed from the basics of the language. In this note we will study linked-list,
one of the most widely used data structures.
A singly linked-list is a sequence of items called nodes, each of which contains two
pieces of information: data stored in the node and a reference to the next item in the
sequence. The last item in a linked-list will have a special reference called null indicating
the fact that it is the last element in the sequence. (See Fig. 1 below.)
o There is no restriction on the number of items that a singly linked-list
could have (except, of course, constrained by computer memory). So, this
structure can be used as an expandable array, in a way.
o Time to access an element depends on where the element is located in the
sequence since we need to start the search from the very first element in
the list (we cannot access an element by its index as in the case of arrays)
Figure 1. A singly linked-list of n elements
A linked-list data structure has an advantage over an array collection in that there is no
restriction on the number of elements it can hold. Structure could grow and shrink
dynamically depending on the need. Array size, on the other hand, need to be determined
before an array structure is created and resizing an array is a costly operation. On the
other hand, accessing a particular element in a linked-list is not as efficient as accessing
an array element: time to access a particular element depends on the location of that
element in the linked-list structure. In an array, on the other hand, the time to access an
element is the same for all elements.
A linked-list data structure typically maintains a pointer to the first element in the list.
This pointer provides the entry into the structure. All basic operations start with this
pointer, which is sometimes called “header”.
Basic operations on a linked-list are inserting a new element, deleting an element,
searching for an element, and traversing all elements. Below is the pseudocode for these
operations (pseudocode is what people typically use to sketch out an algorithm; the actual
code could be built by following the logic in pseudocode):
a) Algorithm insert(newElement)
// create a new data node to add to the linked-list
newNode = allocateNewNode(newElement)
// just add the new element to the beginning of the list
// newElement’s address becomes the entry point to the list
newNode.nextElement header
header address(newNode)
b) Algorithm delete(element)
previousNode null
nextNode header
while nextNode != null and nextNode.element != element do
// Keep a reference to the previous element
previousNode nextNode
// Move to the next element
nextNode nextNode-->nextElement
end while
// The loop above terminates either when the element is found or
// when the list is completely traversed and the element is not found.
If nextNode != null
// This implies that the element pointed by nextNode is the one
// to be deleted. So, the node before it should now point to the
// node after it.
previousNode-->nextElement = nextElement-->nextElement
deallocate memory used by nextElement
else
// Else block will be entered when element is not found. Nothing
// to do here
c) Algorithm find(element)
nextNode
header
while nextNode != null and nextNode.element != element do
// Move to the next element
nextNode nextNode-->nextElement
end while
// The loop above terminates either when the element is found or
// when the list is completely traversed and the element is not found.
If nextNode != null
return nextNode element
else
// Else block will be entered when element is not found.
return null
d) Algorithm traverseList()
nextNode
header
while nextNode != null and nextNode.element != element do
// Work on the operation on the current element
someOperation(nextNode)
// Move to the next element
nextNode nextNode-->nextElement
end while
An example: A linked-list of student records
We will go over a simple example of a linked-list of student records. I will keep the
structure simple since the point of this exercise is not to build a full student record.
Let’s define the student structure in a linked-list:
struct Student
{
char* firstName;
char* lastName;
char* studentNumber;
float gpa;
/*
* Pointer to the next student record.
*/
struct Student* nextStudentRecord;
};
Note that the last element is a pointer to a student record. This will be the “link” from
one record to the next that we will use in order to traverse the linked-list of records. (See
Figure 1 above.)
Code to insert an element to the linked-list is as follows:
/**
* Inserts a given element to the linked list, the first element of
* which is referenced by the header pointer.
*
* linkedListHeader: the pointer to the first element in the
* linked list
* newElement: the new element to be added to the linked list
*/
struct Student* insert(struct Student* linkedListHeader, struct
Student* newElement)
{
/*
* Add the new element to the top of the list.
*/
newElement->nextStudentRecord = linkedListHeader;
/*
* Mark the header node of the list as the new node just added.
*/
linkedListHeader = newElement;
return linkedListHeader;
}
And the code to find an element in the list is as follows:
/**
* Finds the student record with the given student number and
* returns the record to the caller.
*
* linkedListHeader: the pointer to the first element in the
* linked list
* studentNumber: number of the student whose record to be found
*
* returns: student record if found; otherwise, returns NULL.
*/
struct Student* find(struct Student* linkedListHeader, char*
studentNumber)
{
struct Student* currentNode;
currentNode = linkedListHeader;
/*
* Traverse the linked-list until the student record is found
* or until the whole list is traversed.
*/
while (currentNode != NULL
&& strcmp(currentNode->studentNumber, studentNumber) != 0)
{
currentNode = currentNode->nextStudentRecord;
}
return currentNode;
}
About the strcmp() function above: this is a C library function that compares two strings
(or two character arrays). It returns 0 if the two strings are the same. We will cover
strings at length later.
Here is a simple test program that inserts two records into a list, finds a given student
record, and prints it.
#include "linkedlist.h"
int main()
{
/*
* Declare and initialize two student records.
*/
struct Student s1 = {"Turgut", "Ozben", "123890", 3.5, NULL};
struct Student s2 = {"Selim", "Isik", "872340", 3.8, NULL};
/*
* Pointer to the first element of the linked list.
*/
struct Student* studentList;
/*
* Initially there are no students in the list.
*/
studentList = NULL;
/*
* Add students s1 and s2 to the list.
*/
studentList = insert(studentList, &s1);
studentList = insert(studentList, &s2);
/*
* Find student record with student id of 123890
*/
struct Student* p;
p = find(studentList, "123890");
/*
* Print the student record.
*/
if (p != NULL)
{
printf("Student record found \n");
printf("First Name: %s Last Name: %s Student No: %s GPA: %f
\n",
p->firstName, p->lastName, p->studentNumber, p->gpa);
}
else
{
printf("Student record not found \n");
}
return (0);
}
The source files are in hbar server in the usual location. File names are linkedlist.h and
linkedlist.c. There is also a test program called testlinkedlist.c.
Download