• Nem Talált Eredményt

Creating singly linked lists

In document Mechatronic Systems Programming in C++ (Pldal 100-103)

8. User-defined data types

8.1. The structure type

8.1.5. Creating singly linked lists

The simplest forms of linked lists are singly linked lists in which all elements possess a reference to the next list element. The reference in the last element has the value null (I.26. ábra - A singly linked list).

I.26. ábra - A singly linked list

The list is selected in the memory by the pointer pStart so the value of the latter should always be kept. If the value of pStart is set to another value, the list becomes inaccessible.

Let's see what advantages the usage of a linear list has as compared with vectors (one-dimensional arrays). The size of a vector is fixed when it is defined; however, the size of a list can be increased or decreased dynamically.

There is also an important difference between the two how elements are inserted in or removed from them.

Whereas these operations only require the copy of some pointers in the case of lists, these operations require

moving a big amount of data in vectors. There is also a significant difference between the two with respect to the structure of the storage unit, that is that of the element:

Vector elements only contain the stored data whereas list elements also contain a reference (a pointer) to (an)other element(s). C++ list elements can be created by the already presented self-referential structure.

As an example, let's store integer numbers in a linear list, the elements of which have the following type:

struct list_element { int data;

list_element *pnext;

};

Since we allocate memory for each new list element in this example, this operation is carried out by a function to be presented in the next chapter of the present book:

list_element *NewElement(int data) {

list_element *p = new (nothrow) list_element;

assert(p);

p->data = data;

p->pnext = NULL;

return p;

}

That function returns the pointer of the new list element and initializes it if this function has run with success.

We should not forget about calling the function assert (). This macro interrupts running the program and prints out the message "Assertion failed: p, file c:\temp\list.cpp, line 16” if its argument has the value of 0.

When created, the list is filled up by the elements of the following array:

int data [] = {2, 7, 10, 12, 23, 29, 30};

const int num_of_elements = sizeof(data)/sizeof(data[0]);

For a successful management of the list, we need additional variables and the pointer pStart to the beginning of the list:

list_element *pStart = NULL, *pActual, *pPrev, *pNext;

When we are dealing with a given element (pActual) of the list, we might need to know where the preceding element (pPrev) and the next one (pNext) are. In this example, in order to facilitate our task we hypothesise that the list always exists when it has been created, that is the pointer pStart is never null.

Creating the list and filling up it from the array data. When a list is created, there are three separate tasks to carry out with each element:

• memory allocation (with checking if it has taken place) for a new list element (NewElement()),

• assigning data to the list element (NewElement()),

• adding the list element to (the end of) the list. When an element is added to a list, the things to be done are different in the case of first and non-first elements.

for (int index = 0; index<num_of_elements; index++) { pNext = NewElement(data[index]);

if (pStart==NULL)

pActual = pStart = pNext ; // first element else

pActual = pActual->pnext = pNext; // not a first element

}

pActual->pnext = NULL; // closing the list // list: pStart ➝ 2 ➝ 7 ➝ 10 ➝ 12 ➝ 23 ➝ 29 ➝ 30

When printing out the elements of the list, we start from the pointer pStart and step to the next element in a loop until the null pointer indicating the end of the list is reached:

pActual = pStart;

while (pActual != NULL) {

cout<< pActual->data << endl;

// stepping to the next element pActual = pActual->pnext;

}

It is often needed to remove an element from a list. In the following example, the list element to be removed is identified by its index (Indexing starts with 0 from the element to which the pointer pStart points to. This example code is not able to remove the 0th and the last element!) The removal operation also consists of three steps:

// identifying the place of the element having the index 4 (23) pActual = pStart;

for (int index = 0; index<4; index++) { pPrev = pActual;

pActual = pActual->pnext;

}

// removing the element of the linked list pPrev->pnext = pActual->pnext;

// deallocating memory space delete pActual;

// the list: pStart ➝ 2 ➝ 7 ➝ 10 ➝ 12 ➝ 29 ➝ 30

When the 0th element is removed, the pointer pStart has to be set to pStart->pnext before removal. When it is the last element that is removed, the member pnext of the element immediately before the last one has to be set to null.

Another operation is inserting a new element to a list between two already existing elements. The place of the insertion is identified by the index of the element after which the new element is to be inserted. In the example, a new list element is inserted after the element having the index 3:

// determining the place of the preceding element of index 3 (12) pActual = pStart;

for (int index = 0; index<3; index++) pActual = pActual->pnext;

// allocating memory for the new element pNext = NewElement(23);

// inserting the new element in the linked list pNext->pnext = pActual->pnext;

pActual->pnext = pNext;

// list: pStart ➝ 2 ➝ 7 ➝ 10 ➝ 12 ➝ 23 ➝ 29 ➝ 30

The code part above can even insert a new list element to the end of the list.

It is also frequent to add a new element to (the end of) the list.

// searching for the last element pActual = pStart;

while (pActual->pnext!=NULL && (pActual = pActual->pnext));

// allocating memory for the new element pNext = NewElement(80);

// adding the new element to the end of the list pActual->pnext = pNext;

// the list: pStart ➝ 2 ➝ 7 ➝ 10 ➝ 12 ➝ 23 ➝ 29 ➝ 30 ➝ 80

We might also need to search for an element of a given value (sdata) in the list.

int sdata = 29;

pActual = pStart;

while (pActual->data!=sdata && (pActual = pActual->pnext));

if (pActual!=NULL)

cout<<"Found: "<<pActual->data<< endl;

else

cout<<" Not found!"<<endl;

Before exiting the program, the dynamically allocated memory space has to be freed. In order to delete the elements of a list, we have to iterate through the list while making sure to read the next element before deleting the actual list element:

pActual = pStart;

while (pActual != NULL) { pNext = pActual->pnext;

delete pActual;

pActual = pNext;

}

pStart = NULL; // there is no list element!

In document Mechatronic Systems Programming in C++ (Pldal 100-103)