CSC201Lesson 2
CSC201Lesson 2
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.
• 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
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.
QUEUE Figure 2.1: Stack (Entry and Exit are from the same point
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 of Max Heap
data structure.
HASH TABLE
In computer science, a hash table or hash map is a data structure 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
998
Robert Robert +234-8201030481
999
Figure 2.4: The Hash table
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.
.
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 in 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.
Depth-First Traversal Algorithm
In depth-first traversal, we visit the starting node and then proceed to follow links through the
graph until we reach a dead end. In an undirected graph, a node is dead end if all of the nodes
adjacent to it have already been visited. In a directed graph, if a node has no outgoing edges,
we also have a dead end. When we reach a dead end, we back up along our path until we find
an unvisited adjacent node and then continue in that new direction. The process will be
completed when we back up to the starting node and all the nodes adjacent to it have been
visited. Consider the graph in Figure 2.8
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
Shared Libraries
Translatio
…
Compiler Object
From Source code to program Execution
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.
• Reorganization: new memory layout for the combined pieces.
Functions of a loader
A loader places the executable code in main memory starting at a predetermined
location (base or start address).
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.
We can link our list together by allocating, for each element, enough memory for
both the value we want to store, and the address of the next element:
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:
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.