CSC201sup
CSC201sup
Course Content
Primitive types, Arrays, Records Strings and String processing.
Data representation in memory, Stack and Heap allocation, Queues, TREES.
Implementation Strategies for stack, queues, trees.
Run time Storage management; Pointers and References, linked structures.
• Richness of data: the data must be rich enough to satisfy the real relationships of the
data in the real world.
• Simplicity of data structure: the data structure should be so simple to allow easy
processing the data when need arises.
Implementation: This provides the internal representation of data structure. It also provides
the definition of algorithms for operations of data structure.
Space complexity: data structure should be able to minimize the memory usage, that is
memory usage through all data items in a data structure should be less possible.
Processor Speed: As data grows in size, the processor speed falls, no matter the speed of the
processor.
These are:
i. Worst Case
ii. Average Case
iii. Best Case
Worst case: This is a scenario where a particular data structure operations exhaust its
maximum time. For instance, if operation time is f(n), the operation cannot exceed f(n)
time, where f(n) is a function of n.
Average case: This depicts average execution time of an operation of a data structure. If an
operation takes f(n) time, m operation will take mf(n) time to execute.
Best Case: this shows the least possible execution time of an operation of a data structure. If
an operation takes f(n) time in execution, then the actual operation may take time as the
random number which would be maximum as f(n).
Traversing: It is used to visit each variable once. It is also referred to as visiting elements in
the data structure. This operation may have specific name in each data structure; e.g. Peek in
Stack
Searching: It is used to find the location of a given element in the whole data structure.
Example, an array.
Insertion: It is used to insert an element at the specified position in data elements.
Deletion: A deletion operation is used to delete an element from the specified location
Sorting: It is used to arrange or sort the data elements in ascending or descending order.
However, the data items are arranged in some logical order, such as Named key, account
number, etc.
Merging: The Merge operation is used to join two or more sorted data elements in a data
structure.
Boolean datatype
This is the data type that has one of two possible values usually denoted true and false, or 1
and 0 in binary form. It is intended to represent the two truth values of logic and Boolean
algebra. The name is gotten from George Boole who was the first to define an algebraic
system of logic in mid 19th century. Boolean datatype in mostly use for decision making,
they cannot be used for computational operations as we do with integers.
Representation of Array
Array can be declared in various way in different languages. For instance, Array declaration
in C programming language: int a[10]
10 12 3 4 9 0 45 15 7 8 Elements
Int a [10] = 0 1 2 3 4 5 6 7 8 9
Index
Arrays can have multiple dimensions; thus it is common to access an array using multiple
indices. For example a two dimensional array A with three rows and four columns might
provide access to the element at the 2nd row and 4th column by the expression: A[1, 3] (in a
row major language) and A[3, 1] (in a column major language) for a zero-based indexing
system.
4 6 2 9
1 4 3 5
8 4 5 7
Two indices are used for a two-dimensional array, three for a three-dimensional array, and n
for an n dimensional array. The number of indices needed to specify an element is called the
dimension, dimensionality, or rank of the array.
In standard arrays, each index is restricted to a certain range of consecutive integers (or
consecutive values of some enumerated type), and the address of an element is computed by
a "linear" formula on the indices.
One-dimensional array as in Figure 2.1 is a linear vector with linear addressing, the element
with index i is located at the address B + c*i, where B is a fixed base address and c a fixed
constant, sometimes called the address increment or step. If the valid element indices begin
at 0, the constant B is simply the address of the first element of the array. For this reason,
the C programming language specifies that array indices always begin at 0; and the element
is regarded as “zeroth” rather than “first” by many programmers. However, one can choose
the index of the first element by an appropriate choice of the base address B. For example,
if the array has five elements, indexed 1 through 5, and the base address B is replaced by B
− 30c, then the indices of those same elements will be 31 to 35. If the numbering does not
start at 0, the constant B may not be the address of any element.
For a two-dimensional array, the element with indices i,j would have address B + c* i + d* j,
where the coefficients c and d are the row and column address increments, respectively.
More generally, in a k-dimensional array, the address of an element with indices i1, i2, …,
ik is B + c1 · i1 + c2 · i2 + … + ck · ik.
For example: int A[4][3];
This means that array A of integer type has 4 rows and 3 columns, Here we can store 12
elements linearly but starting from first row linear then continuing with second row and so
on. The above array will be stored as:
A11, A12, A13, A21, A22, A23, A31, A32, A33, A41, A42, A43.
This formula requires only k multiplications and k−1 additions, for any array that can fit in
memory. Moreover, if any coefficient is a fixed power of 2, the multiplication can be
replaced by bit shifting. The coefficients ck must be chosen so that every valid index tuple
maps to the address of a distinct element. If the minimum legal value for every index is 0,
then B is the address of the element whose indices are all zero. As in the one-dimensional
case, the element indices may be changed by changing the base address B. Thus, if a
two-dimensional array has rows and columns indexed from 1 to 10 and 1 to 20, respectively,
then replacing B by B + c1 - − 3 c1 will cause them to be renumbered from 0 through 9 and
4 through 23, respectively. Taking advantage of this feature, some languages (like
FORTRAN 77) specify that array indices begin at 1, as in mathematical tradition; while
other languages (like Fortran 90, Pascal and Algol) let the user choose the minimum value
for each index.
Insertion Operation
In Insertion operation, one or more elements are inserted into an array. Based on the
requirement, the new element can be at the beginning or any given index of the array.
Insertion can be done at the beginning of an Array, at a given index, before or after a given
index of an array.
Insertion at the beginning of an array.
If insertion is to be done at the beginning of array, it causes all the existing system to move a
step downward.
Beginning of array
Linked List 10 12 3 4 9 0 45 15 7
0 1 2 3 4 5 6 7 8 9
1.2 RECORDS STRINGS AND STRING PROCESSING
The ASCII values of character A-Z, a-z, 0-9 and special character like ;,/.% etc are shown
on the table below.
Character Methods
These are operations on characters the returns a new character value. Below are some
common methods on characters.
Table 2: Common Methods for Operations on String
boolean Character.isDigit(Char ch)
(Determines if the specified charater is a digit)
boolean Character.isLetter(Char ch)
(Determines if a specified character is a letter)
boolean Character.isLetterOrDigit (Char ch)
(Determines if a specified character is a letter or a digit)
boolean Character.isLowercase(Char ch)
(Determines if a specified character is a lower case letter)
boolean Character.isUppercase(Char ch)
(Determines if a specified character is an upper case letter)
boolean Character.isWhitespace(Char ch)
(Determines if a specified character is whitespace (space and tabs)
char Character.toLowercase(Char ch)
(converts ch to its a lower case equivalent, if any. If not, ch is returned unchanged)
char Character.toUppercase(Char ch)
(converts ch to its a upper case equivalent, if any. If not, ch is returned unchanged)
Having known what the composition of string (character) means let us continue with study
of strings.
String as have earlier been mentioned is sequence of characters, it is always enclosed in a
double quotes.
G o o d M o r n i n g
0 1 2 3 4 5 6 7 8 9 10 11
In this example, the StrLen = text.length() // the value is 12 (that is n) which is the number
of characters in the text. Note the space is regarded as a character
Char last = text.CharAt(StrLen – 1); // the value is g
String concatenation
String concatenation is joining of strings together using the operator “+”. This can be used
to form a new string.
String message = Level + " are " + “to”+ " wait."; //this will get whatever level that is
entered by the user join it other strings to create a message. Assuming the user enters
200Level, then the output will be: “200Level are to wait”
How to concatenate characters to form string
char c1 = 'x';
char c2 = 'y';
It is wrong to add them direct without creating an empty string as shown below
String str = c1 + c2; // this is an integer
Instead it should be concatenated this way
String str = "" + c1 + c2;
A substring
A substring is a subset of a string.
String str = “Good Morning”;
String “Good” = str.substring(0,5); // this means from first index to 5th index without
including the value on the 5th index.
String “Morning” = str.substring(6) // the substring is from the 6th index to the end.
String Processing
When we talk about string processing, we are simply talking about the operations that can
be carried out on strings.
Strings Comparison
Methods Description
s1.equals(s2) Whether two strings contain the same
characters
Assignment: Develop an algorithm that will output the substring “Hello” from the
string “ Hello Jane” . The assignment should be submitted on the day of the exam.
Lesson Two
In this lesson two, we are going to study the following:
Data representation in memory, Stack and Heap allocation, Queues, TREES.
Implementation Strategies for stack, queues, trees.
Computers cannot accept and process data and instructions naturally using human language.
All data type be it numbers, letters, special symbols, sound or pictures must first be
converted into machine-readable (binary) form. So it is important to understand how a
computer together with its peripheral devices handles data in its electronic circuits, on
magnetic media and in optical devices. The way of data encoding in computer is what is
known as data representation.
The complexity of natural language due to its diversity makes the development of a system
that can just understand it very difficult. It is much easier to construct electric circuits on
two-state logic that is binary or On and Off logic. More so, digital devices which are based
on binary systems are more portable, reliable and use less energy when compared to analog
devices.
These terms are used widely in reference to computer memory and data size.
• Bits: This is the basic unit of data or information in digital computers which can be
defined as a binary with only two values either 0 or 1.
• Byte: a group of bits (8 bits) used to represent a character. A byte is considered the
basic unit of measuring memory size in a computer.
• A nibble: is half a byte, which is usually a grouping of 4 bytes.
• Word: two or more bytes make a word. The term word length is used as the
measure of the number of bytes in each word. For example, a word can have a length
of 16 bits, 32 bits, 64 bits etc.
A number system is a set of symbols used to represent values derived from a common base
or radix. In computing, there are two major number systems:
Other number system such as octal number system and hexadecimal number system are
multiples of binary system.
The term decimal is curled from a Latin prefix deci, which means ten. Decimal number
system has ten digits ranging from 0-9 thus it is also called a base ten or denary number
system. Decimal is commonly used number, so most often it is written without subscript but
where many number system is considered it should be written with subscript 10 e.g. X10 (10
indicates the base or radix)
85 ÷ 2 = 42 𝑅 1
42 ÷ 2 = 21 𝑅 0
21 ÷ 2 = 10 𝑅 1
10 ÷ 2 = 5 𝑅 0
5÷2= 2𝑅1
2÷2= 1 𝑅0
1÷2= 0𝑅1
8510 = 10101012
• First, write the place values starting from the right hand side.
• Write each digit under its place value.
• Multiply each digit by its corresponding place value.
• Add up the products. The answer will be the decimal number in base ten.
1x24 1x23 0x22 1x21 1x20 . 0x2-1 0x2-2 0x2-3 0x2-4 1x2-5 1x2-6 1x2-7 0x2-8
16 + 8 + 0 + 2 + 1 . 0 + 0 + 0 + 0 + 0.031 + 0.016 + .009
27 . 056
11011.000011102 = 27.05610
Solution
Working from left to the right, each octal number is represented in binary using three digits
(remember, 23 gives 8) and then combining them together, we get the final binary
equivalent. Therefore:
5=1012
2=0102
1=0012
5 2 1
101 010 001
5218 =1010100012
▪ To convert binary numbers to their hexadecimal equivalents, simply group the digits
of the binary number into groups of four from right to left e.g. 11010001001.The
next step is to write the hexadecimal equivalent of each group e.g.
0110,1000,1001
1001- 9
0001- 1
0110 - 6
• First, write the place values starting from the right hand side.
• If a digit is a letter such as ‘A’ write its decimal equivalent
• Multiply each hexadecimal digit with its corresponding place value and then add the
products
Integers as haven been discussed earlier are whole numbers or fixed-point numbers with the
radix (base) point fixed after the least significant bit. They are opposite to real numbers or
floating-point numbers, where the position of the radix point varies. Integers representation
and processing in computers differs from that of floating-point numbers.
A fixed number of bits are used to represent an integer. The commonly-used bit-lengths for
integers are 8-bit, 16-bit, 32-bit or 64-bit. Besides bit-lengths, there are two representation
schemes for integers:
i. Unsigned Integers: represent zero and positive integers.
ii. Signed Integers: represent zero, positive and negative integers.
➢ There is only one way of representing a zero unlike in case with other two methods.
➢ Effective addition and subtraction can be done even with numbers that are
represented with a sign bit without a need for circuitries to examine the sign of an
operand.
The twos compliment of a number is obtained by first finding the ones compliment then
adding 1. For example, to get the twos compliment of 2510,
Steps:
2510=00110012
= 11001112
A floating-point number (or real number) can represent a very large (1×10^50) or a very
small (1×10^-50) value. It is typically expressed in the scientific notation, with
a fraction (F) and an exponent (E) of a certain radix (r), in the form of F × r^E.
Representation of floating point number is not unique. For example, the number18.66 can be
represented as 1.866×101, 0.1866×102, 0.01866×103, etc. The fractional part can
be normalized. In the normalized form, there is only a single non-zero digit before the radix
point. For example, decimal number523.4567 can be normalized as 5.234567×102; binary
number 1010.1011 can be normalized as 1.011011×23.
It is important to note that floating-point numbers suffer from loss of precision when
represented with a fixed number of bits (e.g., 32-bit or 64-bit). This is because there
are infinite number of real numbers (even within a small range of says 0.0 to 1.0). On the
other hand, a n-bit binary pattern can represent a finite 2n distinct numbers.
We cannot discuss floating numbers representation in detail, it is not within the scope of our
study.
STACK
Stack is a linear data structure that enables the elements to be inserted and deleted from one
end, called the Top of Stack (TOS). A stack data structure follows the last in first out
(LIFO) operation to insert and remove an element from the stack list. It is an abstract data
type with two possible operations to insert (push) and delete (pop) elements in the stack.
A push operation is used in the stack to insert elements at the top of the list, hide those
elements that already available in the list, or initialize the stack if it is empty.
The pop operation is used in the stack data structure to delete a data item from the top of the
list.
Figure 2.1: Stack (Entry and Exit are from the same point
QUEUE
Queue is a linear data structure that enables the insertion at one end of the list, known as
the rear, and the deletion of the elements occurred at another end of the list, called
the front. It is a sequential collection of data elements based on the First in First
out (FIFO) data structure, which means the first inserted elements in a queue will be
removed first from the queue list. Its method of operation is inverse of stack which is Last
in First out.
Below are queue operations:
1. Enqueue(): queue operation for insertion of an element to the list.
2. Dequeue(): queue operation for deletion of an item from the list.
3. Peek(): It is used to get the first element of the queue list without removing it.
4. IsFull(): It is an IsFull operation that indicates whether the list is full.
5. IsEmpty(): It is an IsEmpty operation that represents whether the list is empty.
HEAP
A heap data structure is a special type of complete binary tree that satisfies the heap
property and arranged the elements in a specific order. Heap data structure is of two
types: Max and Min heap.
In Max heap, the root node's value is always higher or equal to the value of all existing
child nodes in the heap tree. While in Min heap, the value of the root node/element is
always shorter than the existing elements of the heap node. Each child node's value in
the min-heap is equal to or larger than the parent node's value. Min Heap is the inverse
HASH TABLE
In computer science, a hash table or hash map is a non-linear data structure that uses a hash
function to map identifying values, known as keys (e.g., a person's name), to their associated
values (e.g., their telephone number). Thus, a hash table implements an associative array.
The hash function is used to transform the key into the index (the hash) of an array element
(the slot or bucket) where the corresponding value is to be sought. A key is a non-null
value that is mapped or linked to an element. Hashing makes our data structure much
simpler and faster when performing insertion and search operations on various data
elements, regardless of the data's size.
Hash function
The hash table algorithm is an array of items; this array is often simply called the hash table.
Hash table algorithms calculate an index based on the data item's key and the length of the
array. The index is used to find or insert the data into the array. The implementation of this
calculation is the hash function,
The hash function calculates an index into the array from the data key and array Length (the
size of the array).
0
Jerry Mary +234-8103684213
1
…
659
Mary Jerry +234-7010368421
660
Mary
…
998
Robert Robert +234-8201030481
999
Robert
DICTIONARY
A dictionary is a type of data structure that holds data elements in a group of objects and is
similar to a hash table, except that it is an ordered or sorted collection of data elements in
key-value pairs. Each key is associated with a single value. When we retrieve a key, the
dictionary will return the associated value of a key. For example, students = {'James' = 25,
'Jasmine' = '17', 'Rosy = '19', 'Margret' = '24', 'Price' = '28'}
Given a word, one can find its definition. A telephone book is a sorted list of people's
names, addresses, and telephone numbers. Knowing someone's name allows one to quickly
find their telephone number and address.
Operations on Dictionary
Graphs
A graph is a non- linear data structure consisting of finite sets of vertices (nodes)
and edges to create an illustrated representation of a set of objects. These edges and nodes
are connecting through any two nodes in the graph. The connected node can be represented
as a directed or undirected graph. In a directed graph, each node is directly connected with
edges in only one direction. In an undirected graph, each node is connected with edges in
all directions. Hence it is also known as a bidirectional node.
TREES
This is a non-linear data structure representing the hierarchical data. It is a finite set of
elements where one of these nodes or elements is called a root node, and the remaining
elements of a data structure consisting of a value called Subtrees. Every node of the tree
maintains the parent-child relationship, where only one parent node and the remaining node
in the tree is the child node. A node can have multiple child nodes but has a single parent
node. There are some types of trees, such as a binary tree, binary search tree, expression
trees, AVL tree and B trees.
.
Figure 2.5: Tree data structure
Binary Trees
A binary tree is a structure in which each node in the tree is said to have at most two nodes
as its children, and each node has exactly on parent node. The top node in the tree is the
only one without a parent node and is called the root of the tree. On the on other hand, a
node without a child (children) is called leaf node.
There are two basic representation of binary trees namely linked and sequential
representation. These are further discussed as follows.
Linked representation:
Binary trees in linked representation are stored in the memory as linked lists. These lists
have nodes that are not stored at adjacent or neighbouring memory locations and are linked
to each other through the parent-child relationship associated with trees. In this
representation, each node has three different parts namely:
• Pointer that points towards the right node
• Pointer that points towards the left node
• Data element
This is the more common representation. All binary trees consist of a root pointer that points
in the direction of the root node. When you see a root node pointing towards null or 0, you
should know that you are dealing with an empty binary tree. The right and left pointers store
the address of the right and left children of the tree.
Sequential representation:
Although it is simpler than linked representation, its inefficiency makes it a less preferred
binary tree representation of the two. The inefficiency lies in the amount of space it requires
for the storage of different tree elements. The sequential representation uses an array for the
storage of tree elements. The number of nodes a binary tree has defines the size of the array
being used. The root node of the binary tree lies at the array’s first index. The index at
which a particular node is stored will define the indices at which the right and left children
of the node will be stored. An empty tree has null or 0 as its first index.
Traversal Algorithms
When we work with graphs, there may be times that we wish to do something to each node
in the graph exactly once. For instance, there may be piece of information that needs to be
distributed to all of the computers on a network. Therefore, we want this information to get
to each computer, and we do not want to give it to any computer twice. The same thing
would be true if we were looking for information instead of distributing it. There are two
methods that we will examine to achieve this traversal. In other words, there are two main
types of Traversal algorithms namely Depth-first and Breadth-first. In Depth-first traversal
algorithm, the traversal will go as far as possible down a path before considering another. In
the Breadth-first traversal, the traversal will go evenly in many directions.
Both methods are discussed in detail below. For these two traversal methods, we choose one
node in the graph as the starting point. In our discussion the phrase “visit node” will be used
to represent the action that needs to be done at each node. For instance if we are searching,
visiting the node would mean that we check it for the information we want.
If we begin the depth-first traversal at node 1, we then visit, in order, the nodes 2, 3, 4, 7, 5
and 6 before we reach a dead end. We would then back up to node 7 to find that node 8 has
not been visited, but that immediately leads to a dead end. We next back up to node 4 and
find that node 9 has not been visited, but again we have an immediate dead end. We then
continue to back up until we reach the starting node, and because all nodes adjacent to it
have been visited, we are done. The recursive algorithm for depth-first traversal algorithm is
as follows
DepthFirstTraversal (G, v)
G is the graph
V is the current node
Visit (v)
Mark (V)
For every edge vw in G Do
If w is not marked Then
DepthFirstTraversal (G, w)
End if
End for
This recursive algorithm relies on the system stack of the computer to keep track of where it
has been in the graph so that it can properly back up when it reaches dead ends. We could
create a similar non-recursive algorithm by using a stack data structure and pushing graph
vertices ourselves.
This algorithm will add the root of the breadth-first traversal tree to the queue but then
immediately remove it. As it looks at the nodes that are adjacent to the root, they will be
added to the end of the queue. Once all of the nodes adjacent to the root have been visited,
we will return to the queue and get the first of those nodes. You should notice that because
nodes are added to the end of the queue, no node that is two edges away from the root will
be considered again until all of the nodes one edge away have been taken off of the queue
and processed.
Advantages of Breadth-first Traversal Algorithm
• Used to find the shortest path between vertices
• Always finds optimal solutions.
• There is nothing like useless path in BFS, since it searches level by level.
• Finds the closest goal in less time
For every execution (run-time) the CPU fetches instructions and data of a program from
memory; therefore, both the program and its data must reside in the main (RAM and ROM)
memory. Modern multiprogramming systems are capable of storing multiple programs
together with their data in the main memory.
The main task of the memory management component of an operating system is to ensure
safe execution of programs by providing:
– Memory sharing
– Memory protection
Translatio …
n Object
Compiler
codes Loading Code
Linker Loader Data
Exec. Code Workspace
(Load module)
…
Libraries
codes Secondary memory
Figure 2.9: Source program to Executable code Main Memory
Address binding (Relocation)
Address binding or relocation is the process of associating program instructions and data
(addresses) to physical memory addresses.
Types of Address binding
i. Static—new locations are determined before execution. It is used in Compile and Load
time
• Compile time: The compiler or assembler translates symbolic addresses (e.g.,
variables) to absolute addresses.
• Load time: The compiler translates symbolic addresses to relative (relocatable)
addresses. The loader translates these to absolute addresses.
ii. Dynamic—new locations are determined during execution.
• Run time: The program retains its relative addresses.
The absolute addresses are generated by hardware.
Function of a Linker
This as have earlier mentioned combines the object code into a single self-sufficient
executable code. A compile time linker collects (if possible) and puts together all the
required pieces to form the executable code.
Issues:
• Relocation: this is concerned with where to put pieces.
• Cross reference: this is concerned with where to find pieces.
Functions of a loader
A loader places the executable code in main memory starting at a predetermined
location (base or start address).
Figure2.11: Loading of codes in main memory
Methods of Loading
This can be done in different ways depending on hardware architecture:
• Absolute loading: always loads programs into a designated memory location.
• Relocatable loading: allows loading programs in different memory locations.
• Dynamic (runtime) loading: loads functions when first called (if ever).
Linked-List
Linked-List is a collection of data links known as nodes. Each node contains a data value
and the address of the next link. Unlike array all the elements of the linked-list are not stored
in neighbouring memory locations. It can be simply said to be a sequence of data nodes that
connect through links. Each node of a list consists of two items: a data part where values
are stored and a pointer which indicates where the next node can be found. The linked list's
starting point denotes the head of the list, and the endpoints represent the node's tail also
known a Null.
Head
45 215 65
Tail
Figure 2.12: Linked list
With a linked list, a list of values that can easily be grown by storing values in different
parts of memory can be stored.
By the way, NUL refers to \0, a character that ends a string, and NULL refers to an
address of all zeros, or a null pointer (as pointing nowhere).
Unlike arrays, random access elements is not supported in a linked list because
the location of each element is identified by the link. For example, we can no
longer access an element of the list by calculating its position, in constant time,
instead, we have to follow each element’s pointer, one at a time. And we need to
allocate twice as much memory as we needed before for each element.
In code, we might create our own struct called node (like a node from a graph in
mathematics), and we need to store both an int and a pointer to the
next node called next:
• typedef struct node
• {
• int n;
• struct node *next;
• }
• node;
This struct can start with typedef struct node so that we can refer to
a node inside our struct.
We can build a linked list in code starting with our struct. First, we’ll want to
remember an empty list, so we can use the null pointer: node *list = NULL;.
To add an element, first thing is to allocate some memory for a node, and set its
values:
• node *n = malloc(sizeof(node));
• // We want to make sure malloc succeeded in getting memory for us:
• if (n != NULL)
• {
• // This is equivalent to (*n).number, where we first go to the
node pointed
• // to by n, and then set the number property. In C, we can also
use this
• // arrow notation:
• n->number = 2;
• // Then we need to store a pointer to the next node in our list,
but the
• // new node won't point to anything (for now):
• n->next = NULL;
• }
To add to the list, we’ll create a new node the same way, perhaps with the value
4. But now we need to update the pointer in our first node to point to it.
Since our list pointer points only to the first node (and we can’t be sure that the
list only has one node), we need to “follow the breadcrumbs” and follow each
node’s next pointer:
• // Create temporary pointer to what list is pointing to
• node *tmp = list;
• // As long as the node has a next pointer ...
• while (tmp->next != NULL)
• {
• // ... set the temporary to the next node
• tmp = tmp->next;
• }
• // Now, tmp points to the last node in our list, and we can update
its next
• // pointer to point to our new node.
If we want to insert a node to the front of our linked list, we would need to
carefully update our node to point to the one following it, before updating list.
Otherwise, we’ll lose the rest of our list:
• // Here, we're inserting a node into the front of the list, so we
want its
• // next pointer to point to the original list, before pointing the
list to
• // n:
• n->next = list;
• list = n;
And to insert a node in the middle of our list, we can go through the list,
following each element one at a time, comparing its values, and changing
the next pointers carefully as well.
With some volunteers on the stage, we simulate a list, with each volunteer acting
as the list variable or a node. As we insert nodes into the list, we need a
temporary pointer to follow the list, and make sure we don’t lose any parts of our
list. Our linked list only points to the first node in our list, so we can only look at
one node at a time, but we can dynamically allocate more memory as we need to
grow our list.
Now, even if our linked list is sorted, the running time of searching it will
be O(n), since we have to follow each node to check their values, and we don’t
know where the middle of our list will be.