0% found this document useful (0 votes)
14 views210 pages

CBDS2103 Data Structure - Smay19 (RS & MREP)

Uploaded by

dayaalen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views210 pages

CBDS2103 Data Structure - Smay19 (RS & MREP)

Uploaded by

dayaalen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 210

CBDS2103

Data Structure

Copyright © Open University Malaysia (OUM)


CBDS2103
DATA STRUCTURE
Assoc Prof Dr Nantha Kumar Subramaniam
Marini Abu Bakar
Dr Sufian Idris
Nor Leyza Jailani
Roziah Latih

Copyright © Open University Malaysia (OUM)


Project Directors: Prof Dr Widad Othman
Prof Dr Siti Aishah Hashim Ali
Open University Malaysia

Module Writers: Assoc Prof Dr Nantha Kumar Subramaniam


Open University Malaysia

Marini Abu Bakar


Dr Sufian Idris
Nor Leyza Jailani
Roziah Latih
Universiti Kebangsaan Malaysia

Moderators: Mohd Shahidan Abdullah


Universiti Teknologi Malaysia

Siti Hajar Alias


Kolej Poly-Tech MARA

Aedah Abd Rahman

Enhancer: Jaspal Kaur Naranjan Singh


Open University Malaysia

Developed by: Centre for Instructional Design and Technology


Open University Malaysia

First Edition, December 2012


Second Edition, April 2014 (rs)
Third Edition, December 2018
Fourth Edition, April 2019 (MREP)
Copyright © Open University Malaysia (OUM), April 2019, CBDS2103
All rights reserved. No part of this work may be reproduced in any form or by any means without
the written permission of the President, Open University Malaysia (OUM).

Copyright © Open University Malaysia (OUM)


Table of Contents
Course Guide ix–xiv

Topic 1 Arrays 1
1.1 Concept of Array 3
1.2 One-dimensional Array 4
1.2.1 Declaring Array 4
1.2.2 Initialising Array Elements 7
1.2.3 Assigning and Accessing Array Elements 10
1.2.4 Operations on Array Elements 14
1.2.5 Array and Function 15
1.2.6 Sorting Array 16
1.3 Two-dimensional Array 18
1.3.1 Declaring 2D Array and Initialising 2D 18
ArrayÊs Elements
1.3.2 Assigning and Accessing 2D Array Elements 21
1.3.3 2D Array and Function 22
Summary 23
Key Terms 23

Topic 2 Structures 24
2.1 Concept of Structures 25
2.2 Declaring and Initialising Structure Elements 26
2.3 Referencing Structure Elements 29
2.4 Structure-type Array 31
2.5 Structure-type Structure 34
2.6 Structure and Function 36
2.6.1 Return Value Function 38
2.7 typedef Construction 40
Summary 41
Key Terms 41

Copyright © Open University Malaysia (OUM)


iv  TABLE OF CONTENTS

Topic 3 Pointers 42
3.1 Overview of a Pointer 43
3.2 Parameter Passing Using Pointer 46
3.3 Pointer and Array 49
3.3.1 Pointer and String 50
3.3.2 Array of Pointer 52
3.4 Dynamic Memory 54
3.5 Pointer and Structure 56
Summary 58
Key Terms 58

Topic 4 Lists and Linked Lists 59


4.1 List 60
4.1.1 Basic List Operations 61
4.1.2 Implementation of List Using Array 64
4.2 Linked List 65
4.2.1 Basic Linked List Operations 66
4.2.2 Implementation of Linked List Using Pointer 68
4.3 Differences between List and Linked List 78
Summary 81
Key Terms 81

Topic 5 Stacks 82
5.1 Stack Characteristics 84
5.2 Basic Stack Operations 85
5.3 Implementation Using Array 86
5.3.1 Declaring Stack Data Structure 87
5.3.2 Creating Stack 88
5.3.3 Checking Empty Stack 88
5.3.4 Checking Full Stack 89
5.3.5 Inserting Items into Stack 89
5.3.6 Removing Items from Stack 90
5.4 Stack Applications 91
5.4.1 Separating Even and Odd Numbers 92
5.4.2 Reverse Polish Notation (Postfix Notation) 97
Summary 104
Key Terms 104

Copyright © Open University Malaysia (OUM)


TABLE OF CONTENTS  v

Topic 6 Queues 105


6.1 Queue Basic Operations 107
6.2 Implementation of Queue Data Structure 108
6.2.1 Declaring Queue Data Structure 113
6.2.2 Creating Queue 114
6.2.3 Checking Empty Queue 114
6.2.4 Checking Full Queue 115
6.2.5 Inserting Items into Queue 115
6.2.6 Removing Items from Queue 116
Summary 118
Key Terms 118

Topic 7 Sorting 119


7.1 Simple Selection Sort 121
7.1.1 Simple Selection Sort Implementation Using 124
Array
7.1.2 Simple Selection Sort Algorithm Efficiency 125
7.2 Linear Insertion Sort 126
7.2.1 Linear Insertion Sort Implementation Using 128
Arrays
7.2.2 Linear Insertion Sort Algorithm Efficiency 129
7.3 Quick Sort 130
7.3.1 Quick Sort Implementation Using Array 135
7.3.2 Quick Sort Algorithm Efficiency 136
7.4 Bubble Sort 137
7.4.1 Bubble Sort Implementation Using Array 137
7.4.2 Bubble Sort Algorithm Efficiency 141
Summary 143
Key Terms 143

Topic 8 Searching 144


8.1 Basic Methods of Searching 144
8.1.1 Sequential Search 146
8.1.2 Binary Search 147
8.2 Analysis of Searching Algorithm 151
Summary 152
Key Terms 153

Copyright © Open University Malaysia (OUM)


vi  TABLE OF CONTENTS

Topic 9 Trees 154


9.1 General Structure of a Tree 155
9.2 Binary Tree 156
9.2.1 Data Structure for Binary Tree 157
9.3 Binary Search Tree (BST) 158
9.3.1 Creating BST 159
9.3.2 Searching BST 160
9.3.3 Inserting Nodes in BST 160
9.3.4 Traversing BST 165
9.3.5 Deleting Nodes in BST 168
9.4 Expression Tree 172
Summary 174
Key Terms 175
Reference 175

Topic 10 Graphs 176


10.1 Graph Concept and Terminologies 177
10.2 Types of Graph 178
10.2.1 Simple Graph 178
10.2.2 Directed Graph and Undirected Graph 179
10.2.3 Weighted Graph 181
10.2.4 Complete Graph 182
10.2.5 Cycle 182
10.3 Graph Representation and Storage Structure 183
10.4 Graph Operations 186
10.5 Graph Traversal 187
10.5.1 Breadth First Search 187
10.5.2 Depth First Search 189
Summary 192
Key Terms 193
Reference 193

Copyright © Open University Malaysia (OUM)


"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"

COURSE GUIDE
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"

Copyright © Open University Malaysia (OUM)


"
"
"
"
"
"
"
"
"
"

Copyright © Open University Malaysia (OUM)


COURSE GUIDE  ix

COURSE GUIDE DESCRIPTION


You must read this Course Guide carefully from the beginning to the end. It tells
you briefly what the course is about and how you can work your way through
the course material. It also suggests the amount of time you are likely to spend in
order to complete the course successfully. Please keep on referring to the Course
Guide as you go through the course material as it will help you to clarify
important study components or points that you might miss or overlook.

INTRODUCTION
CBDS2103 Data Structure is one of the courses offered at Open University
Malaysia (OUM). This course is worth 3 credit hours and should be covered over
8 to 15 weeks.

COURSE AUDIENCE
This course is offered to learners undertaking the Bachelor of Information
Technology programme and other IT-related programmes.

As an open and distance learner, you should be able to learn independently and
optimise the learning modes and environment available to you. Before you begin
this course, please confirm the course material, the course requirements and how
the course is conducted.

Copyright © Open University Malaysia (OUM)


x  COURSE GUIDE

STUDY SCHEDULE
It is a standard OUM practice that learners accumulate 40 study hours for every
credit hour. As such, for a three-credit hour course, you are expected to spend
120 study hours. Table 1 gives an estimation of how the 120 study hours can be
accumulated.

Table 1: Estimation of Time Accumulation of Study Hours

Study
Study Activities
Hours
Briefly go through the course content and participate in initial discussion 3
Study the module 60
Attend 3 to 5 tutorial sessions 10
Online participation 12
Revision 15
Assignment(s), Test(s) and Examination(s) 20
TOTAL STUDY HOURS ACCUMULATED 120

COURSE LEARNING OUTCOMES


By the end of this course, you should be able to:

1. Explain well-known data structures such as arrays, structures and pointers;


and

2. Write programs of data structures to implement algorithms for creation,


insertion, deletion, searching and sorting.

Copyright © Open University Malaysia (OUM)


COURSE GUIDE  xi

COURSE SYNOPSIS
This course is divided into 10 topics. The synopsis of each topic is presented
below:

Topic 1 introduces basic data structures using array. Array is the simplest data
structure that can be used in a program. In this topic, you will learn how to
declare, initialise, assign and operate an array. Both one-dimensional and two-
dimensional arrays will be discussed in this topic.

Topic 2 explains structures which hold information for a group of data. Unlike
arrays, structures can consist of different types of data type. These enable you to
write more efficient and readable programs. Understanding the concept of
structure is very important for you to comprehend the subsequent topics in this
module.

Topic 3 focuses on pointers. In the earlier topics, all the variable data types which
have been declared enable us to have direct access to the values that are kept in
storage by the program. In addition, C language allows us to declare variables
which keep the storage address. These are referred to as pointers.

Topic 4 covers lists and linked lists which are separate data structures. The
difference between both is that in a linked list, data items have links between
them but this is not the case in list data items which uses arrays. Last but not
least, the implementation of both data structures will be elaborated as well.

Topic 5 discusses stacks, which is another way to structure data using the last-in-
first-out (LIFO) approach. Basic stack operations such as create stack, test empty
stack, test full stack, remove element from stack and add element to stack will be
explained too in this topic.

Topic 6 touches on queues, which is a way to structure data using the first-in-
first-out (FIFO) approach. Basic queue operations such as create queue, test
empty queue, test full queue, remove elements from queue and add elements to
queue will be discussed in this topic too.

Topic 7 explores sorting, which is one of the important concepts in programming.


In this topic, you will learn various techniques of sorting and their efficiency in
the operation.

Topic 8 examines searching, which is the process of finding an element or data


that is required in a data structure. There are various types of searching methods
and some of them will be covered in this topic.

Copyright © Open University Malaysia (OUM)


xii  COURSE GUIDE

Topic 9 explores trees, which is one of the most important data structures and
which has many functions. It has been used in various applications, such as
gaming and intelligent systems. In this topic, you will learn the meaning of tree
data structure and how to implement binary search tree, which is a commonly
used type of tree.

Topic 10 introduces graphs, which is a natural model used to represent the


arbitrary relationship among data objects.

TEXT ARRANGEMENT GUIDE


Before you go through this module, it is important that you note the text
arrangement. Understanding the text arrangement will help you to organise your
study of this course in a more objective and effective way. Generally, the text
arrangement for each topic is as follows:

Learning Outcomes: This section refers to what you should achieve after you
have completely covered a topic. As you go through each topic, you should
frequently refer to these learning outcomes. By doing this, you can continuously
gauge your understanding of the topic.

Self-Check: This component of the module is inserted at strategic locations


throughout the module. It may be inserted after one sub-section or a few sub-
sections. It usually comes in the form of a question. When you come across this
component, try to reflect on what you have already learnt thus far. By attempting
to answer the question, you should be able to gauge how well you have
understood the sub-section(s). Most of the time, the answers to the questions can
be found directly from the module itself.

Activity: Like Self-Check, the Activity component is also placed at various


locations or junctures throughout the module. This component may require you
to solve questions, explore short case studies, or conduct an observation or
research. It may even require you to evaluate a given scenario. When you come
across an Activity, you should try to reflect on what you have gathered from the
module and apply it to real situations. You should, at the same time, engage
yourself in higher order thinking where you might be required to analyse,
synthesise and evaluate instead of only having to recall and define.

Summary: You will find this component at the end of each topic. This component
helps you to recap the whole topic. By going through the summary, you should
be able to gauge your knowledge retention level. Should you find points in the
summary that you do not fully understand, it would be a good idea for you to
revisit the details in the module.

Copyright © Open University Malaysia (OUM)


COURSE GUIDE  xiii

Key Terms: This component can be found at the end of each topic. You should go
through this component to remind yourself of important terms or jargon used
throughout the module. Should you find terms here that you are not able to
explain, you should look for the terms in the module.

References: The References section is where a list of relevant and useful


textbooks, journals, articles, electronic contents or sources can be found. The list
can appear in a few locations such as in the Course Guide (at the References
section), at the end of every topic or at the back of the module. You are
encouraged to read or refer to the suggested sources to obtain the additional
information needed and to enhance your overall understanding of the course.

SOFTWARE
The software application required for this subject needs to be downloaded from
myINSPIRE. You can use this software for tutorials and completion of tasks at
home.

PRIOR KNOWLEDGE
Learners of this course need to have basic knowledge in C programming
language.

ASSESSMENT METHOD
Please refer to myINSPIRE.

REFERENCES
Gilberg, R. F., & Forouzan, B. (1998). Data structures: A pseudocode approach
with C. Boston, MA: PWS.
Gottfriend, B. (2010). Programming with C. New York, NY: McGraw-Hill.

Kelley, A., & Pohl, I. (2008). A book on C. San Francisco, CA: Benjamin
Cumming.

Marini Abu Bakar. (1998). Struktur data menggunakan C. Petaling Jaya,


Malaysia: Prentice Hall.

Weiss, M. A. (2012). Data structures and algorithm analysis in C (2nd ed.).


Boston, MA: Addison Wesley.
Copyright © Open University Malaysia (OUM)
xiv  COURSE GUIDE

TAN SRI DR ABDULLAH SANUSI (TSDAS)


DIGITAL LIBRARY
The TSDAS Digital Library has a wide range of print and online resources for
the use of its learners. This comprehensive digital library, which is accessible
through the OUM portal, provides access to more than 30 online databases
comprising e-journals, e-theses, e-books and more. Examples of databases
available are EBSCOhost, ProQuest, SpringerLink, Books247, InfoSci Books,
Emerald Management Plus and Ebrary Electronic Books. As an OUM learner,
you are encouraged to make full use of the resources available through this
library.

Copyright © Open University Malaysia (OUM)


Topic  Arrays
1
LEARNING OUTCOMES
By the end of this topic, you should be able to:
1. Describe the concept of array;
2. Solve programming problems using one-dimensional array and
two-dimensional array; and
3. Solve programming problems using arrays that involve functions.

 INTRODUCTION
Hello there and welcome to CBDS2103 Data Structure. Before we go further and
explain data structures, let us start with a basic question  what is a computer?

A computer is a machine that manipulates information.

The study of information technology or computer science therefore, inevitably,


includes the study of:

(a) How information is organised in a computer;

(b) How it can be manipulated; and

(c) How it can be utilised.

Thus, it is vital to understand the concept of information organisation and


manipulation.

Copyright © Open University Malaysia (OUM)


2  TOPIC 1 ARRAYS

The study of different structures for representation of data and the algorithms
that operate on these structures is known as a study of data structures. A „data
structure‰ which displays the relationship of adjacency between elements is called
„linear‰. This type of data structures is used to represent one of the simplest and
most commonly found data object, which is, an ordered or linear list.

Let us look at some examples of an ordered or linear list.

Months of the year


[January, February, March, ⁄, December]

Or

The states in Malaysia


[Johor, Kedah, Kelantan, Malacca, Negeri Sembilan, Pahang, Penang,
Perak, Perlis, Sabah, Sarawak, Selangor, Terengganu]

Or

A group of friends
[Sudha, Sze Hong, Neeraj, Azim, Salim]

If we view an ordered list more abstractly, we say that it is either empty or it can
be written as:

[x1, x2, x3, ...... xi]

where xi are atoms or elements from some set A.

Did you know that there are a variety of operations that can be performed on linear
data structures? These operations include:

(a) Find the length of the list, n;

(b) Read the list from left to right or right to left;

(c) Retrieve the i th element of the list, 1 i n;

(d) Store a new value into the i th position, 1 i n;

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  3

(e) Insert a new element at position i, 1 i n causing elements numbered i,
i  1, ⁄ n to become numbered i  1, i  2 ... n  1; and

(f) Delete the element at position i, 1 i n causing elements numbered i  1, ⁄
n to become numbered i, i  1, ... n  1.

Take note that the simplest linear data structures that makes use of computed
addresses to locate its elements is a one-dimensional array.

Therefore, this topic will discuss the concept of arrays, one-dimensional array and
two-dimensional arrays as well as how to use them in programming. So are you
ready? Let us start with the lesson!

1.1 CONCEPT OF ARRAY


What are variables? Can you compare the concept of variables and arrays?
Variables are used to store information that can be referenced and manipulated in
a computer program.

How do we declare and use a variable? In order to declare and use a variable, we
need to associate a name and the data type to represent a particular value.
Similarly, an array also has a name and a data type that will identify it. However,
an array can hold multiple elements, whereas a variable holds a single value.

In C programming language, it is common to define a collection of characters such


as student name using an array of characters. So what does array mean?

Arrays are data structures that contain data items of the same type.

Did you know that they are also called static data structures? This means that the
size of the array is fixed from the declaration all the way to the final program
implementation.

Why do we need arrays in our programming? This question can be answered by


giving an example. Let us say that you would like to keep a record of your personal
spending for the year 2018. You can file all your receipts and details of expenditure
in multiple files according to the respective months. This means that you have
12 different files. However, would it not be easier if you could manage a single file
with 12 compartments?

Copyright © Open University Malaysia (OUM)


4  TOPIC 1 ARRAYS

Now, let us relate this scenario to computer programming. Let us just say that we
would like to write a program to manage your expenses. Your program can declare
12 separate variables to represent the total monthly expenditure (just like how we
would use 12 files to store the receipts). However, we could further improve the
program by using an array that has 12 elements, that is, by storing the monthly
total spending in each of the array elements.

1.2 ONE-DIMENSIONAL ARRAY


Now, let us move on to one-dimensional array. What does it stand for?

A one-dimensional array is an array that has only one index or subscript.

What is an index?

An index is a value that is written in the brackets [ ] after an array name.

Did you know that an index can identify the number of elements in an array? This
is explained in the following subtopic.

1.2.1 Declaring Array


Did you know that it is easy to declare an array? We can use the same method that
we use to declare normal variables but the difference lies in that the name of the
array must include the array size specification (which is enclosed by the „[‰ and
„]‰ symbols).

In general, we can declare a one-dimensional array as follows:


data_type array_name[number_of_elements];

Which can be explained as:


data_type  Type of data that will be stored in the array, i.e. int,
float, char, double.
array_name  The name of the array.
number_of_elements  A positive integer that indicates how many elements
should be stored in the memory.

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  5

The value of number_of_elements will decide the number of data values that
can be stored in the array. The number of this data values can also be referred to
as array size.

Let us have a look at the following example of array declaration:


int number[10];

Take note that this statement will declare an array that is called number and is of
size 10. This declaration will instruct the compiler to reserve 10 memory spaces in
sequence, which can be referred to as number. This sequence of memory spaces is
also known as array elements. Since the data_type for number is declared as
being the int type, therefore the number array elements can contain data of int
type only. This relationship is illustrated in Figure 1.1.

Figure 1.1: Illustration of memory location for the declaration of int number[10]

The value within the [ ] brackets is also known as array index. Keep in mind that
the array index always begins with 0 and ends with the size of the array subtracted
by 1. In the previous example, the array index of number begins with 0 and ends
with 9. With this, the array element values can be referred to as number[0],
number[1], ... number[9].

Copyright © Open University Malaysia (OUM)


6  TOPIC 1 ARRAYS

Remember, the array size must be an integer and consists of an expression which
is evaluated to determine the index. If a program uses an expression as an index,
then the expression is evaluated to determine the index. For example, if a = 5 and
b = 6, then the statement:

Keep in mind that arrays may be declared to contain other data types. For example,
an array of type char can be used to store a character string.

ACTIVITY 1.1

1. Declare a suitable array for each of the following:


(a) An array for 30 bank balances.
(b) An array for customer addresses.

2. Identify the statement that declares an array that is of data type


float, is called marks and is of size 20.
A. float marks(20);
B. float marks [20];

C. float *marks [20];

3. Which statement describes an array correctly?


A. An array is the same as a variable.
B. An array can contain different data types.
C. An array must include size specification.

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  7

SELF-CHECK 1.1

Define one dimensional array and index.

1.2.2 Initialising Array Elements


How do we initialise array elements? For array variables, we can set the initial
values for each array element during the declaration. For example:
int digit[10] = {7, 5, 3, 8, 0, 9, 2, 4, 1, 6};

Array elements can come in two type of values:

(a) Array with Initial Values


In the previous example, int digit[10] = {7, 5, 3, 8, 0, 9, 2,
4, 1, 6}; can be illustrated as in Figure 1.2.

Figure 1.2: Array initialisation and memory location illustration

Remember, all the array elements that are not given initial values will be set
with the value of 0 automatically (see the following example):
int digit[10] = {1, 2, 3};

Copyright © Open University Malaysia (OUM)


8  TOPIC 1 ARRAYS

Here, the digit array will have sequential values as shown in Figure 1.3.

Figure 1.3: Partial initialisation of elements and memory location illustration

(b) Array with Partial Initial Values


Another easy way of declaring arrays is by listing the initial values of the
elements, without declaring the size of the array. Have a look at the following
array declaration. Here, the size of the digit array is 5, based on the number
of elements in the initial value list.
int digit[] = {1, 2, 3, 4, 5};

SELF-CHECK 1.2

Draw a diagram that illustrates the memory location for the declaration
of the digit array in Subtopic 1.2.2(b).

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  9

ACTIVITY 1.2

1. Which array initialisation will assign odd numbers from 1 to 5 to an


array named Odd?

(Note: Any integer that cannot be divided exactly by 2 is an odd


number.)

A. int Odd [3] = {1, 3, 5};

B. int Odd [5] = {1, 2, 3, 4, 5};

C. int Odd [5] = {1, 3, 5, 7, 9};

2. An array called Height has five values and is initialised with the
values as below.
float Height[ ] = {1.2, 1.45, 1.3, 1.55, 1.4};

Why is the array size not written?

A. The array size is necessary to be written for all array


declarations but this declaration is invalid.

B. The array size is flexible based on the memory allocations


given to the array at runtime.

C. When declaring arrays using initial values list, it is not


necessary to write the array size.

Copyright © Open University Malaysia (OUM)


10  TOPIC 1 ARRAYS

1.2.3 Assigning and Accessing Array Elements


We have looked at the array index that enables us to differentiate every element in
an array. The array index also enables us to refer to the elements in an array. For
example, let us look at the digit array declaration again:
int digit[10] = {7, 5, 3, 8, 0, 9, 2, 4, 1, 6};

We can refer to the first array element as digit[0], the fifth element as
digit[4] and so on. Here, observe that the value of digit[0] is 7, while the
value of digit[4] is 0 (see Figure 1.4).

Figure 1.4: Memory elements of digit array

We can assign any data values for each of the array element that has been defined
by using the assignment statement.

However, the value that is assigned must be the same data type with the type of
data contained within the array. Look at the following example:

Example 1.1:

int digit[10]; /* Declare digit array of size 10 */


digit[0] = 7; /* Assign 7 to the first element */
digit[1] = 5; /* Assign 5 to the second element */
digit[2] = 3; /* Assign 3 to the third element */
digit[3] = 8; /* Assign 8 to the fourth element */
digit[4] = 0; /* Assign 0 to the fifth element */
digit[5] = 9; /* Assign 9 to the sixth element */

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  11

digit[6] = 2; /* Assign 2 to the seventh element */


digit[7] = 4; /* Assign 4 to the eighth element */
digit[8] = 1; /* Assign 1 to the ninth element */
digit[9] = 6; /* Assign 6 to the tenth element */

We declared the digit array without initial values. Each of the following
assignment statement assigns values to the array element. As a result, we will have
an array that is the same array as in Figure 1.4.

Keep in mind that assigning values to array elements is the same as assigning
values to a variable. The difference is that we need to state the array index that is
being referenced.

Just as in normal assignment statements, the right-hand side part of the assignment
statement for the array element can also be an expression. Look at the following
example:

Example 1.2:

int X[3]; /* Array declaration of 3 elements */


X[0] = 2; /* Assign 2 to X[0] */
X[1] = 3  4; /* Assign 7 to X[1] */
X[2] = 5 * 6; /* Assign 30 to X[2] */

The expression on the right-hand side of the assignment statement can also contain
elements of the same array. Now, let us look at Example 1.3.

Example 1.3:

int Y[5]; /* Array declaration of 5 elements */


Y[0] = 1; /* Assign 1 to Y[0] */
Y[1] = Y[0] * 2; /* Assign Y[0] * 2 expression to Y[1] */
Y[2] = Y[1] * 3; /* Assign Y[1] * 3 expression to Y[2] */
Y[3] = Y[2] * 4; /* Assign Y[2] * 4 expression to Y[3] */
Y[4] = Y[3] * 5; /* Assign Y[3] * 5 expression to Y[4] */

Can you figure out the values that are assigned to Y[0] to Y[4]?

Copyright © Open University Malaysia (OUM)


12  TOPIC 1 ARRAYS

The values that are assigned in these assignment statements are explained in
Figure 1.5.

Figure 1.5: Assignment statements that involve Y array elements for Example 1.3

Take note that array indexes do not necessarily have to be constant values. We can
also use int type expression as an array index.

However, the value of the index must be in the range of 0 and the value that is one
less than the size of the array (see Example 1.4).

Example 1.4:

int a = 0;
x[a] = 5;

In this example, x[a] <==> x[0] because a = 0.

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  13

SELF-CHECK 1.3

1. Look at the assignment given below. The comments are given as a


guide. Based on your understanding of the examples given earlier
and the illustration in Figure 1.5, draw an array based on the
following statements:
int S[5]; /* Declare array with 5 elements */
int i = 0, j = 1;
S[i] = 8; /* Assign 8 to S[0] */
S[j] = S[i] + 5; /* Assign S[0] + 5 to S[1] */
S[j+1] = S[i] * S[j]; /* Assign S[0] * S[1] to S[2] */
S[j*3] = S[i + 2]; /* Assign S[2] to S[3] */
S[j*4] = S[j * 2]; /* Assign S[2] to S[4] */

2. Referring to the arrays that are declared below, state the values that
are assigned to each array element.

(a) int abc[6] = {0, 2, 4, 6, 8, 10};

(b) float c[5] = {2.0, 0.5, 1.2, 0.3};

(c) int xyz[10] = {5, 10, 0, 10, 5, 0, 0};

3. Given the following program segments, what are the values of the
array elements at the end of the respective segments?

(a) int M[5] = {2, 3}; (b) int R[4], i = 1;


M[2] = M[1] * 3; R[i - 1] = 8;
M[3] = M[2] * 1; R[i] = R[I - 1] * 8;
M[4] = M[0] * 2 * 3; R[i + 1] = R[i]  10;
R[i + 2] = R[i] * 5;

Copyright © Open University Malaysia (OUM)


14  TOPIC 1 ARRAYS

1.2.4 Operations on Array Elements


Did you know that in C language, we cannot implement an operation for the whole
array? This means that, if a and b are of the same arrays (having the same data
type, size and dimension), operations like assignment, comparison and the like,
should be performed element by element.

This is usually done by using the loop structure, where each loop will perform an
operation on a single array element. The number of loops is usually the same as
the number of elements in the array.

Look at the following Example 1.5.

Example 1.5:
The code below shows how to copy the contents of array A to array B.
int A[5] = {2, 4, 6, 8, 10};
int B[5];
int i;
/* Copy one by one each array element in A to array B */
for (i = 0; i < 5; i++)
B[i] = A[i];

SELF-CHECK 1.4

Values from array A are to be inserted into array B, incrementing each of


the values to be double of its original value. Which one of the options
below correctly shows the insertion and increment?

A. A[i] = B[i] * 2;

B. B[i] = A[i] * 2;

C. B[i] = A[i] + B[i];

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  15

ACTIVITY 1.3
There are many operations that can be performed on array
elements. One of the examples is the addition operation (visit
https://phanderson.com/C/arraysum.html to see the coding). Copy and
run the coding. Write out the output in the myINSPIRE forum.

1.2.5 Array and Function


We have discussed functions in the previous Computer Programming module.
Can you still recall? Why do we need to use functions? By using functions, our
program code becomes more modular.

We can also use this concept with arrays and functions. In fact, we can pass the
entire array to a function, as a parameter. However, the way that an array is passed
to a function is quite different from the way other types of data are passed to
functions. The array is passed to the function by reference. This means in order to
pass an array to a function, we need to state the array name only (without any
bracket symbols or index numbers) as a function parameter and the entire array
will be sent to the function. In the definition of the function, the name of the array
must be written in brackets but without stating the size of the array.

Let us look at Example 1.6.

Example 1.6:
// function prototype
void modifyHours(int [], int);

// main function
// declaring array variable
int WorkingHours[24];
Refers to the same
// call the function
array
modifyHours (WorkingHours, 24);

// function definition
void modifyHours (int b[], int size)
{
...
}

Copyright © Open University Malaysia (OUM)


16  TOPIC 1 ARRAYS

The code shows a function called modifyHours that will get an array called
WorkingHours. Pay attention to how the function prototype, function call and
function definition are written. Take note that any changes made to the arrayÊs
values in the function, will change the original contents of the array. This is
important, as we are referencing the array in the function.

In the function prototype, the first parameter indicates that an array will be passed
to the function and it is not necessary to provide the name of the array at this time.
In the main function, the array WorkingHours is declared and then, in order to
pass this array to the function modifyHours, we put in only the name of the array
as the first parameter.

Lastly, in the function definition, you may create an array named b that will receive
the values of the WorkingHours array. Here, the name of the array b is written as
the first parameter in the brackets but without stating the size of the array.

An individual element in an array can also be passed to a function. However, it


will be passed like a normal variable, which is passed by value. To pass the
individual element, use the subscripted name of the array element as a parameter
in the function call.

ACTIVITY 1.4
Visit https://phanderson.com/C/arraysum.html again. This time,
examine how functions are used with arrays. Modify all the program
codes if functions are not used. Will the answers still be the same? Write
down your output (if any) in the myINSPIRE forum.

1.2.6 Sorting Array


There are many C programming applications that use arrays and functions, such
as sorting or searching for values in an array. Look at the code in Example 1.7 to
learn how sorting is done in an array by passing the array by reference to a
function.

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  17

Example 1.7:
An integer array with 10 values are created and is assigned values entered by the
user. The array is then passed to a function where the values in the array are sorted.
// function prototype
void numberSort (int []);
// main function
// array declaration
int number[10];
// input values
for (i = 0; i < 10; i++)
scanf(“%d”, &number[i]);
// function call
numbersort(number);
// function definition
void numberSort (int num[]) {
int j, k, temporary;
for (j = 0; j < 10; j++) {
for (k = j + 1; k < 10; k++) {
if (num[j] > num[k]) {
temporary = num[j];
num[j] = num[k];
num[k] = temporary;
}
}
}
}

Copyright © Open University Malaysia (OUM)


18  TOPIC 1 ARRAYS

Pay attention to the way we write the function prototype, function call and the
function definition of the function numberSort. For complete examples of the
codes, please refer to myINSPIRE.

1.3 TWO-DIMENSIONAL ARRAY


Now, let us move on to two-dimensional array. What does it stand for?

Two-dimensional array can be regarded as a two-dimensional matrix that has


rows and columns.

Remember, the two-dimensional array elements must also be of the same data
type, arranged in such a way that it looks like arrays on top of arrays. This array
has two indexes, one, for the number of rows and the other for the number of
columns.

In addition, we can calculate the number of elements in a two-dimensional array


by multiplying its number of rows and number of columns.

1.3.1 Declaring 2D Array and Initialising 2D


Array’s Elements
How do we declare array and initialising its elements? The following is the
declaration for a two-dimensional array:
data_type array_name[number_of_row][number_of_column];

Where:

data_type  Type of data stored in the array

array_name  Name for the array

number_of_row  A positive integer that represents the rows of the array

number_of_column  A positive integer that represents the columns of the


array

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  19

Take note that the [ ] [ ] (brackets) identify the two-dimensional array and the
enclosed numbers indicate the number of rows and columns.

For example, the statement int table [3][4]; declares an integer type two-
dimensional that consists of three rows and four columns. The compiler creates the
array table, which reserves memory space for 12 integer type elements, which is
the number of row 3, multiplied by the number of column 4.

Let us assume that we would like to store a set of examination marks for
50 students and each student has 10 examination scores. The data of the marks can
be stored by using a two-dimensional array as follows:
int marks[50][10];

With this declaration, the compiler will set aside 500 memory cells (which is
50  10) as illustrated in Figure 1.6.

Figure 1.6: Memory location illustration for the declaration of int marks[50][10]

Each element can be referred to by using the name of the array, as well as the
row index and column index. For example, marks[1][9] refers to the
10th examination mark for the second learner, as shown in Figure 1.6.

The element contents of this two-dimensional array can be initially assigned


during the array declaration, similar to how we would assign initial array element
values for one-dimensional arrays. For example, the following square array:
int square[4][4] = { {1, 2, 3, 4}, {2, 3, 4, 5},
{3, 4, 5, 6}, {4, 5, 6, 7}};

Copyright © Open University Malaysia (OUM)


20  TOPIC 1 ARRAYS

The element contents of the square array can be illustrated as in Figure 1.7.

Figure 1.7: Memory cell content for the declared square array

ACTIVITY 1.5

Refer to Multi-dimensional Arrays in C from the following link:


https://www.tutorialspoint.com/cprogramming/c_multi_dimensional
_arrays.htm

Copy the coding given in the website and run it. Do you get the same
output?

SELF-CHECK 1.5

Declare a two-dimensional array that has three rows and five columns
called pqr. Assign the initial values for each row element of the first row
with value 1, the second row element with value 2 and each element in
the third row with value 3.

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  21

1.3.2 Assigning and Accessing 2D Array Elements


In order to assign initial values or to access an array element in a two-dimensional
array, we need to state the name of the array along with the row and column
indexes. For this, we can use a nested loop as shown in Example 1.8 that reads 16
values to be stored in the square array.

Example 1.8:

int square[4][4];
int i, j;

for (i = 0; i < 4; i++)


for (j = 0; j < 4; j++) {
printf(“Enter a value: “);
// Assigning values to the array elements
scanf(“%d”, &square[i][j]);
}

SELF-CHECK 1.6

State the values that are assigned to each following array element:

(a) int p[2][4] = {{2, 4, 6, 8}, {1, 3, 5, 7}};

(b) int q[2][4] = {{2, 4}, {1, 3}};

Copyright © Open University Malaysia (OUM)


22  TOPIC 1 ARRAYS

1.3.3 2D Array and Function


Lastly, let us look at 2D array and function. How do we pass a two-dimensional
array to a function? Passing a two-dimensional array to a function is done by
referencing, which is the same as passing a one-dimensional array to a function.
Keep in mind that only the name of the array needs to be stated in the function
call. Observe the following code in Example 1.9.

Example 1.9:

// function prototype
void read5YearRainfallDistribution (int rain[][12]);

// main function
// two-dimension array declaration
int rain[5][12];
// function call
read5YearRainfallDistribution(rain);

//function definition
void read5YearRainfallDistribution(int rain[][12])
{
...
}

Here, read5YearRainfallDistribution is a function that will receive the


two-dimensional array, called rain. Notice how the function call is written, where
the name of the two-dimensional array is written by itself without the [] for the
row and column. This type of passing of the two-dimensional array to the function
is called passing by reference and the original value of the two-dimensional array
will change if there are any changes made to the two-dimensional array in the
function definition.

Copyright © Open University Malaysia (OUM)


TOPIC 1 ARRAYS  23

 Arrays are data structures that contain data items that are related and of the
same type. They can be in one or more dimensions.

 A one-dimensional array is an array that has only one index or subscript.

 A two-dimensional array can be regarded as a two-dimensional matrix that


has rows and columns.

 In general, we can declare a one-dimensional array as data_type


array_name[number_of_elements];

 We can set the initial values for each array element during declaration.

 The declaration for a two-dimensional array is data_type


array_name[number_of_row][number_of_column];

 We can use functions in arrays so that our program code is more modular.

 Passing a two-dimensional array to a function is done by referencing.

Array Initialising
Assigning One-dimensional array
Column Referencing
Declaring Row
Elements Sorting
Functions Two-dimensional array
Index

Copyright © Open University Malaysia (OUM)


Topic  Structures
2
LEARNING OUTCOMES
By the end of this topic, you should be able to:
1. Describe the concept of structure;
2. Declare and initialise structure elements;
3. Refer structure elements;
4. Apply the structure-type array and structure-type structure; and
5. Use the structure in the function and typedef construction.

 INTRODUCTION
In the previous Topic 1, we have learned about arrays. If you recall, arrays are data
structures that have all elements of the same type of data.

In this second topic, we shift our focus to structures that are groups of data that
can have elements consisting of different types of data. This data structure is very
important in writing programs relating to manipulating various types of data that
are similar to databases.

We will also discuss structures in the C programming language. We shall look at


how structures are declared and how each of its elements can be accessed and
processed in programming. The relationship between structure and array, as
well as the function, shall also be discussed. So are you ready? Let us continue
with the lesson.

Copyright © Open University Malaysia (OUM)


TOPIC 2 STRUCTURES  25

2.1 CONCEPT OF STRUCTURE


What do you understand about structure? Can you compare structure with
variable and array? Before we go further into the topic of structures, let us first
understand the concept of structure. Firstly, its meanings.

A structure is a combination of bits of data from different sources and types.

Unlike arrays, structures can combine the data of different types and can be
referred to using the same name. Let us assume that we want to create an account.
We would need the following information:
(a) Account number;
(b) Type of account;
(c) Name of account holder; and
(d) Savings balance.

After identifying each data element, we need to decide the data type to represent
each element. Table 2.1 shows the data that could possibly represent the account
information.

Table 2.1: Data Representation for Account Information

Element Name Data Type


Account number Integer
Type of account Character
Name of account holder 30 character string
Savings balance Real

SELF-CHECK 2.1

1. What are the advantages of structure compared to array?


2. Identify the elements which can represent a learner at OUM. Then,
for each element, identify the data types that can represent it.

Copyright © Open University Malaysia (OUM)


26  TOPIC 2 STRUCTURES

2.2 DECLARING AND INITIALISING


STRUCTURE ELEMENTS
How do we declare and initialise structure elements? In general, the template for
declaring structure is by using the struct construction, which is as follows:
struct struct_name {
data_1_definition;
data_2_definition;
:
data_n_definition;
};

where

structure_name  Name of the constructed struct that must fulfil the


naming rule of a variable.

data_*_definition  Data type definition for each element that forms the
structure.

Let us look at the following Example 2.1 of a structure declaration.

Example 2.1:

struct account {
int accountNo;
char accountType;
char name[30];
float balance;
};

Copyright © Open University Malaysia (OUM)


TOPIC 2 STRUCTURES  27

Take note that before using the declaration of the structure in a program, we need
to declare the variable of struct type. This variable of type struct can be
declared as follows:

struct structure_name variable_name;

where

structure_name  Name for the structure that has been declared.

variable_name  Name for the variable that represents the structure.

Observe that

Declares the myAccount variable as an account structure.

Based on the previous variable declaration, the memory space that is reserved for
myAccount is as shown in Figure 2.1.

Figure 2.1: Memory space for myAccount declaration

Copyright © Open University Malaysia (OUM)


28  TOPIC 2 STRUCTURES

We can also declare the variable by listing the variable names at the end of the
structure declaration. Let us observe the declaration of the following variable
where oldAccount and newAccount are variables of type account (see
Example 2.2).

Example 2.2:

struct account {
int accountNo;
char accountType;
char name[30];
float balance;
} oldAccount, newAccount;

As with other types of data, we can also initialise the value of a structure. For
example:
struct account myAccount = {1234, ‘S’, “Nadiah”, 1998.88};

SELF-CHECK 2.2
1. Sketch the memory space for the account structure myAccount if
it is initialised in the following way:
struct account myAccount = {1234, ‘S’,
“Nadiah”, 1998.88};

2. Based on the structure given below, what is the variable declared?


struct date {
int day;
int month;
int year;
} anniversary;

A. anniversary
B. date
C. day, month, year

Copyright © Open University Malaysia (OUM)


TOPIC 2 STRUCTURES  29

3. Based on the structure given in Question 2, which structure variable


initialisation option is correct?
A. anniversary = {1,1,1999};
B. date = {1,1,1999};
C. day = 1; month = 1; year = 1999;

2.3 REFERENCING STRUCTURE ELEMENTS


Did you know that the elements of a structure are normally processed
individually? In other word, separately. Therefore, we must be able to access each
of the structure elements. How do we do that? This can be achieved by using a „.‰
(dot) operator as follows:
variable.data_definition

where

variable  Name of declared structure variable.

data_definition  Element in the structure that is referred.

Observe the following example.

Example 2.3:

myAccount.accountNo = 1234;
myAccount.accountType = ‘S’;
strcpy(myAccount.name, “Nadiah”);
myAccount.balance = 1998.88;

This example assigns values to the structure elements. In actual fact, this type of
data assignment is equivalent to giving initial values to a structure.

Let us have a look at the following code. This code shows how the input and output
of structure elements are performed (see Example 2.4).

Copyright © Open University Malaysia (OUM)


30  TOPIC 2 STRUCTURES

Example 2.4:

printf(“Account number: “);


scanf(“%d”, &myAccount.accountNo);
printf(“Account type: “);
scanf(“%c”, &myAccount.accountType);
printf(“Name: “);
gets(myAccount.name);
printf(“Balance: “)
scanf(“%f”, &myAccount.balance);
printf(“Name: %s\n, Account number: %d\n, Account type:
%c\n, Savings balance: %.2f\n”, myAccount.name,
myAccount.accountNo, myAccount.accountType,
myAccount.balance);

The C programming language offers a library function called strcpy, defined in


the string.h header file that allows the data to be assigned into a character array,
such as names and addresses. To input and output character arrays, you may use
the gets() and puts() functions that are available in stdio.h header file,
instead of the scanf() and printf() functions. Observe that the & operator is
used to represent the address for each structure element that is to be assigned with
a new value.

Copyright © Open University Malaysia (OUM)


TOPIC 2 STRUCTURES  31

ACTIVITY 2.1

1. Given the following structure declaration:


struct customerInfo {
char name[30];
int customerNo;
char telephoneNo[10];
}customer;

Which statement will display the customerNo?

A. printf(“%d”, customerNo);

B. printf(“%d”, customer.customerNo);

C. printf(“%d”, customerInfo.customerNo);

2. Using the same structure as in Question 1, assign the name


„Aisyah‰ to the customer.

A. customername = “Aisyah”;

B. customer.name = “Aisyah”;

C. puts(customer.name = “Aisyah”);

2.4 STRUCTURE-TYPE ARRAY


How do we represent a group of data from the same type of structure? To represent
a group of data from the same type of structure, we use an array representation of a
structure-type. How do we declare it? We declare the array of structure-type as
follows:
struct account customer[500];

The previous declaration declares customers variable as an array of 500 elements


of account structure-type. Each field for these array elements can be referred to
directly.

Copyright © Open University Malaysia (OUM)


32  TOPIC 2 STRUCTURES

For example, we can assign customer[14].accountNo (since the index


begins with 0) as the reference for the 15th customerÊs account number (see
Example 2.5).

Example 2.5:

customer[14].accountNo = 122;
printf(“The 15th customer’s account number: %d\n”,
customer[14].accountNo);

We can also refer to the savings balance for the last customer as
customer[499].balance (see Example 2.6).

Example 2.6:

customer[499].balance = 8755.02;
printf(“The 500th customer’s balance: %.2f\n”,
customer[499].balance);

Besides that, we can refer the first character for the name of the first customer as
customer[0].name[0]. Let us now look at Example 2.7.

Example 2.7:

strcpy(customer[0].name, "Nadiah");
printf(“The name of the first customer begins with the
letter %c\n”, customer[0].name[0]);

SELF-CHECK 2.3
You have previously sketched the memory space for arrays in Topic 1.
How about the memory space for the account structure-type array? Can
you sketch it as well?

Copyright © Open University Malaysia (OUM)


TOPIC 2 STRUCTURES  33

ACTIVITY 2.2
1. Given the following structure declaration:
struct book {
char title[50];
int year;
float price;
}books[50];

Which option will assign the first bookÊs title?

A. strcpy(books.title, “C programming”);

B. strcpy(books[0].title, “C programming”);

C. strcpy(book[50].title[50], “C programming”);

2. Based on the structure in Question 1, which option will assign the


year 2018 to all the books.

A. for (i = 0; i < 50; i++)


books.year = 2018;

B. for (i = 0; i < 50; i++)


books[i].year = 2018;

C. for (i = 0; i < 50; i++)


books.year[i] = 2018;

Copyright © Open University Malaysia (OUM)


34  TOPIC 2 STRUCTURES

2.5 STRUCTURE-TYPE STRUCTURE


Did you know that we can also declare a structure element as another type of
structure? Look at the Example 2.8.

Example 2.8:

struct date {
int day;
int month;
int year;
};
struct account2 {
int accountNo;
char accountType;
char name[30];
float balance;
struct date transaction;
};

Notice that the date structure is written before it is used in the account2
structure. Here transaction represents the last transaction date that is declared
as a structure type date. This declaration is shown in the following Figure 2.2.

Figure 2.2: Memory space for the declaration of account2

Copyright © Open University Malaysia (OUM)


TOPIC 2 STRUCTURES  35

Assuming that we declare the following:


struct account2 newAccount;

We can refer to the month of the last transaction for newAccount as


newAccount.transaction.month

Also, assuming we declare:


struct account2 newCustomer[100];

We can refer to the year of the last transaction for the 10th newCustomer as
newCustomer[9].transaction.year.

ACTIVITY 2.3
1. Given the following declaration:
struct information {
char telephoneNo[10];
char address[50];
char postcode[5];
char city[15];
char state[15];
};
struct customerInfo {
char name[30];
int customerNo;
struct information personal;
} customer;
Write the statement to access the following structure elements for:
(a) Customer name
(b) Customer number
(c) Telephone number
(d) Postcode

Copyright © Open University Malaysia (OUM)


36  TOPIC 2 STRUCTURES

2. Using the structure declarations given in Question 1, write


statements to assign the following information to the customer
variable.

Customer Information Details


Name Aisyah
Number 1226
Telephone number 011-333011
Address No. 21, Jalan Kenangan
Postcode 02000
City Seri Intan
State Darul Mulia

2.6 STRUCTURE AND FUNCTION


In C language, a structure is passed to a function by value. This means that the
structure value is copied for processing, in the body of the function. Therefore, any
changes made to the value by the function would not give any effect on the value
of the structure variable that is copied.

Copyright © Open University Malaysia (OUM)


TOPIC 2 STRUCTURES  37

Observe Example 2.9.

Example 2.9:

//Structure declaration
struct date{
int day;
int month;
int year;
The dte variable of date
}; structure type is passed
// function prototype to the increaseDate
function by value and the
void increaseDate (struct date t);
original dte value is still
// main function maintained.
void main( ) {
struct date dte = {20, 1, 2018};
increaseDate (dte);
printf(“%d/%d/%d”, dte.day, dte.month, dte.year);
}
// function definition
void increaseDate(struct date t) {
(t.year)++; /* The year element is increased */
}

The dte variable of the date structure type is passed by value to the
increaseDate() function. This increaseDate() function increases the year
element.

However, when the function ends, the value of the year element for the dte
structure in the main() function is still the same as the value before the
increaseDate() function was called. This means that the output that is printed
is 20/1/2018.

As with other arrays, the passing of the structure array to the function is performed
by reference.

Copyright © Open University Malaysia (OUM)


38  TOPIC 2 STRUCTURES

2.6.1 Return Value Function


We can return a structure from a function, using the statement return. Let us look
at Example 2.10.

Example 2.10:

// function prototype
struct date addYear(struct date dte, int);

The dte variable of the date


// main program structure type is passed to the
void main() { addYear function by value and
the original dte value is still
// variable declaration maintained.
struct date dte = {31, 10, 2018};
struct date t1;

// function call
t1 = addYear(dte, 3);
}
struct date addYear(struct date t, int i) {
t.year += i;
return t;
}

The dte variable of date structure type and value 3 is passed to the function
addYear() by value. This means that the value of the dte structure is copied to
the parameter t, while 3 is assigned to the parameter i in the function. This
function will add the i value to the year element (year = 2018 + 3 = 2021).

Then, the t variable of the date structure type (with the day = 31, month =
10, year = 2021 values) is returned with the return statement. The value
that is returned is assigned to the t1 structure.

Copyright © Open University Malaysia (OUM)


TOPIC 2 STRUCTURES  39

SELF-CHECK 2.4

A structure, when passed to a function, will copy the structure value for
processing in the body of the function. Any changes made to the values
of the structure by the function would not give any effect on the values
of the structure variable copied. What is this called?

A. Passing by reference

B. Passing by value

C. Passing by variable

ACTIVITY 2.4

A student structure is declared as below:


struct student {
int id;
char name[50];
} fulltimestudent;

This structure is to be sent to a function that will display the student ID


number and student name. Which function call will implement this?

A. display (student);

B. display (fulltimestudent);

C. display (student fulltimestudent);

Copyright © Open University Malaysia (OUM)


40  TOPIC 2 STRUCTURES

2.7 typedef CONSTRUCTION


Did you know that other than using the struct data type in applying data
structures, the programmer also has the option to use the typedef construction
statement? The syntax is as follows:
typedef <data_type> <variable_name>;

Let us look at Example 2.11.

Example 2.11:

typedef int input; ------- (i)


input positive_input, negative_input; ------- (ii)

In statement (i) that contains the typedef statement, we have defined an integer
variable with the name input. We can then define other input type variables, as
shown in statement (ii). The positive_input and negative_input variables
in (ii) are actually integer types. In (ii), we have replaced the data type int with
input.

The typedef data type can also be used in the structure declaration. Consider the
following example (see Example 2.12).

Example 2.12:

typedef struct biodata {


char name[20];
int age;
char address[50];
} Bio;

Based on the declaration, we can declare the typedef Bio construction as


follows:
Bio information1, information2;

Take note that the variable declaration is shorter. We can avoid using the word
struct in this declaration. This is because Bio is not a normal structure as learned
in the previous subtopics. It is a data type declaration of structure type.

Copyright © Open University Malaysia (OUM)


TOPIC 2 STRUCTURES  41

 A structure is a combination of bits of data from different sources and types.

 Using structure is an easy way to group information from several related items
by using the same variable name. Unlike array, the structure elements do not
necessarily have to be of the same type.

 In general, the template for declaring structure is by using the struct


construction.

 We can also declare the variable by listing the variable names at the end of the
structure declaration.

 The elements of a structure are normally processed individually. Therefore, we


must be able to access each of the structure elements using a „.‰ (dot) operator.

 To represent a group of data from the same type of structure, we use an array
representation of a structure type.

 We can also declare a structure element as another type of structure.

 In C programming language, a structure is passed to a function by value  the


structure value is copied for processing, in the body of the function. Any
changes made to the value by the function would not give any effect on the
value of the structure variable that is copied.

 We can use the typedef construction statement in applying data structures.


It can also be used in the structure declaration.

Arrays Referencing
Declaration struct

Dot operator (.) Structures

Initialisation typedef

Copyright © Open University Malaysia (OUM)


Topic  Pointers
3
LEARNING OUTCOMES
By the end of this topic, you should be able to:
1. Describe pointer;
2. Use pointer to pass parameters to functions through passing by
reference;
3. Declare an array by using a pointer;
4. Create memory space by using the malloc() and free()
commands; and
5. Show the relationship between pointer and structure.

 INTRODUCTION
Did you know that all the variable data types that have been declared before this,
have enabled direct access to the values that are kept in storage by the program?

This is because other than declaring variables that hold simple data (integer, float,
double, char), the C language also allows us to declare variables that keep the
storage address. As we already know, each storage cell that is used has a specific
and unique address. Variables that keep these addresses are referred to as pointers.

So are you ready to discover more on this interesting topic? Let us continue with
lesson.

Copyright © Open University Malaysia (OUM)


TOPIC 3 POINTERS  43

3.1 OVERVIEW OF A POINTER


What is a pointer?

A pointer is just like another variable, the main difference is that it stores
address of another variable rather than a value.

This value refers to the memory location for a variable or an array element.
Pointers in C are used to allocate memory dynamically at run time. The pointer
variable may belong to any of the data types such as int, char, float or double.

For example, let us say that a is a variable that represents an integer data type,
while p is an integer pointer, as illustrated in the following variable declaration:
int a;
int *p;

If you are creating a pointer to store the address of an integer variable, the pointer
data type should also be type integer. The compiler will assign memory space for
these data automatically. These data items can be accessed if we know the location
or address. The address for memory space a is given by the form &a, where & is
the operator address. Therefore, we can write:
p = &a;

which means that p is a pointer variable that points to a. The value in p is the
address for a and not the value of a. Let us look at Figure 3.1 which illustrates this.
Observe that the address is underlined.

Figure 3.1: Relationship between a and p (where p = &a)

Copyright © Open University Malaysia (OUM)


44  TOPIC 3 POINTERS

The value of the item represented by a can be accessed using *p, where * is the
reference operator. The declaration of pointer variables is as follows:
data_type *variable_name;

data_type are the data types found in C, such as int, char, float and
double, whereas variable_name is a valid name in C. The symbol * identifies
that the variable_name is of pointer type (not a normal variable).

Observe the following example (see Example 3.1).

Example 3.1:
Figure 3.2 shows an illustration for the p = &a statement in this code:
int a,b; // variables a and b of integer type
int *p; // Pointer p of integer type
a = 7; // Assigning 7 to a
b = 7; // Assigning 7 to b
p = &a; // p points to a

Figure 3.2: An illustration for p = &a

Observe that the addresses are underlined, and may be different depending upon
the compiler and platform.

Did you know that a pointer can be initialised using an address or even with a
NULL value (or 0)? Take note that a pointer with the NULL value does not point to
any memory location. A pointer variable can also be used to assign an address of
a variable as an initialisation of the pointer variable.
int data;
int *a = NULL; // Pointer to NULL value
int *b = &data; // b points to data

Copyright © Open University Malaysia (OUM)


TOPIC 3 POINTERS  45

A variable that is a pointer to a pointer must be declared as such. This is done by


placing an additional asterisk * in front of its name. The memory location that is
referred to by the pointer of a pointer, contains the address of the pointer. Look at
the following code (see Example 3.2).

Example 3.2:

int a = 100;
int *p; // Pointer to the int variable
int **pp; // Pointer to the pointer
p = &a; // p points to a
pp = &p; // pp points to p that points to a

Figure 3.3 shows you the memory locations for a, p and pp.

Figure 3.3: Memory locations of a, p and pp

In Figure 3.3, we assume that the address value for a is 62FE4C, while p has the
address 62FE48 and the address for pp is 62FE40. To get the pointer variable
value which is the address of a variable, use the %p format specification.

SELF-CHECK 3.1

1. What do you think will be displayed when you try to print out the
value of a null pointer? Will it contain a 0 or some other value?
What about the address of a random variable?

2. If you have created two variables and two pointer variables to point
at them, what is the difference in value of these two addresses?
Justify your answer.

Copyright © Open University Malaysia (OUM)


46  TOPIC 3 POINTERS

ACTIVITY 3.1

What is the output for the following program segments?

(a) int n = 10; (b) float m = 3.5;


int *p = &n; float *p = &m;
printf (“%d\t”, n); *p = *p * 5;
printf (“%d\n”, *p); printf (“%f\n”, m);

A. 10 A. 3.5
B. 10 10 B. 7.5
C. 10 C. 17.5
10

3.2 PARAMETER PASSING USING POINTER


In a C program, we use function when writing modular programs. Here,
parameter passing means that variable data is passed to functions from the main
function or other functions. How does parameter passing relate to pointers?

Well, pointers can also be passed to functions too. This way, we pass the address
to a local variable that points to the actual location of the data item by the calling
function. Take note that the value that is changed in the function will change the
value at the actual location too. This method of passing is known as passing by
reference or reference passing.

Copyright © Open University Malaysia (OUM)


TOPIC 3 POINTERS  47

Let us observe Code 1 and Code 2.

Code 1 Code 2
void A(int num) void A(int *ptr)
{ {
num = 5; *ptr = 5;
} }
void B() void B()
{ {
int data = 3; int data = 3;
A(data); Data B(&data); Data
= 3 = 5
} }

These codes explain the concept of passing by reference, in which the first Code 1
is a simple program that uses a normal variable and Code 2 uses a pointer. Two
functions A and B have values passed between them. Observe that in Code 1, the
variable data is passed from function B to function A does not change the value
of the original data which is 3. In Code 2, since the variable data has been passed
using its address (&data) to the pointer in function A, the value of data is now 5
and not 3.

Copyright © Open University Malaysia (OUM)


48  TOPIC 3 POINTERS

ACTIVITY 3.2

Look at the outline of the following functions:


float function1(int a, int b);
float function2(int *p, int *q);

void main() {
int a = 10; int b = 5;
float x,y;

x = function1(a, b);
printf (“a = %d, b = %d\n”, a, b);

y = function2(&a, &b);
printf (“a = %d, b = %d\n”, a, b);
}
float function1(int i, int j) {
i = 70; j = 7;
return ((float) i / j);
}
float function2(int *i, int *j) {
*i = 50; *j = 4;
return ((float) *i / *j);
}

(a) What is the value assigned to a and b after the program has
completed its execution?

(b) What is the output for this program?

Post your answers on the myINSPIRE online forum.

Copyright © Open University Malaysia (OUM)


TOPIC 3 POINTERS  49

3.3 POINTER AND ARRAY


Did you know that another way to declare an array is by using a pointer? Instead
of creating an array with subscript [], we can declare a pointer. In fact, an array
name is actually a pointer to the first element of an array.

Therefore, if x is a one-dimensional array having five elements, the address for the
first array element can be written as &x[0] or x. Let us look at Figure 3.4 which
shows the illustration of array x.

Figure 3.4: An illustration of array as pointer

Then, the address for the second array element can be written as &x[1] or (x +
1) and so on. In general, the address for the (n + 1) element can be written as
&x[n] or (x + n). Figure 3.5 shows you the memory location for the array x that
is declared as int x[5].

Figure 3.5: An illustration of the memory location for array x

In Figure 3.5, x and &x[0] points to the first elementÊs address which is 62FE30.
Similarly, &x[1] is equivalent to (x + 1), &x[2] is equivalent to (x + 2),
&x[3] is equivalent to (x + 3) and &x[4] is equivalent to (x + 4). This is
called pointer arithmetic, where pointers can be added to and subtracted from.
When you add a value to the pointer, it means that the pointer will move forward
based on the value added.

Copyright © Open University Malaysia (OUM)


50  TOPIC 3 POINTERS

In Figure 3.5, the expression (x + 4) will move the array pointer x forward four
times. Have you noticed that the addresses of the array indexes all increase by
four? Why did that happened? This is because, the integer value is stored in four
bytes of memory. It is easier to display the memory values in hexadecimal values,
as shown in Figure 3.5.

You can also create a pointer variable to point to an array. When assigning array
to a pointer, you can write the assignment statement in two ways:

int x[5] = {1,2,3,4,5};


int *p;

p = x;

Or
p = &x[0];

Can you recall of the passing of an array to a function by reference? This has been
explained in Topic 1. Passing of an array to a function by reference can be done
because the array name is the address or pointer and the passing of the pointer to
the function is performed by the reference.

Note: An array name is a constant pointer. This means that it cannot be assigned
with a new value or in other words, it cannot point to another location other
than the first element of the array.

3.3.1 Pointer and String


What does string mean?

A string is a one-dimensional array of characters terminated by the null


character „\0‰.

Copyright © Open University Malaysia (OUM)


TOPIC 3 POINTERS  51

Since strings are a type of an array, we can also declare and refer to strings as a
pointer.

In the following declaration, rent is a pointer of char type that points to the
December string.
char *rent = “December”;

Figure 3.6 shows you the memory location for this declaration.

Figure 3.6: Memory location illustration for rent

With this declaration, we can perform the following assignment:


rent = “May”;

With this assignment, it means that rent will point to the new location that has
the May string (refer to Figure 3.7).

Figure 3.7: Memory illustration after the rent assignment statement

Take note that this method of assignment cannot be implemented when we declare
the string as a character type array. So how do we solve this? You can use strcpy
if you want to assign values to a character type array variable.

Copyright © Open University Malaysia (OUM)


52  TOPIC 3 POINTERS

3.3.2 Array of Pointer


We can also declare an array where each of its elements is a pointer. This means
that each array element can be pointing to another variable or to another array. For
the second situation, we can get a two-dimensional array.

We declare a pointer type array as follows:


int *tts[4];

Assigning arrays to the pointer arrays makes use of pointer arithmetic. For
example, an array arr1 is declared with four integer values. These values can be
assigned to the *tts pointer as:
int arr1[4] = {1,2,3,4};

for (int x = 0; x < 4; x++)


{
*(tts+i) = &arr1[i];
}

Figure 3.8 illustrates the memory location resulting from the previous declaration.

Figure 3.8: Memory location illustration for tts

Copyright © Open University Malaysia (OUM)


TOPIC 3 POINTERS  53

ACTIVITY 3.3

1. Given the following declarations:


char *ptr;
char myString[] = “abcdefg”;
ptr = myString;
ptr += 5;

The pointer ptr points to which string?

A. fg

B. efg

C. defg

2. Given
int n[5] = {10, 20, 30, 40, 50};
int *p;
p = n; // p = &n[0];

What is the value of *p + 3 and *(p + 3)?

A. 10, 40

B. 13, 40

C. 13, 43

Copyright © Open University Malaysia (OUM)


54  TOPIC 3 POINTERS

3.4 DYNAMIC MEMORY


Did you know that the C language allows us to create memory space dynamically?

Dynamic memory management refers to manual memory management,


where you can obtain more memory when required and release it when it is
not necessary.

This means that we can declare the memory size that is needed by the program,
during the execution of the program. This way, when we write a program that
involves dynamic arrays, we do not need to give the size of the array during
declaration.

Let us understand the difference between static and dynamic memory allocation
(see Table 3.1).

Table 3.1: Differences between Static and Dynamic Memory Allocation

Static Memory Allocation Dynamic Memory Allocation


 Memory is allocated at compile time.  Memory is allocated at runtime.
 Memory cannot be increased during  Memory can be increased during
program execution. program execution.
 Used in arrays.  Used in linked lists.

We can also decide to input the size of the array during program execution and
the program will reserve sufficient space for the array elements. This is known as
reserving memory space dynamically.

How do we do this? To do this, we need the functions malloc() and free()


from the stdlib.h library. How does malloc() work? malloc() functions
allocate requested size of bytes and returns a pointer to the first byte of the
allocated memory. The malloc() function will provide dynamic memory space
when the program is executed. The malloc() function syntax is as follows:
ptr = (int *) malloc(no * sizeof(int));

(int *) is the cast into the pointer data type and sizeof will determine the
memory size that is provided in byte units depending on the data type. no is a
value that is multiplied with the size of the memory required. If sizeof(int)is
given, then four bytes of memory is created multiplied by no.

Copyright © Open University Malaysia (OUM)


TOPIC 3 POINTERS  55

In C, the memory size of a type of data is different from one computer system to
another. Because of this, the sizeof() function is very important even though it
is only to determine the size of simple data types. For example, ptr = (int *)
malloc (100 * sizeof(int)); will allocate 400 bytes of memory and the
ptr points to the first address of the first byte of memory.

If successful, this function will assign the address for the memory that has been
reserved to the ptr. If the space is insufficient, the memory allocation will fail and
this function will return the NULL value.

Now, let us move on to the free() function. Conversely, the free() function
will release the memory that has been reserved by malloc(). The free()
function that frees the space allocated in the memory pointed by ptr is written as:
free(ptr);

Let us look at the following code (see Example 3.3).

Example 3.3:

int *list; /* Pointer that will point to the dynamic


memory space */
...
printf(“Enter the number of data: “);
scanf(“%d”, &no);
...
list = (int *) malloc(no * sizeof(int));
if (list == NULL) {
printf(“Error in memory allocation\n);
exit(1);
}
...
...
free(list); /* Releases memory */

This coding declares list as a pointer and then reserves memory space
dynamically. The memory space that is reserved by malloc() is shown by the
list. Now, we can operate the list just as how we would operate an array of size
no.

Copyright © Open University Malaysia (OUM)


56  TOPIC 3 POINTERS

3.5 POINTER AND STRUCTURE


Lastly, let us look at pointer that point to a structure. Look at the following
declaration:
struct date {
int day;
int month;
int year;
};

We can declare the variable holiday as a date struct. We can also declare ptr
as a pointer of struct date * type (that can point to the location of struct
date type). Look at the following declaration.
struct date holiday;
struct date *ptr;

Based on the previous declaration, the following statement would make ptr to
point to holiday. Here, the address for holiday is assigned to ptr. Look at the
illustration of memory space in Figure 3.9.
ptr = &holiday;

Figure 3.9: Memory location illustration for holiday and ptr

Copyright © Open University Malaysia (OUM)


TOPIC 3 POINTERS  57

Table 3.2 shows the different ways of referencing and the actual action for the
related referenced variable.

Table 3.2: Ways of Pointing to Structures and Actual Action

Reference Action
ptr Pointer to holiday
*ptr The actual holiday structure
(*ptr).day Same as holiday.day
(*ptr).month Same as holiday.month
(*ptr).year Same as holiday.year

Take note that we can use the operator „->‰ to access structure elements through
ptr. Look at the following statements.
(ptr->day) /* Same as (*ptr).day */
(ptr->month) /* Same as (*ptr).month */
(ptr->year) /* Same as (*ptr).year */

As discussed in Subtopic 3.2, we can also pass a structure to a function by


reference. Structure arrays can also be declared dynamically.

ACTIVITY 3.4

1. When accessing a structure element using a pointer, which operator


is used?

A. Arrow operator (->)

B. Dot operator (.)

C. Pointer operator (&)

2. X->Y is syntactically correct if?

A. X and Y are both structures.

B. X is a structure and Y is a pointer to the structure.

C. X is a pointer to the structure and Y is a structure.

Copyright © Open University Malaysia (OUM)


58  TOPIC 3 POINTERS

 A pointer stores address of another variable rather than a value. This value
refers to the memory location for a variable or an array element.

 Passing variable data to functions from the main function or other functions is
called parameter passing.

 Pointer can also be passed to functions  the address is pass to a local variable
that points to the actual location of the data item by the calling function. The
value that is changed in the function will change the value at the actual
location. This method is called passing by reference or reference passing.

 Another way to declare an array is by using a pointer. An array name is


actually a pointer to the first element of an array.

 The malloc() function will provide dynamic memory space when the
program is executed.

 The free() function will release the memory that has been reserved by
malloc().

 Pointer can point to a structure. A structure can also be passed to a function by


reference and its arrays can be declared dynamically.

Array of pointers Pointers


Dynamic memory Reference passing
free() function Structures
malloc() function

Copyright © Open University Malaysia (OUM)


Topic  Lists and
Linked Lists
4
LEARNING OUTCOMES
By the end of this topic, you should be able to:
1. Apply the basic list operations;
2. Perform the basic linked list operations; and
3. Differentiate between list and linked list.

 INTRODUCTION
Static representation of linear order such as array may lead to wastage of memory
and in some cases, overflows. Now, let say we do not want to assign memory to
any linear list in advance. Instead, we want to allocate memory to elements as they
are inserted in list. This requires dynamic allocation of memory and it can be
achieved by using malloc() or calloc() function as we have seen in Topic 3
recently.

However, memory assigned to elements will not be contiguous, which is a


requirement for linear ordered list and was provided by array representation. So
how do we achieve this? Well, we have to consider a logical ordered list, that is,
elements are stored in different memory locations but they are linked to each other
and form a logical list.

Copyright © Open University Malaysia (OUM)


60  TOPIC 4 LISTS AND LINKED LISTS

Take note that list and linked list are two different terms. Hopefully, you will not
be confused with these two terms. Let us learn more on these two terms in the next
subtopics. Happy reading!

4.1 LIST
Firstly, what does a list mean?

A list is a general term that is defined by one type of sequential data items.

Can you give some examples of list? Well, list of courses that is being offered to
learners by OUM and breakfast menu in McDonaldÊs are examples of list.

How do we implement list in programming? Lists in programming can be


implemented by using array. This is because it is easier for each data item not being
linked to each other but is arranged sequentially and forms a list. This is shown in
the myList array that is illustrated in Figure 4.1.

Figure 4.1: myList array

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  61

4.1.1 Basic List Operations


There are several basic operations that can be performed by using linked list (see
Figure 4.2).

Figure 4.2: Five basic list operations

These basic operations are further explained as follows:

(a) Create Empty List


Before a list can be used for the other operations, it must be created first. A
new list is created (by default) having empty values or it is said to be an
(empty) list. One example an empty list is as follows:
int myList[10];

Copyright © Open University Malaysia (OUM)


62  TOPIC 4 LISTS AND LINKED LISTS

(b) Test Whether a List is Empty or Not


Generally, a list is created to contain data. However, you may initialise it with
0s or „NULL‰ values. How do we test to see if a list is empty or not? If the
list is empty, you will not be able to perform deletion from the list. One
example of coding is as follows (see Example 4.1).

Example 4.1:

int myList[10] = {0}; // all of the array elements will be 0

if (myList[0] == 0)
printf(“List is empty”);

In Example 4.1, the first element of the myList array is 0, so, we consider it
to be empty as there has not been any data assigned to the array yet. Keep in
mind that the array itself is not empty and cannot be empty, as it contains
the value 0s.

You do not need to test if the list is full or not. This is because the insertion
of data into the list is done by assigning values at the arrayÊs index.

(c) Traverse List


Firstly, what does traversal operation mean?

The traversal operation is a process of traversing or visiting from one


array element to another array element until the end of the list.

Usually, this operation is performed for a variety of functions such as


printing each data item that is contained in the list or searching for a
particular array element value (see Example 4.2).

Example 4.2:

int myList[10] = {1,2,3,4,5,6,7,8,9,10};


//Array initialisation
for (int x = 0; x < 10; x++)
if (myList[x] == keyvalue)
printf(“Searched:%d”, keyvalue);

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  63

In Example 4.2, keyvalue is a number that is entered by the user and it is


used to determine if the keyvalue exists in the list. Each of the list element
is compared to the keyvalue using the == operator (equals operator).

(d) Insert New Item (Add an Item to the List)


The operation of adding a new data item into the list is called insertion. This
operation involves the shifting of data items in the list if the sorted sequence
is to be preserved.

Keep in mind that array insertion does not increase the size of the array. If
the data item is to be inserted early on in the list, then many shifting of data
needs to be done as compared to when an insertion is done in the middle of
the list. No shifting will occur if the data item is to be inserted at the end of
the list or if the list does not need to be in a sorted state and the new data
item can be added at the end. The prerequisite for an insertion operation is
that the list must not be full.

Let say we want to insert a value 8 into a list: 2, 5, 9, 14, 20 at the third position
(so that the list is sorted), data elements that are in the list need to be shifted
by one position (see Figure 4.3).

Figure 4.3: Shifting data elements by one position to insert 8 value

After inserting the value 8, the new list is shown as in Figure 4.4.

Figure 4.4: New list after inserting the value 8

(e) Delete an Item from the List


The deletion operation for a sorted list also involves the process of shifting
too. This is because, if the item that is to be deleted is located early or in the
middle of the list, the emptied location cannot be left empty. It must be filled
with the following data item. Remember, the prerequisite for a deletion
operation is that the list must not be empty.

Copyright © Open University Malaysia (OUM)


64  TOPIC 4 LISTS AND LINKED LISTS

The opposite of inserting an item into the list is done for the deletion of data
elements, where the data elements are shifted by one into the empty
locations. Let say the value 8 is to be deleted from a list: 2, 5, 8, 9, 14, 20 (see
Figure 4.5).

Figure 4.5: Deleting the value of 8 in a list

After deletion operation, the values 9, 14 and 20 are shifted by one (see
Figure 4.6).

Figure 4.6: After deletion operation, the values 9, 14 and 20 are shifted by one

4.1.2 Implementation of List Using Array


As stated previously, a list is made up of data items that are sequential. From this
definition, it will encourage us to use array as the data structure for implementing
a list.

However, we shall not discuss it in detail here. It would be sufficient that you
know a little bit about this concept.

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  65

SELF-CHECK 4.1

1. Data elements that are retrieved by an index in which data


structure?

A. Linear array

B. Linked list

C. Binary tree

2. Which of the following will create a new list that is empty?

A. int List[10] = 0;

B. CreateList (&List);

C. CreateList(List[10]);

4.2 LINKED LIST


Firstly, what does linked list mean?

Linked list is a specific term that is used in programs and is defined as a group
of data items that is sequential, with its data items having links between each
other.

In the previous subtopics, you learned how arrays could improve the readability
and efficiency of your programming codes.

However, arrays are not practical for updating or for inserting and deleting data
as it involves a lot of movement of data. Thus, this weaknesses can be overcome
by using linked list.

Copyright © Open University Malaysia (OUM)


66  TOPIC 4 LISTS AND LINKED LISTS

As stated before, linked list is a collection of data items which have links with each
other  insertions and deletions can be made anywhere in a linked list. Linked list
consist of sequential data items known as nodes. Each node is made up of two
parts (see Figure 4.7).

Figure 4.7: Two parts of node

The linked list structure can be illustrated as in Figure 4.8.

Figure 4.8: Linked list structure

Linked lists can be implemented in two ways, which are:

(a) Arrays; and

(b) Pointers.

Take note that the implementation of linked list using array will not be discussed
in this course. Only the implementation of linked list using pointer will be
discussed.

4.2.1 Basic Linked List Operations


In linked list, there are several basic operations that can be performed. Basically, it
is the same as what has been previously discussed in the basic operations of list in
Subtopic 4.1.1. However, there are several additions as follows:

(a) Create Empty Linked List


Before a linked list can be used for other operations, it must be created first.
Remember, a linked list is always pointed to by a pointer and when a new
linked list is created, this pointer will point to null. This indicates that a
linked list is created but it is empty.

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  67

(b) Test whether a Linked List is Empty or Not


A linked list needs to be confirmed empty or otherwise, before the process of
deletion can be performed. This is because, if the linked list is empty, deletion
cannot be performed.

(c) Traverse Linked List


The traversal operation in linked list is a process of traversing or visiting from
one node to another node until the end of the linked list is encountered.
Usually, this operation is performed for printing each data item that is
contained in the linked list.

(d) Insert New Item (Add New Item in Linked List)


There are three positions for the insertion operation which are:

(i) Insert at the beginning of the linked list;

(ii) Insert between two nodes in the linked list; and

(iii) Insert at the end of the linked list.

Did you know that inserting at the beginning of the linked list is easier than
inserting in between two nodes in the linked list? This is because there is an
extra step of traversing up to the node where the new node will be inserted
after (or up to the previous node where the new node will be inserted before).

How about insertion at the end of the list? The insertion of a new node at the
end of the list involves traversing until the last element is reached, and then
inserting the new node at the end.

However, you do not need to test whether the linked list is full or not, as you
can add as many new nodes as you want.

(e) Delete Item from Linked List


Deleting a node from a linked list involves updating the link to the node
immediately after the removed node. Take note that the „removed node‰
now has become disconnected from the linked list and cannot be referred to.

Same as the insertion of items into the linked list, deletion can also be done
at the beginning, between two nodes in the linked list or at the end of the
linked list.

(f) Create New Nodes


Did you know that before a new node can be assigned a value, it has to be
given sufficient memory space to store data? In order to reserve memory
space dynamically, we can use the malloc( ) function.

Copyright © Open University Malaysia (OUM)


68  TOPIC 4 LISTS AND LINKED LISTS

(g) Search Linked List Linearly


In this operation, a search is a process of finding a data item in a linked list.

4.2.2 Implementation of Linked List Using Pointer


As usual, before we can use the linked list in our program, we must declare it. We
define the linked list abstract data type as a group of data items that are sequential
with the basic operations that have been stated just now. Here, we will use pointers
to implement a linked list.

(a) Declaration of Data Structure


The linked list data structure can be defined as follows (see Example 4.3).

Example 4.3:

typedef char ELEMENT;


typedef struct node
{
ELEMENT data;
struct node *next;
} NODE;

This linked list contains data items of type character. We define the variable
in Example 4.3 as structure type using the following statements:

NODE *list;
struct node *pnode;

(b) Creation of Empty Linked List


The CreateList function can be written as (see Example 4.4).

Example 4.4:

/* Receive: Reference to sList list


Process: Create new list
Return: New list reference */
void CreateList (NODE **sList)
{
*sList = NULL;
}

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  69

An example of a procedure call to this function is as follows:


CreateList(&list);

The linked list list is sent by reference (observe the & symbol that is used).
This means, in the CreateList function, sList will receive the address of
the list pointer. At the end of this function, list will have the value
NULL, which is a new list that is empty (refer to Figure 4.9).

Figure 4.9: New empty list

Now, we have created a linked list but it is empty.

(c) Creation of New Node


For the operation of creating a new node, we declare the NewNode function
as follows (see Example 4.5).

Example 4.5:

/* Receive: Value that is the data for the node


Process: Reserve memory space for the node
Return: A pointer that points to the node */
NODE * NewNode(ELEMENT dataelement)
{
NODE *Nnode;
Nnode = (NODE *) malloc (sizeof(NODE));
if (Nnode != NULL)
{
Nnode->data = dataelement;
Nnode->next = NULL;
}
return Nnode;
}

Copyright © Open University Malaysia (OUM)


70  TOPIC 4 LISTS AND LINKED LISTS

Figure 4.10 illustrates the node that will be returned after the execution of
this function. Let us just say that dataelement has a value of „A”.

Figure 4.10: New nodes

(d) Determine Empty Linked List


The BOOL data type has the values of FALSE or TRUE that is represented
by 0 and 1 respectively. The following is the definition of BOOL (see
Example 4.6).

Example 4.6:

typedef enum boolean {FALSE, TRUE} BOOL;


/* BOOL is of type enum with FALSE = 0, TRUE = 1 */

The following is the declaration of EmptyList function (see Example 4.7).

Example 4.7:

/* Receive: Reference to sList list


Process: Checks if the value of sList pointer is
NULL
Return: TRUE value if empty, FALSE if not */
BOOL EmptyList (NODE *sList)
{
return ((BOOL) (sList == NULL));
}

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  71

(e) Traversal of Linked List


The process for the TraverseList operation depends on the type of
application, such as printing all the data items, counting the number of data
items and other applications (see Example 4.8).

Example 4.8:

/* Receive: Reference to sList list


Process: Traverse and print each element in list
Return: None */
void TraverseList (NODE *sList)
{
NODE *pnode;
for (pnode = sList; pnode != NULL; pnode = pnode->next)
printf(“pnode.data: %c->\n”, pnode->data);
printf(“NULL”);
}

Let us look at Figure 4.11 which shows you the TraverseList operation
will print each element in the list.

Figure 4.11: List traversal

Copyright © Open University Malaysia (OUM)


72  TOPIC 4 LISTS AND LINKED LISTS

(f) Searching Linked List Linearly


The following is a function for searching a list that is not sorted (see
Example 4.9).

Example 4.9:

/* Receive: Reference to sList list and dataelement value


Process: Search the list until a node is found that
contains the item that is required
Return: TRUE value if found, FALSE if not */
BOOL SearchList (NODE *sList,ELEMENT dataelement)
{
NODE *qNODE;
qNODE = sList;
while (qNODE != NULL)
{
if (qNODE->data == dataelement)
return (BOOL) (TRUE);
else
{
qNODE = qNODE->next;
}
}
return (BOOL) (FALSE);
}

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  73

(g) Insertion of Node in Linked List


There are three types of insertion that can be done in linked list:

(i) Insert Node at the Beginning of the List


Assuming that the newNode node is to be inserted at the beginning of
the sList list. Figure 4.12 shows you newNode that will be inserted
into the sList.

Figure 4.12: Insertion of the newNode into the sList

The following are steps to insert a node at the beginning of the list:

Step 1: Set newNode->next = sList (see Figure 4.13).

Step 2: Set sList = newNode (see Figure 4.13).

Figure 4.13: Step 1 and Step 2 in inserting a node at the beginning of the list

The output list is shown in Figure 4.14.

Figure 4.14: New list after „D‰ is inserted at the beginning of the list

Copyright © Open University Malaysia (OUM)


74  TOPIC 4 LISTS AND LINKED LISTS

The code to insert a new node at the beginning of the linked list is given
in Example 4.10.

Example 4.10:

/ * Receive: Reference to sList list and newNode


Process: Inserts the newNode at the beginning
of the sList
Return: NONE */

void InsertAtBeginning (Node *sList, NODE *newNode)


{
newNode->next = sList;
sList = newNode;
}

(ii) Insert Node in the Middle of the Linked List


How do we insert a node in between two nodes? Let us suppose pointer
newNode points to a node that is to be inserted. For the insertion
operation in the middle of a linked list, we need an extra pointer temp
that points to the location where node newNode is to be inserted.

At the end of this operation, newNode will be inserted after the node
that is identified (pointed) by temp. Figure 4.15 illustrates this situation
before the insertion.

Figure 4.15: Before insertion of newNode node in the middle of the linked list

The algorithm for this operation is as follows:

Step 1: Set newNode->next = temp->next

Step 2: Set temp->next = newNode

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  75

Let us look at Figure 4.16 which shows you the effects of both steps.
The earlier temp.next link which was pointing to node „D‰ has been
replaced with the link to newNode.

Figure 4.16: Effects after insertion of node

(iii) Insert Node at the End of the Linked List


Let us suppose that the newNode node is to be inserted at the end of
the sList list (see Figure 4.17).

Figure 4.17: Inserting newNode node at the end of the sList list

Here are the steps to perform this operation:

Step 1: Set newNode->next = temp->next.


/* Point to NULL value */

Step 2: Set temp->next = newNode


/* Point to newNode */

The effect of these steps is shown in Figure 4.18.

Figure 4.18: Output of Step 1 and Step 2

Copyright © Open University Malaysia (OUM)


76  TOPIC 4 LISTS AND LINKED LISTS

The function for inserting a node in a linked list at the end is as follows
(see Example 4.11).

Example 4.11:

/* Receive: Reference to sList list and newNode


Process: Inserts the newNode at the end of the
sList
Return: NONE */

void InsertAtEnd (Node *sList, NODE *newNode)


{
newNode->next = temp->next;
temp->next = newNode;
}

However, it is not necessary to write three different insert list functions


as given just now. The function for inserting a node in a linked list for
all the previous cases is summarised as follows (see Example 4.12).

Example 4.12:

void InsertList (NODE **sList, NODE *newNode, NODE *temp)


{
if (temp == NULL)
{
newNode->next = *sList;
*sList = newNode;
}
else {
newNode->next = temp->next;
temp->next = newNode;
}
} //InsertList

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  77

The pointer temp points to the location where the node needs to be
inserted. If temp is null, the new node will be inserted at the start of the
list.

(h) Deletion of Node from Linked List


Last but not least, let us look at how to delete a node from a linked list. Keep
in mind that the node deletion operation also has three situations which are:

(i) Delete the first node;

(ii) Delete the middle node; and

(iii) Delete the last node.

Deleting the middle and last nodes has the same characteristics. The pointer
temp is used to show the position of the node that is to be deleted. If temp
is null, this means that the first node is to be deleted and if the value of temp
is not null, then this means that the middle or last node is to be deleted
depending on the position of pointer temp. The following is the operation
for deleting a node (see Example 4.13).

Example 4.13:

void DeleteItem (NODE **sList, NODE *pnode)


{
NODE *temp;
if (EmptyList(*sList))
{
printf(“Deletion Error: Empty List”);
return;
}
if (pnode == NULL)
{
temp = *sList;
*sList = temp->next;
}
else // if pnode is not null
{

Copyright © Open University Malaysia (OUM)


78  TOPIC 4 LISTS AND LINKED LISTS

temp = pnode->next;
pnode->next = temp->next;
}
free(temp);
}

Note: Observe the use of testing the empty list function.

ACTIVITY 4.1
Let us suppose that you are given a linked list as follows:

A pointer temp is created, that points to where pList is pointing to.


Which statement shows that temp is now pointing to the node „A‰?
A. temp = next;
B. temp = temp->next;
C. temp->next = A->next;

4.3 DIFFERENCES BETWEEN LIST AND


LINKED LIST
Before we end this topic, let us identify the differences between list and linked list.
The list, which is an array, is a linear data structure. List has homogenous values
which means that the type of data in the list is similar, either all the values are
integer data or characters, just like the name of a person.

As for an element, it is independent of each otherÊs positions. List elements can be


updated easily by identifying its index value and then overwriting the contents at
that index. List elements however, cannot be added or deleted once it is declared.

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  79

Linked list is linear and non-linear data structure. Linked list is linear for accessing
and non-linear for storing in memory. This means that the nodes of the linked list
are all joined, and is accessible one after another linearly through the link. Each node
in the linked list is connected with its previous node which is a pointer to the node.

However, the nodes are stored in memory based on available memory spaces as
and when the nodes are created. It is a complex process for updating the node in a
linked list. This is because the node has to be reached first linearly using a pointer
from the beginning of the linked list. If the node to be updated is at the end, the
process involves looking at all the nodes before the last node can be reached and
updated.

The nodes in the linked list can be added and deleted easily from the list, as
described in Subtopic 4.1.

To sum up, the differences between list and linked list can be simplified as shown
in Table 4.1.

Table 4.1: Differences between List and Linked List

Aspect List Linked List


Size  Fixed number.  Grow and contract due to
 Size needs to be specific during insertions and deletions.
declaration.
Storage  Static: Its cell is allocated during  Dynamic: Its node is
capacity compile time. allocated during runtime.
Order and  Stored consecutively.  Stored randomly.
sorting
Accessing  Direct or random access method.  Sequential access method.
the element  Specify the array index or  Traverse starting from the
subscript. first node in the list by
pointer.
Searching  Binary search and linear search.  Linear search.

Copyright © Open University Malaysia (OUM)


80  TOPIC 4 LISTS AND LINKED LISTS

SELF-CHECK 4.2
In your opinion, what is the difference between list and linked list? You
can go to https://goo.gl/yoEKkQ to know more about the differences
between list and linked list.

ACTIVITY 4.2

1. What is being performed by the program excerpt below?


for (pCurrent = pList; pCurrent != null; pCurrent =
pCurrent->next)
printf(“%d\n”, pCurrent->data);

2. You are given the following two linked lists and the code:

temp = pList1;
while (temp->next != NULL);
temp = temp->next;
temp->next = pList2;

What does the code indicate?

A. The temp pointer is used to traverse pList1 only.

B. The temp pointer is used to traverse pList1 and pList2.

C. The temp pointer is used to traverse pList1 and then points


at pList2.

Copyright © Open University Malaysia (OUM)


TOPIC 4 LISTS AND LINKED LISTS  81

 List and linked list are two data structures that are used to store information.
A one-dimensional array is similar to a list.

 Basic list operations are to create empty list, test whether a list is empty or not,
traverse list, insert a new item to the list and delete an item from the list.

 A linked list consists of a nodes and links. A node has data and a pointer that
points to another node. Using pointer to implement linked list is a little more
difficult than working with array.

 The basic linked list operations are create empty linked list, test whether a
linked list is empty or not, traverse linked list, insert new item, delete item,
create new nodes and search linked list linearly.

 List and linked list are different in many aspects, such as size, storage capacity,
order and sorting, accessing the element and searching.

Comparison Nodes
Deletion Pointers
Insertion Searching
Linked lists Traversal
Lists

Copyright © Open University Malaysia (OUM)


Topic  Stacks
5
LEARNING OUTCOMES
By the end of this topic, you should be able to:
1. State the meaning and characteristics of stacks data structure;
2. Describe the basic stack operations;
3. Write C programs using stack data structure; and
4. Demonstrate stack applications.

 INTRODUCTION
In the previous topic, we have been introduced to lists and linked lists. Among the
important things that were highlighted are the use of pointers and basic
operations.

Now, you will be introduced to another way of structuring data, that is, stack.
Stack can be pictured as a stack of arranged plates, where the last plate washed
will be put on top and it will be the first one to be used when we want to eat (refer
to Figure 5.1). The plate that was under the first plate used will then become the
plate at the top.

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  83

Figure 5.1: Illustration of the stack concept

Similarly, a stack is also an array. Refer to Figure 5.2, the data „A‰ is inserted first,
followed by „B‰ and then „C‰. Likewise, the data „C‰ will be removed first,
followed by „B‰ and then „A‰. At the moment, the data „C‰ is at the top.

Figure 5.2: A stack as an array

As you can see in Figure 5.2, there is a pointer named top that will point to the top
of the array (stack). This pointer will indicate where the next data will be inserted
or deleted. Removing data from a stack is called pop, and inserting data into a
stack is called push. Based on this discussion, can you define what a stack is?

A stack can be defined as a heap of arranged data items that can be accessed
from one end only.

In other words, a stack is a limited version of an array. New elements or nodes as


they are often called, can be added to a stack and removed from a stack only from
one end. For this reason, the main characteristic of a stack is called the last-in-first-
out (LIFO) structure.

Copyright © Open University Malaysia (OUM)


84  TOPIC 5 STACKS

5.1 STACK CHARACTERISTICS


What are the characteristics of a stack? The characteristics are as follows:

(a) Stack is an ordered list of similar data types.

(b) Stack is a LIFO (last in first out) structure, meaning that the last item inserted
will be the first item to be taken out.

(c) Push() function is used to insert new elements into the stack and pop()
function is used to remove an element from the stack. Both insertion and
removal are allowed at only one end of the stack called the top.

(d) Stack must be checked if it is full when insertion or push() function is to be


carried out.

(e) Stack must be checked if it is empty when deletion or pop() function is to


be carried out.

The simplest application of a stack is to reverse a word. You need to push a given
word into a stack, letter by letter, then pop the letters that are at the top from the
stack. For example, let us take the word „Hello‰ and push it into a stack. What is
the result? The word „olleH‰ which is the reverse word will pop from the stack.

Did you know that a common application of stack is an „undo‰ mechanism in text
editors? This operation is accomplished by keeping all text changes in a stack.
Have you notice it?

Other stack applications are:

(a) Expression evaluation using postfix notation;

(b) Backtracking while playing games or paths on a graph; and

(c) Memory management where the call to and from a function is executed.

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  85

5.2 BASIC STACK OPERATIONS


The basic stack operations are almost the same as the basic linked list operations,
but they are modified slightly according to its implementation. The basic
operations that can be performed on stacks are explained in Table 5.1.

Table 5.1: Five Basic Stack Operations

Operation Description
Create stack  For creating an empty stack.
 Performed before all the following operations can be carried
out.
Test empty stack  To test whether the stack is empty or not.
 Performed before the item removal operation is executed  if
the stack is empty, then there is no item that can be removed.
Test full stack  Performed if the implementation is done using arrays.
 If the implementation is done using pointers, this test is not
needed.
 To test whether a stack is full or not  it is performed before the
insertion operation is carried out because arrays have an item
limit.
 Items cannot be inserted in a stack if the stack is full.
Remove element  To remove an item from a stack.
from stack  The prerequisite is that the stack must not be empty.
Add element to  For inserting an item into a stack.
stack  The prerequisite is that the stack must not be full.

Copyright © Open University Malaysia (OUM)


86  TOPIC 5 STACKS

SELF-CHECK 5.1

1. What is the main characteristic of a stack data structure?

A. First-in-first-out (FIFO)

B. Last-in-first-out (LIFO)

C. Last-in-last-out (LILO)

2. What is the name of the pointer that shows the value that will be
popped next?

A. pop

B. top

C. up

5.3 IMPLEMENTATION USING ARRAY


Did you know that the stack data structure can be implemented in two ways?
These two ways are by using:

(a) Arrays; and

(b) Pointers.

Take note that the implementation using arrays is easier compared to the
implementation using pointers. Moreover, array representation of stack performs
pop and push functions easily. It is also efficient to use arrays for writing stacks as
all the stack nodes or data items are in contiguous memory and can be processed
quickly. Since modern processors has plenty of memory, the only problem with
array implementation of stack, which is the size of the array is not a problem
anymore.

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  87

Let us look at an example of how to add data into stack and remove data from a
stack (see Figure 5.3).

Figure 5.3: Illustration of adding and removing data from stack

5.3.1 Declaring Stack Data Structure


Stack data structure can be defined as follows (see Example 5.1).

Example 5.1:

#define MAXSTK 10

typedef struct node


{
int top;
int element [MAXSTK];
} STK;

In Example 5.1, the stack maximum is set to just 10 items. This limit is set at the
beginning, according to the needs of an application.

Copyright © Open University Malaysia (OUM)


88  TOPIC 5 STACKS

5.3.2 Creating Stack


The basic stack creation operation can be written as follows (see Example 5.2).

Example 5.2:

/* Create empty stack */


void CreateStk (STK *t)
{
t->top = -1;
}

If the stack is empty, t->top is -1. For a full stack, t->top would be the
maximum for the stack, which is 10 (for this example). The CreateStk operation
is the initial operation that is performed, so the stack must be empty.

5.3.3 Checking Empty Stack


The basic operation to test whether a stack is empty or not, can be written as
follows (see Example 5.3).

Example 5.3:

/* Check if the stack is empty */


BOOL EmptyStk (STK *t)
{
return ((BOOL) (t->top < 0));
}

This function will return TRUE if the stack is empty and FALSE if the stack contains
items. This is because a stack is empty when the value of top is -1.

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  89

5.3.4 Checking Full Stack


The basic operation to test whether a stack is full or not can be written as follows
(see Example 5.4).

Example 5.4:

/* Check if the stack is full */


BOOL FullStk (STK *t)
{
return ((BOOL) (t->top >= MAXSTK));
}

This function will return the value TRUE if the stack is full and the value FALSE if
the stack can still be filled with a new item. This is because a stack is full when the
value of top is MAXSTK which is 10 in this example.

5.3.5 Inserting Items into Stack


The basic operation for inserting items into a stack can be written as in
Example 5.5.

Example 5.5:

/* Insert an item into a stack t or display an error


message if stack t is full using the push function */
void push (ELEMENT item, STK *t)
{
if (FullStk(t))
printf("\nStack Full \n");
else
{
t->top++;
t->element[t->top] = item;
}
}

Copyright © Open University Malaysia (OUM)


90  TOPIC 5 STACKS

5.3.6 Removing Items from Stack


The basic operation for removing an item from the top of the stack can be written
as in the following Example 5.6.

Example 5.6:

/* Remove an item from a stack t or display an error


message if stack t is empty using the pop function */
void pop (ELEMENT *item, STK *t)
{
if (EmptyStk(t))
printf("\nStack Empty \n");
else
{
*item = t->element[t->top];
t->top--;
}
}

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  91

ACTIVITY 5.1

A stack data structure is defined as:

#define MAXSTK 10;


typedef int ELEMENTTYPE;
typedef struct stk
{
int top;
ELEMENTTYPE element [MAXSTK];
}STK;

Which of the following code shows an item insertion into stack?

A. t->element[t->top] = item; t->top++; top

B. [t->top] = item; t->top++;

C. t->top++; t->element[t->top] = item;

5.4 STACK APPLICATIONS


You have learnt a bit on stack applications in the first subtopic. Can you recall?
Now, let us read further to know more about other stack applications.

Copyright © Open University Malaysia (OUM)


92  TOPIC 5 STACKS

5.4.1 Separating Even and Odd Numbers


Let us look at Example 5.7. Try to understand it, line by line. Then, type and
execute the program using a computer. Observe the results.

Example 5.7:

#include <stdio.h>

/* Declaration of stack data structure */


#define MAXSTK 10
typedef int ELEMENT;
typedef enum { FALSE, TRUE } BOOL;
typedef struct node
{
int top;
int element [MAXSTK];
} STK;

/* Declaration of function prototypes */


void CreateStk (STK *t);
BOOL EmptyStk (STK *t);
BOOL FullStk (STK *t);
void push (ELEMENT item, STK *t);
void pop (ELEMENT *item, STK *t);

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  93

main ()
{
int counter, number, temp;
STK odd, even;
/* Create even and odd stacks */
CreateStk(&odd);
CreateStk(&even);
/* Read data and insert into the related stack */
for (counter = 1; counter <= 10; counter ++)
{
printf("\nInput number: ");
scanf("\n%d", &number);
if (number%2 == 0)
push(number, &even);
else
push(number, &odd);
}

/* Print contents of odd stack */


printf("\nPrinting Odd Numbers: ");
while (!EmptyStk (&odd))
{
pop (&temp, &odd);
printf("%d ", temp);
}

Copyright © Open University Malaysia (OUM)


94  TOPIC 5 STACKS

/* Print contents of even stack */


printf("\nPrinting Even Numbers: ");
while (!EmptyStk (&even))
{
pop (&temp, &even);
printf("%d ", temp);
}
}

//FUNCTIONS

/* Create empty stack */


void CreateStk (STK *t)
{
t->top = -1;
}
/* Check if the stack is empty */
BOOL EmptyStk (STK *t)
{
return ((BOOL) (t->top < 0));
}

/* Check if the stack is full */


BOOL FullStk (STK *t)
{
return ((BOOL) (t->top >= MAXSTK));
}

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  95

/* Insert an item into a stack t or display an error


message if stack t is full */
void push (ELEMENT item, STK *t)
{
if (FullStk(t))
printf("\nStack Full \n");
else
{
t->top++; // top is now 0
t->element[t->top] = item;
// item is inserted into index 0
}
}

/* Remove an item from a stack t or display an error


message if stack t is empty */
void pop (ELEMENT *item, STK *t)
{
if (EmptyStk(t))
printf("\nStack Empty \n");
else
{
*item = t->element[t->top];
t->top--;
}
}

Copyright © Open University Malaysia (OUM)


96  TOPIC 5 STACKS

The program in Example 5.7 reads 10 numbers one by one from the keyboard and
test whether the number is even or odd.

If the number is odd, then that number will be inserted into the odd stack and if
the number is even, then that number will be inserted into the even stack. Later,
the contents of both stacks will be printed onto the screen. So what is the output of
this program? The output of Example 5.7 is shown in Figure 5.4.

Figure 5.4: The output for Example 5.7

In this example, a loop is used to input data from the user. The loop is repeated
10 times from 1 to 10. It is important to understand that the values pushed into the
stack is for array index 0 to 9 (depending on the input by the user).

Even though the FullStk codes to check if the stack is full is given in the push
function and the Emptystk codes to check if the stack is empty is given in the pop
function, these codes will not be executed.

However, it is good programming practice to include these codes to understand


the stack data structure.

You may practise writing the codes for stack data structure using pointers to see
the effects of EmptyStk and FullStk for pop and push functions respectively.

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  97

5.4.2 Reverse Polish Notation (Postfix Notation)


One of the biggest technical hurdles faced when conceiving the idea of higher level
programming languages is to generate machine language instructions, which
would properly evaluate any arithmetic expression. The compiler will find it
difficult to evaluate an arithmetic expression written in a normal form (known as
infix notation like M + N * P). In order to evaluate this infix notation, the compiler
will convert it into a postfix notation (also known as reverse Polish notation) before
evaluating its expression.

Notation Expression
Infix M+N
Postfix MN+

Let us look at on how to convert infix to postfix notation and how postfix notation
evaluation can be done.

(a) Infix to Postfix Conversion


In infix notation, parentheses will determine the precedence of the operation.
For example, 2 * (3 + 2) and 2 * 3 + 2 will give different answers. In postfix
notation, the parentheses are not required in determining the precedence of
operations. This is also known as reverse Polish notation. Let us look at the
algorithm for reverse Polish notation first.

Algorithm:
Scan infix expression from left to right
If an operand is encountered add to postfix string (P)
If an operator is found
Repeatedly pop the operator from stack which are having higher
precedence than the operator found and add to P
Add the new operator to stack
If a right parenthesis is found
Repeatedly pop the stack and add the popped operators to P until a left
parenthesis is found
Remove the left parenthesis
Stop

Copyright © Open University Malaysia (OUM)


98  TOPIC 5 STACKS

Let us look at Example 5.8 which shows you how infix notation ((3 + 5 * 1)/8)
* 14 is being converted to postfix notation.

Example 5.8:
Convert infix notation ((3 + 5 * 1)/8) * 14 to postfix notation.

Answer:
The steps in converting infix notation ((3 + 5 * 1)/8) * 14 to postfix notation is
shown in Figure 5.5.

Figure 5.5: Steps in converting infix notation to postfix notation

Now, let us look at Example 5.9 which shows you the program to convert
infix notation to postfix notation.

Example 5.9:

#include <stdio.h>
#include <ctype.h>
#define SIZE 50 /* Size of stack */
char s[SIZE];
int top = -1; /* Global declarations */

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  99

void push(char elem) {/* Function for PUSH operation */


s[++top] = elem;
}

char pop() { /* Function for POP operation */


return (s[top--]);
}

int pr(char elem) { /* Function for precedence */


switch (elem) {
case '#':
return 0;
case '(':
return 1;
case '+':
case '-':
return 2;
case '*':
case '/':
return 3;
}
}

Copyright © Open University Malaysia (OUM)


100  TOPIC 5 STACKS

main() { /* Main Program */


char infx[50], pofx[50], ch, elem;
int i = 0, k = 0;
printf("\n\nRead the Infix Expression ? ");
scanf("%s", infx);
push('#');
while ((ch = infx[i++]) != '\0') {
if (ch == '(')
push(ch);
else if (isalnum(ch))
pofx[k++] = ch;
else if (ch == ')') {
while (s[top] != '(')
pofx[k++] = pop();
elem = pop(); /* Remove ( */
} else { /* Operator */
while (pr(s[top]) >= pr(ch))
pofx[k++] = pop();
push(ch);
}
}
while (s[top] != '#') /* Pop from stack till empty */
pofx[k++] = pop();
pofx[k] = '\0'; /* Make pofx as valid string */
printf("\n\nGiven Infix Expn: %s Postfix Expn: %s\n",
infx, pofx);
}

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  101

So what is the output for Example 5.9? Let us look at Figure 5.6 that
represents the output for Example 5.9.

Figure 5.6: The output for Example 5.9

(b) Evaluating Postfix Notation


In order to evaluate a postfix notation, operand values are read from left to
right and are inserted into a stack. When the operator is read, the two top
most operands that are situated in the stack are removed and the operation
is performed. A detailed implementation of this algorithm is as follows:
Algorithm:
Given a postfix expression V1 ⁄ Vn where Vi is either an operand or an
operator. The following algorithm evaluates the expression.

i=1

While i  n

If Vi is an operand: Push Vi to stack

If Vi is an operator: Apply Vi to the top two elements of the stack.


Replace these by the result in the stack.

i=i+1
Output result from stack

Copyright © Open University Malaysia (OUM)


102  TOPIC 5 STACKS

Let us look at Example 5.10 that demonstrates this.

Example 5.10:
Evaluation of postfix notation: 3 5 1 * + 8 / 14 *

Stack
empty
3
3 5
3 5 1
3 5
8
8 8
1
1 14
14

Answer: 14

SELF-CHECK 5.2

1. Change the following infix expression to a postfix expression.

(a) J*K/L+M

(b) J*(K+L*M)/N

2. Using the postfix expression evaluation algorithm, evaluate the


following postfix expressions.

(a) 21 3 / 10 – 7 3 / *

(b) 35*26–*

Copyright © Open University Malaysia (OUM)


TOPIC 5 STACKS  103

ACTIVITY 5.2

The basic operation for inserting data into a stack can be written as:
/* Insert an item into a stack t or display an
error message if t is full */
void InsertStk (ELEMENT item, STK *t)
{
if (FullStk(t))
printf("\nStack Full \n");
else
{
xxx;
t->element[t->top] = item;
}
}

What is the code written at xxx?

A. t->++top;

B. t->top++;

C. t->top--;

Copyright © Open University Malaysia (OUM)


104  TOPIC 5 STACKS

 A stack can be defined as a heap of arranged data items that can be accessed
from one end only. It is a limited version of an array.

 Among the characteristics of stacks are ordered list of similar data types, LIFO
(last in first out) structure, insert new elements into the stack using push()
function and using pop() function to remove an element from the stack.

 Basic stack operations are create stack, test empty stack, test full stack, remove
element from stack and add element to stack.

 The stack data structure can be implemented in two ways, namely using arrays
and using pointers.

 Stack can be applied when we want to separate even and odd numbers, and
reverse Polish notation.

Evaluation Postfix notation


Infix notation Push () function
Last in first out (LIFO) Stack
Pop () function Top

Copyright © Open University Malaysia (OUM)


Topic  Queues
6
LEARNING OUTCOMES
By the end of this topic, you should be able to:
1. State the meaning and characteristics of queues data structure;
2. Identify basic queue operations; and
3. Write C programs using queues.

 INTRODUCTION
Let us begin this topic with a saying that is hoped to motivate you in learning this
topic. It goes something like:

Never ask for things to be easier


Always ask yourself to be better

We have already gone through Topic 4 and Topic 5. Therefore, let us broaden our
knowledge in the data structures subject with this topic on queues.

Copyright © Open University Malaysia (OUM)


106  TOPIC 6 QUEUES

Similar to stacks, queues also have a wide application. In our daily lives, we can
see queues almost every day as customer waiting lines in banks (see Figure 6.1) or
cars at toll gates.

Figure 6.1: People in a queue

Customers or cars that arrive first will be attended to first, while those that come
after will be attended to when their turn comes. What is the meaning of queues?

In general, we can define queues formally as an ordered list, where elements can
be added at only one point (which is called the back or end) and an item can only
be removed from the other end (which is called the front or head).

From the definition given, we can say that the main characteristic of a queue is also
known as first-in-first-out (FIFO) which is different from the main characteristic of
stack data structure which is last-in-first-out (LIFO). Let us look at an example of
queue with five elements (see Figure 6.2).

Figure 6.2: A queue with five elements

As we can see in Figure 6.2, the element „A‰ is added to the queue first, followed
by „B‰, „C‰, „D‰, and „E‰. The front and back of the queue is also shown in the
figure.

Copyright © Open University Malaysia (OUM)


TOPIC 6 QUEUES  107

6.1 QUEUE BASIC OPERATIONS


Like all the basic data structure operations previously mentioned, queue
operations are just as similar. Let us look at Table 6.1 which explains more on this.

Table 6.1: Queue Basic Operations

Operation Description
Create queue Queues need to be created before it can be used for any
operations. Queues are created by giving initial values for the
variables at the front and back of the queue.
Test empty queue Before removing an item from the queue operation, we need to
conduct a test first to see whether a queue is empty or not.
Test full queue Before adding an item to the queue operation, conduct a test
first to see whether a queue is full or not.
Remove one element All items or elements are always removed from the front of the
from queue (delete queue. The prerequisite for this operation is that the queue
queue  dequeue) must not be empty.
Add one element to All items or elements are always added at the back of the queue.
queue (enter queue  The prerequisite for this operation is that the queue must not be
enqueue) full, which means that there must still be room to insert another
item.

SELF-CHECK 6.1

1. Define queue and its main characteristic.

2. Which operation is the prerequisite to execute the removal of an


item from the queue?

A. Test delete queue

B. Test empty queue

C. Test full queue

Copyright © Open University Malaysia (OUM)


108  TOPIC 6 QUEUES

6.2 IMPLEMENTATION OF QUEUE DATA


STRUCTURE
Queue data structure can be implemented in two ways which are by using:

(a) Pointers; and

(b) Arrays.

For the implementation of queues in this topic, we shall use arrays to keep queue
data items and two integer variables to represent the front and back queue
locations (we used the integer variable top to represent the top of the stack).

The value of the variable that represents the back of the queue will be increased
when an item is added to the queue (the item is added to the back of the queue).
Similarly, the value of the front variable will also be increased when an item leaves
the queue (the item leaves through the front of the queue).

Let us recall the basics of arrays. An array has a name and data type, and holds
multiple elements. The number of elements stored in an array is a fixed value
called the array size. The array index begins at 0 and ends at the size of the array
subtracted by 1. So, if we have an array with size 10, the index will be from 0 to 9.

Observe the following case.

Assume that the maximum for queue elements is 5. The CreateQueue


operation will create an empty queue with the front and back equal to 0,
which means that both are pointing to position index 0.

Let us look at Table 6.2 which summarises this operation.

Copyright © Open University Malaysia (OUM)


TOPIC 6 QUEUES  109

Table 6.2: Implementation of Queue Data Structure using Array

Operation Description
Step 1: Creating a new queue

Function: CreateQueue

The integer variables „Front‰ and „Back‰ are created


having the value 0. Both of the variables are pointing to
the first queue array index which is 0.
Step 2: Inserting three new
values into the array: A, B and
C

Function:
1. Enqueue (A)
2. Enqueue (B) When the first Enqueue A function was executed, the
3. Enqueue (C) value 0 is inserted into the index 0, which is the value
indicated by Back. After this insertion, Back is
increased by 1. For the second insertion, Enqueue B,
the value 0 is inserted into index 1, which is indicated
by Back and the value Back is increased to 2. So, for the
third insertion, the Enqueue C, the value 0 is inserted
into index 2 and the Back value is now increased to 3.
This shows where the next insertion (Enqueue)
function will take place. Before inserting new items into
the queue, the test full queue is always done.

Copyright © Open University Malaysia (OUM)


110  TOPIC 6 QUEUES

Step 3: Remove two items


from the front of the queue.

Function:
1. Dequeue()
2. Dequeue()
In the Dequeue() function, the Front variable is used.
It will be increase by 1, after each Dequeue() function.
In this example, the first Dequeue() function
increased the Front value from 0 to 1, and the second
Dequeue() function increase it again to 2. You can see
that the Front is now showing the value that is in the
queue at the index 2. This is now the front of the queue
and will be the next value deleted from the queue. It is
important that before deleting items from the queue, the
test empty queue is always done.
Step 4: Insert two more items
into the queue.

Function:
1. Enqueue (D)
2. Enqueue (E) Since inserting new values into the queue will be from
the back of the queue, D is inserted into the index that is
indicated by Back which is 3. Back is now increased to
4, and the value E is inserted here. The Back value is
again increased, the value of Back now is 5. Before
inserting new items into the queue, the test full queue is
always done.

After the two items D and E have been added, the value of the back variable is
increased by 2 and this is over the limit of the maximum array index that was
defined as 5 (Remember! Array index starts at 0). Also observe that the number of
items in the queue is 3 and there are still two more empty spaces in the queue.

Copyright © Open University Malaysia (OUM)


TOPIC 6 QUEUES  111

If we want to add more items and maintain the queue characteristics, one way is
by shifting the queue element, so that the first item is located at index 0, second
item at index 1 and third item at index 2. The values of the front and back variables
also need updating. This is difficult because every time a new insertion and
removal queue operation is performed, shifting also needs to be done.

We can solve this problem by assuming that the array element is arranged in a
circle. This arrangement is called a circular queue. Let us take the same case as in
Table 6.2. The circular queue is explained in Table 6.3.

Table 6.3: Circular Queue in Data Structures

Operation Description
Step 1: Insert three items
into the queue.

Function:
1. Enqueue (A)
2. Enqueue (B)
3. Enqueue (C)

„Front‰ and „Back‰ are both at index 0 in the beginning.


When the first Enqueue (A) function was executed, the
value A is inserted into the index 0, which is the value
indicated by Back. After this insertion, Back is increased
by 1. For the second insertion, Enqueue (B), the value B
is inserted into index 1, which is indicated by Back, and the
value Back is increased to 2. Similarly, for the third
insertion, the Enqueue (C), C is inserted into index 2, and
the Back value is now increased to 3. This shows where the
next insertion (Enqueue()) function will take place. Before
inserting new items into the queue, the test full queue is
always done.

Copyright © Open University Malaysia (OUM)


112  TOPIC 6 QUEUES

Step 2: Remove two items


from the front of the
queue.

Function:
1. Dequeue()
2. Dequeue()

In the Dequeue()function, the Front variable is used.


Front will be increased by 1, after each Dequeue()
function. In this example, the first Dequeue() function
increased the Front value from 0 to 1, and the second
Dequeue() function increased it again to 2. You can see
that the Front is now showing the value that is in the
queue at the index 2 which is C. This is now the front of the
queue and will be the next value deleted from the queue.
However, it is important that before deleting items from the
queue, the test empty queue is always done.
Step 3: Insert two more
items into the queue.

Function:
1. Enqueue (D)
2. Enqueue (E)

Here, observe that after two more items have been inserted,
the value of the Back variable is now 0. This enables more
items to be inserted in the queue in the empty spaces.
However, it is important that before inserting new items
into the queue, the test full queue is always done.

Copyright © Open University Malaysia (OUM)


TOPIC 6 QUEUES  113

6.2.1 Declaring Queue Data Structure


Similar to what has been discussed earlier, queue data structure consist of
an array for keeping queue items and two variables front and back, each
representing the locations for the front and back of the queue. When we use arrays
to create queue, the maximum number of array elements needs to be declared
beforehand. For the following data structure, we assume the maximum is 10.

However, this value can be changed according to the application. The queue data
structure can be defined as shown in Example 6.1.

Example 6.1:

#define QLimit 10
typedef int ELEMENTTYPE;
typedef struct queue
{
int front;
int back;
ELEMENTTYPE element[QLimit];
} QUEUE;

We can redefine the queue variable for use in the main program as:
QUEUE queue;

Copyright © Open University Malaysia (OUM)


114  TOPIC 6 QUEUES

6.2.2 Creating Queue


The function for the basic operation to create empty queue can be written as in
Example 6.2.

Example 6.2:

/* Receive: Reference to queue g


Process: Create a new queue
Return: Reference to new queue */
void CreateQ(QUEUE *g)
{
g->front = 0;
g->back = 0;
}

6.2.3 Checking Empty Queue


When does a queue become empty? A queue is said to be empty when the values
of front and back variables are equal.

The function to test whether the queue is empty or not can be written as in
Example 6.3.

Example 6.3:

/* Receive: Queue g
Process: Test whether queue g is empty or not
Return: The value TRUE (1) if the queue is empty,
the value FALSE(0) if otherwise */
BOOL EmptyQ (QUEUE *g)
{
return ((BOOL) (g->front == g->back));
}

Copyright © Open University Malaysia (OUM)


TOPIC 6 QUEUES  115

6.2.4 Checking Full Queue


Meanwhile, the test to see whether or not a queue is full can be written as in the
following Example 6.4.

Example 6.4:

/* Receive: Queue g
Process: Test whether queue g is full or not
Return: The value TRUE (1) if the queue is full, the
value FALSE (0)if otherwise. */
BOOL FullQ (QUEUE *g)
{
return ((BOOL) (((g->back + 1) % QLimit) == g->front));
}

6.2.5 Inserting Items into Queue


The enqueue operation to insert items into queue involves two steps, which are:

(a) Assigning the item that is inserted into the element with a back index value
(because the item is inserted from the back); and

(b) Then, the back value is increased. The value that is added needs to be a
modulo with QLimit so that the back value is always in the region of 0 and
QLimit - 1.

Copyright © Open University Malaysia (OUM)


116  TOPIC 6 QUEUES

The function for this operation can be written as in Example 6.5.

Example 6.5:

/* Receive: One data item and one queue g


Process: Insert data item to the back of the queue
Return: The updated queue */
void Enqueue(ELEMENTTYPE item, QUEUE *g)
{
if (FullQ(g))
printf(“ERROR: FULL QUEUE\n”);
else
{
g->element[g->back] = item;
g->back = (g->back + 1) % QLimit;
}
}

6.2.6 Removing Items from Queue


The Dequeue operation will return the item value on the front index. After the
value is assigned to the variable that returns it, thus the front value is increased.
This value is also a modulo with QLimit in the same way as the InsertQ
function. The function to remove items from a queue can be written as in
Example 6.6.

Example 6.6:

/* Receive: Queue g
Process: Remove data item from front of queue
Return: The data item is removed and the queue is
updated */
void Dequeue(ELEMENTTYPE *item, QUEUE *g)
{

Copyright © Open University Malaysia (OUM)


TOPIC 6 QUEUES  117

if (EmptyQ(g))
printf(“ERROR: EMPTY QUEUE \n”);
else
{
*item = g->element[g->front];
g->front = (g->front + 1) % QLimit;
}
}

SELF-CHECK 6.2

1. Inserting an item into a queue when the queue is not full is called
an X operation and deletion of an item from the queue when the
queue is not empty is called a Y operation. Find out what is X and
what is Y.

A. X is insert, Y is delete

B. X is push, Y is pop

C. X is enqueue, Y is dequeue

2. When inserting items into a queue, which variable will be increased


by 1?

A. Front

B. Back

C. Top

ACTIVITY 6.1
Go to https://goo.gl/J2k3d4, copy and run the programs given. Do
you get the same outputs? Using the same program, insert A, B, C, D
and E as the input. What is the result now?

Copyright © Open University Malaysia (OUM)


118  TOPIC 6 QUEUES

 Queue is an ordered list, where elements can be added at only one point (which
is called the back or end) and an item can only be removed from the other end
(which is called the front or head).

 The main characteristic of a queue is known as first-in-first-out (FIFO). This is


because the data is inserted at the back and is removed from the front only.

 The queue basic operations are create queue, test empty queue, test full queue,
delete queue and enter queue.

 Queue data structure can be implemented by using pointers and arrays.

 There are two variables that identify the position of the front and the back of
the queue. These variables are called front and back. A queue is empty when
both the values of front and back variables are equal.

 When adding items into the queue, the variable back is increased by 1. When
removing items from the queue, the variable front is increased by 1.

 It is important to test for empty queue when deleting items, and test for full
queue when inserting items.

 A queue implemented as an array may show that it is full, while it may be


empty (no more items can be inserted as the back variable is over the limit of
the array size). This can be prevented by using a circular queue.

Back Front
Circular queue Increase
Delete queue (dequeue) Queues
Enter queue (enqueue) Test empty queue
First-in-first-out (FIFO) Test full queue

Copyright © Open University Malaysia (OUM)


Topic  Sorting
7
LEARNING OUTCOMES
By the end of this topic, you should be able to:
1. Identify four types of sorting algorithms;
2. Differentiate the efficiency of several sorting algorithms; and
3. Apply sorting algorithms to related problems.

 INTRODUCTION
In the previous topics, we have been introduced to data structures (lists, stacks and
queues) and algorithms. Both of these concepts go hand in hand and have a close
relationship. It can perhaps be illustrated as follows (see Figure 7.1).

Figure 7.1: The relationship between data structures and algorithms

Copyright © Open University Malaysia (OUM)


120  TOPIC 7 SORTING

Therefore, to produce an effective program, the selection of data structures and


efficient algorithm is very important. Sometimes, the different selection of data
structures would also need different algorithms to solve a problem. For example,
with the efficiency of a loop algorithm for data structures, a linear list sort would
depend on the number of nodes.

There are also several algorithms that are different in efficiency for the same data
structure. In this case, consideration only lies in the selection of the most efficient
algorithm from the perspective of processing time. One of the most important
algorithms in programming is sorting. Therefore, this topic will discuss several
algorithms for sorting.

Did you notice that in our daily lives, we rarely use the word sorting? However,
we often perform the procedure. A clear example would be when a teacher would
write a studentÊs attendance list, where he would arrange the name of the students
beginning with the letter „A‰ and followed by the next letter, as illustrated in
Figure 7.2. The process of arranging according to a given rule is called sorting.

Figure 7.2: Example of sorting

Throughout this topic, we will focus on four types of sorting namely simple
selection sort, linear insertion sort, quick sort and bubble sort (see Figure 7.3).

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  121

Figure 7.3: Four types of sorting

We will give attention to each type of sorting from the aspects of:

(a) The way to use it;

(b) Its implementation in programming; and

(c) The differences between each sorting.

So are you ready to do „sorting‰? Let us continue with the lesson!

7.1 SIMPLE SELECTION SORT


Let us firstly fully focus on simple selection sort. Did you know that simple
selection sort is the easiest method of sorting?

Simple selection sort chooses the smallest or biggest in a list and place it on
the most appropriate position.

Copyright © Open University Malaysia (OUM)


122  TOPIC 7 SORTING

Consider the following element list in Figure 7.4, that is to be sorted in ascending
order. There are seven numbers that are labelled with the respective position.

Figure 7.4: An unsorted element list

So how do we sort this list using simple selection sort? Let us look at Table 7.1
which shows you the answer.

Table 7.1: Steps that are Needed to Sort in Ascending Order

Step Action
1 Compare Element 1 with Elements 2 to 7. Find the smallest element compared to
1. Element 3 is the smallest. Therefore, we change the position of Element 1 with
Element 3.
2 Compare Element 2 with Elements 3 to 7. Element 2 is the smallest, so no
changing of positions of elements is necessary.
3 Compare Element 3 with Elements 4 to 7. Element 5 has the smallest value, so an
exchange of positions between Element 3 and Element 5 occurs.
4 Compare Element 4 with Elements 5 to 7. Element 6 has the smallest value, so an
exchange of positions between Element 4 and Element 6 occurs.
5 Compare Element 5 with Elements 6 to 7. Element 5 is the smallest, so no
changing of positions of elements is necessary.
6 Compare Element 6 with Element 7. Element 7 has the smallest value, so an
exchange of positions between Element 6 and Element 7 occurs.
7 The result that is obtained is a sorted list of numbers.

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  123

Figure 7.5 shows the steps for sorting in ascending order.

Figure 7.5: Steps for sorting in ascending order

Copyright © Open University Malaysia (OUM)


124  TOPIC 7 SORTING

Remember, simple selection sort is a selection sort because the process of selection
and exchanging of positions occurs at the same time.

7.1.1 Simple Selection Sort Implementation Using


Array
The following Example 7.1 shows you a function for simple selection sort that is
implemented using array, where the list of numbers that is to be sorted is the
elements of an array.

Example 7.1:

void SelectSort(int arr[], int n) {


int i, j, minIndex, tmp;
for (i = 0; i < n - 1; i++) {
minIndex = i;
for (j = i + 1; j < n; j++)
if (arr[j] < arr[minIndex])
minIndex = j;
if (minIndex != i) {
tmp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = tmp;
}
}
}

The SelectSort function will receive an array arr and the size of the array n.
The function starts with assigning the minIndex to the first index value which
is 0.

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  125

There is a loop in the main loop, which is essentially to find the smallest value in
the elements from index 1 to the end of the list. The first if statement is to compare
the values of the elements, and the second if statement is to swap or exchange
them. As you can see in Figure 7.5, the list is sorted in Step 7.

7.1.2 Simple Selection Sort Algorithm Efficiency


For a simple selection sort, the execution time depends on the time to compare the
values to determine their positions. Selecting the smallest value requires scanning
the list of n elements (n  1 comparisons) and then swapping it into the first
position.

Finding the next lowest element (2nd smallest) requires scanning the remaining
n  1 elements (n  2 comparisons) and so on. Therefore, the total number of
comparisons are given in the form of:

n  n  1
(n – 1) + (n – 2) + . . . + 2 + 1 =
2

Which is of complexity O(n 2 ) in terms of number of comparisons.

Let us use the elements in Figure 7.4 to show you the calculations:

77  1
= 21
2

or

(n  1) + (n  2) + (n  3) + (n  4) + (n  5) + (n  6)
= 6 + 5 + 4 + 3 + 2 + 1
= 21

Copyright © Open University Malaysia (OUM)


126  TOPIC 7 SORTING

As a conclusion, you need to:

(a) Compare the first element with the rest; and

(b) Know when and how to change the position of the element.

SELF-CHECK 7.1

How does the simple selection sorting method work if the data is to be
sorted in ascending order?

A. The smallest data in the list is placed at the front of the list.

B. The smallest data in the list is placed at the back of the list.

C. The smallest data in the list is placed in the middle of the list.

7.2 LINEAR INSERTION SORT


Now, let us look at the next type of sorting. Perhaps with this new type of sorting,
you can make a comparison with the previous sorting technique.

In the linear insertion sort, the list is divided into two parts: sorted and
unsorted. In each pass, the first element of the unsorted sublist is transferred
to the sorted sublist by inserting it at the appropriate place.

If we have a list of n elements, it will take at most n  1 passes to sort the data.
This concept is shown in Figure 7.6.

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  127

Figure 7.6: Steps for linear insertion sort

Copyright © Open University Malaysia (OUM)


128  TOPIC 7 SORTING

In other words, the method of linear insertion sort is the method of inserting a new
element in a sorted list. The element is inserted at the position that is suitable and
the final list is the sorted list.

Let us use the data elements in Figure 7.6 with the assumption that the first element
is the element for a sorted sublist. In the first loop, the first two elements are
compared. It is found that the second element is smaller than the first element, so
we shift the first element to the right to insert the second element. Now (Step 2 in
Figure 7.6), the second element has become the first element of the sorted sub-list.

We then compare the third element with the elements in the sublist. Since Element
3 is the smallest compared to the elements of the sublist, we then shift number 33
and 67 in order to insert number 21. The process repeats where small numbers are
inserted in the correct positions and the elements to the right will be shifted to the
right.

7.2.1 Linear Insertion Sort Implementation Using


Arrays
The following Example 7.2 shows a function for linear insertion sort that is
implemented using array.

Example 7.2:

void InsertSort(int x[], int n)


{
int i, k, y;

for (k = 0; k < n; k++)


{
y = x [k];
for (i = k; i >= 0 && y < x[i + 1]; i--)
x[i + 1] = x[i];
x[i] = y;
}
}

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  129

7.2.2 Linear Insertion Sort Algorithm Efficiency


Did you know that the worst case scenario for the linear insertion sort when a list
is sorted, is in the inverted sequence that is required? Let us look at Figure 7.7 as
an example.

Figure 7.7: The inverted linear insertion sort

The insertion of x[2] requires two comparisons, that is, comparison with x[1]
and x[0], inserting x[3] requires three comparisons and so on. The number of
comparisons that are required is:

n  n  1
1 + 2 + 3 + ... + n =
2

So, the efficiency of the linear insertion sort algorithm is O(n2).

SELF-CHECK 7.2

Which sorting algorithm gives the best performance when applied on an


array which is almost sorted?

A. Insertion sort

B. Quick sort

C. Selection sort

Copyright © Open University Malaysia (OUM)


130  TOPIC 7 SORTING

7.3 QUICK SORT


What does quick sort mean?

The quick sort is an in-place, divide-and-conquer, massively recursive sort


and a very efficient and fastest sorting algorithm in practice.

Quick sort has two phases (see Figure 7.8).

Figure 7.8: Two phases of quick sort

The recursive algorithm consists of four steps:

(a) If there are one or less elements in the array to be sorted, return immediately;

(b) Pick an element in the array to serve as a „pivot‰ point (usually the left-most
element in the array is used);

(c) Split the array into two parts – One with elements larger than the pivot and
the other with elements smaller than the pivot; and

(d) Recursively repeat the algorithm for both halves of the original array.

This method is based on frequently changing elements similar to a bubble sort


method. In short, in this quick sort, a value is known as chosen pivot value. Several
exchanges of element positions occur until all the elements on the left of the pivot
are smaller than it and all the elements on the right of the pivot are larger than it.
The same process is repeated for the sublist on the left and the sublist on the right
of the pivot.

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  131

Let us use the same data used in the sorting method previously (Figure 7.4). This
is to show to you the difference in efficiencies of sorting methods. The steps in
quick sort are listed as follows:

Step 1

(a) We begin by selecting a number as a pivot. To simplify this process, we


choose the first element, which is 67 as the pivot. We start to search the list
from the right to find a smaller value than the pivot and we find 50. We
search the list from the left for a value that is larger than the pivot and we
find number 84. Figure 7.9 will clarify this first step.

Figure 7.9: Step 1(a) for quick sort

(b) Since the index number for 50 is larger than the index number for 84, so an
exchange in positions occurs for those numbers. Or, we look at both the
arrows above. If the arrow pointing to the right and the arrow pointing to the
left still have not met, then repeated exchanging of positions occur between
the two values. This can be seen in Figure 7.10 as follows.

Figure 7.10: Step 1(b) for quick sort

Copyright © Open University Malaysia (OUM)


132  TOPIC 7 SORTING

Step 2

(a) We repeat the search from the right of the list to find a value smaller than the
pivot and we find number 49. We search from the left of the list to find a value
that is larger than the pivot and we find number 84. At this time, we find that
the index value for 49 is smaller than the index value for number 84.

Therefore, we exchange number 49 with the pivot value. Or, when the arrow
pointing to the right and the arrow pointing to the left overlaps one another,
the smallest value will be exchanged with the pivot value. This step is
illustrated in Figure 7.11.

Figure 7.11: Step 2(a) for quick sort

(b) Now, the pivot value is between the left sublist and right sublist. Look at
Figure 7.12 for evidence.

Figure 7.12: Step 2(b) for quick sort

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  133

Step 3

(a) We repeat Step 1 for the left sublist, that is, we determine the pivot value. We
choose the first number again as the pivot, which is number 49. We search
from the right to find a smaller value than the pivot value and we find
number 21. We search from the left to find a larger value than the pivot value
and we find number 50. Figure 7.13 shows this execution.

Figure 7.13: Step 3(a) for quick sort

(b) Since the index value for number 49 is smaller than the index value for 21, so
we exchange number 21 with the pivot value. Look at Figure 7.14 for
evidence of this execution.

Figure 7.14: Step 3(b) for quick sort

(c) Repeat the search operation and exchanges for the left sublist for the pivot
value of 67, also for the left and right sublists for the pivot value of 49. Look
at the following Figure 7.15 which explains all the steps for quick sort fully.

Copyright © Open University Malaysia (OUM)


134  TOPIC 7 SORTING

Figure 7.15: Step 3(c) for quick sort

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  135

7.3.1 Quick Sort Implementation Using Array


We can write the quick sort method as a recursive function using array as follows
(see Example 7.3).

Example 7.3:

void quickSort(int number[], int low, int high)


{
if (low < high) {

int mid = partition(number, low, high);


quickSort(number, low, mid - 1);
quickSort(number, mid + 1, high);
}
}

Take note that the partition function is for arranging elements so that the values
smaller than the pivot will be on the list and values that are larger than the pivot
will be on the right (see Example 7.4).

Example 7.4:

int partition(int number[], int start, int end) {


/* Set the pivot */
int pivot = number[start];
do {
/* Look for a number smaller than pivot from
the end */
while (start < end && number[end] >= pivot) {
end--;
}
if (start < end) { // Found a smaller number
number[start] = number[end];

Copyright © Open University Malaysia (OUM)


136  TOPIC 7 SORTING

/* Now, find a number larger than pivot


from the start */
while (start < end && number[start] <= pivot) {
start++;
}
if (start < end) { // Found a larger number
number[end] = number[start];
}
}

} while (start < end);


/* Done, move the pivot back to the array */
number[start] = pivot;
return start;
}

7.3.2 Quick Sort Algorithm Efficiency


The worst case scenario for this algorithm would be when the list to be sorted is
already sorted or inverted and sorted. The processing time for this case is O(n2),
while the processing time for normal cases is O(n log2 n).

So how do we increase the efficiency of this method? A modification that can be


made to increase the efficiency of this method is by changing to another method
of sorting that is faster for smaller sublists. Keep in mind that for sublists with less
than 20 elements, this quick sort method is not so efficient.

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  137

7.4 BUBBLE SORT


Now, let us move on to the last type of sort which is bubble sort. What does it stand
for?

Bubble sort is a sorting algorithm that will compare adjacent pair of data in a
list, swapping them if they are out of order, continuing down the list until all
the adjacent pairs are in order.

The whole process is repeated again in the next loop. For a list of 10 items, bubble
sort will go through the list nine times (n  1) for it to be sorted.

7.4.1 Bubble Sort Implementation Using Array


This type of sorting performs adjacent element exchanges until all elements
are arranged according to the requirements. The following is the function
implementation of the bubble sort (see Example 7.5).

Example 7.5:

void bubbleSort(int arr[], int n) {


int i,j;
int tmp;

for (i = 0; i < n – 1; i++) {


for (j = 0; j < n – i – 1; j++) {
if (arr[i] > arr[i + 1]) {
tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}
}
}

Copyright © Open University Malaysia (OUM)


138  TOPIC 7 SORTING

In order to understand the algorithm in Example 7.5, let us consider the following
number list (see Figure 7.16).

Figure 7.16: Number list

Let us look at the first sorting process in Figure 7.17.

Figure 7.17: Loop 1 sorting process

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  139

The second sorting process is shown in Figure 7.18.

Figure 7.18: Loop 2 sorting process

Copyright © Open University Malaysia (OUM)


140  TOPIC 7 SORTING

Next is loop 3 (see Figure 7.19).

Figure 7.19: Loop 3 sorting process

Now, let us look at loop 4 in Figure 7.20.

Figure 7.20: Loop 4 sorting process

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  141

Next is loop 5 (see Figure 7.21).

Figure 7.21: Loop 5 sorting process

Lastly, the sorting process is done in loop 6 (see Figure 7.22).

Figure 7.22: Loop 6 sorting process

Observe that the n number of items is 7, therefore the number of loops is n  1,


which is 6. For each loop, the number value is reduced by 1 and for each loop, the
largest value is brought to the end of the list. In the example given in Figure 7.16,
even though in loop 2 the list seems to be already sorted, this algorithm still
continues until loop 6.

7.4.2 Bubble Sort Algorithm Efficiency


In the first repetition, the bubble sort algorithm would have to look at n elements,
then after that it would look at n  1 elements (since the biggest integer is at the
end) and so on and so forth till one comparison occurs.

n  n  1
n + n  1 + n  2 + ... + 1 =
2

So, the efficiency of the bubble sort algorithm is O(n2).

Copyright © Open University Malaysia (OUM)


142  TOPIC 7 SORTING

ACTIVITY 7.1

Given below is the function SortData.

void SortData(int list[], int no)


{
int i, indx, j, largest;

for (i = no; i >=0; i--)


{
largest = list[0];
indx = 0;
for (j = 1; j <= i; j++)
if (list[j] > largest)
{
largest = list[j];
indx = j;
}
list[indx] = list[i];
list[i] = largest;
}
}

Show each of the steps on how the list {25, 57, 48, 37, 12} is sorted using
the function.

Copyright © Open University Malaysia (OUM)


TOPIC 7 SORTING  143

 Sorting is the process of arranging data in either ascending or descending


order.

 Simple selection sort is the easiest method of sorting  we will choose the
smallest or biggest in the list and place it at the most appropriate position.

 In linear insertion sort, the list is divided into two parts: sorted and unsorted.
In each pass, the first element of the unsorted sublist is transferred to the sorted
sublist by inserting it at the appropriate place.

 The quick sort is an in-place, divide-and-conquer, massively recursive sort and


a very efficient and fastest sorting algorithm in practice.

 Bubble sort is a sorting algorithm that will compare adjacent pair of data in a
list, swapping them if they are out of order, continuing down the list until all
the adjacent pairs are in order. The whole process is repeated again in the next
loop.

 In general, all sorting procedures will produce the same results and the only
thing that differentiates them is from the aspect of efficiency.

Bubble sort Quick sort


Efficiency Simple selection sort
Linear insertion sort

Copyright © Open University Malaysia (OUM)


Topic  Searching
8
LEARNING OUTCOMES
By the end of this topic, you should be able to:
1. Explain the basic search techniques; and
2. Apply two types of search techniques.

 INTRODUCTION
There are a variety of applications that require searching a key value in a given
data structure. In fact, searching is a costly computational activity. Therefore, a
number of efficient algorithms have been developed for searching.

In this topic, you will be introduced to two techniques that can be used in data
search namely sequential search technique and binary search technique. So are you
ready to do some „searching‰? Let us continue with the lesson.

8.1 BASIC METHODS OF SEARCHING


Generally, we use the search operation to find data that is located in a file. That
data could either be a record or record field. What does a record mean?

A record is a single or group of fields in a record.

Copyright © Open University Malaysia (OUM)


TOPIC 8 SEARCHING  145

One of the fields is nominated as the record key, which is a unique signature for
that record, for instance, your IC or MyKad 12-digit numbers.

How about a file? What does it mean?

A file is one or more groups of record.

The relationship between the key and record can be simple or complex. The key
found in our record is named as the internal key. Meanwhile, a key that is kept
outside of the record is called external key. For the external key cases, we use
pointers to refer to the matching record. Did you know that there are two types of
keys? These are further explained in Table 8.1.

Table 8.1: Two Types of Keys

Primary Key Secondary Key


 A key field with a unique value for each  A key field that is not unique to the
record. record.
 There are no two records that can have  There can be two or more records with
the same key value. the same key.
 For example, your identity card (IC)  For example, the name of a state, where
numbers, where each individual will there can exist two or more people that
have different IC numbers. originate from the same state.

What does search algorithm mean?

Search algorithm is the algorithm that receives an argument a and tries to find
the record key that has the value a.

That algorithm will either return the entire record or a pointer value that points to
the required record, if the search was successful to begin with. If not, the null value
will be returned.

There are also cases where, if the search is not successful, the key value that is
being searched will be inserted into the data structure and this is called an insertion
operation.

Copyright © Open University Malaysia (OUM)


146  TOPIC 8 SEARCHING

For successful searches, we call this an access operation. For the operation to delete
a key value, it is called deletion operation. You should already know these terms
from the previous topics. Do you still remember?

There are several techniques that can be used in data search. Among them are:

(a) Sequential search technique;

(b) Binary search technique; and

(c) Binary tree search technique (which will be covered in the next subtopic).

Our next subtopics will focus on sequential search and binary search. Let us
continue the lesson.

8.1.1 Sequential Search


Did you know that this technique is the simplest, but it is slow and not so efficient?
This technique is applied to records that are arranged using arrays or linked lists.

In addition, the sequential searching method works well with small and unsorted
arrays. Searching begins with the first record and is done sequentially until the
data is found. Let us look at Example 8.1 which demonstrates this type of search
technique.

Example 8.1:
Let say A[1], A[2], ... , A[n] are array elements that consist of n keys Ki;
(1 <= i <= n) that are different.
Keys K1 K2 K3 K4 ... Kn
Array Elements A[1] A[2] A[3] A[4] ... A[n]

Solution:
The K key is the argument that is searched (key search). The following algorithm
will find the smallest integer i (array index) where Ki is its key.
For i = 0 until key number n
Start for
If search value = K(i)
Return the i value
End for

Copyright © Open University Malaysia (OUM)


TOPIC 8 SEARCHING  147

SELF-CHECK 8.1

Which of the following search techniques begins with the first record and
is done continuously until the data is found or end of records is reached?

A. Binary search

B. Binary tree search

C. Sequential search

8.1.2 Binary Search


Binary search can only be used for sorted arrays, but it is fast compared to
sequential search. In binary search, we need to find the position for a K search key
in a table. The search key is compared to a key in the middle of the table. If they
are equal, then the search is successful, otherwise, the search is reduced by half.

If the search value is less than the middle value of the array, the first half is
searched, otherwise the second half is searched. This continues until the search
value is equal to the middle value of the array or until the search value is not found
and the search is unsuccessful.

The algorithm for binary search is as follows:


If key value in middle of table = search key
Search successful

If not
Test whether the value of search key > value of middle
key

If YES
The search process continues for the element
above the middle key in the table

If NO
The search process continues for the elements
below the middle key in the table

Copyright © Open University Malaysia (OUM)


148  TOPIC 8 SEARCHING

Let us look at Example 8.2 that demonstrates binary search.

Example 8.2:
Find search key 39 in the following array (see Figure 8.1).

Figure 8.1: An array

Solution:
Number of data = 10
Initial value = 0 (array index value starts from 0)
Final value = 9

(a) Round 1
We find the middle value first.
Middle value = (Initial + Final)/2
= (0 + 9)/2
= 9/2
=4

Test the middle key with the search key.

Middle key = k(4) = 20 20 < 39

The location of k(4) is shown in Figure 8.2.

Figure 8.2: The location of k(4)

Since the search key value (39) is bigger than the middle key (20), the focus
of the search will only be on the right of the middle key, which is location
k(5) until k(9).

Copyright © Open University Malaysia (OUM)


TOPIC 8 SEARCHING  149

(b) Round 2
The result of Round 1 found that the focus location for the search is on the
right of the middle key, which is the location that goes towards the end.

Therefore, we need to change the initial value to the location to the right of
the middle value, which is the middle value plus 1.

Change initial value, which is initial = Middle + 1


=4+1
=5

We calculate for the middle value again:

Middle value = (Initial + End)/2


= (5 + 9)/2
= 14/2
=7

Test middle key with search key:

Middle key = k(7) = 40 40 < 39

(see Figure 8.3)

Figure 8.3: The location of k(7)

In this round, we found that the value of the search key (39) is less than
the middle key (40). Therefore, the focus of the search will only be to the
left of that middle key, which is location k(5) and k(6).

You need to give your full attention to follow this algorithm. Let us continue
to the next round.

Copyright © Open University Malaysia (OUM)


150  TOPIC 8 SEARCHING

(c) Round 3
The result of Round 2 has revealed that the focus of the search is to the left of
the middle key, which is the location leading towards the start value.

Therefore, we need to change the end value of the location to the left of the
middle value, which is the middle value minus one.

Change end value, end = Middle  1


=71
=6

We find the middle value again:

Middle value = (Initial + end)/2


= (5 + 6)/2
= 11/2
=5

Test the middle key with the search key:

Middle key = k(5) = 25 25 < 39

In this round, we found that the search key value (39) is bigger than the
middle key (25), so the focus of the search is only to the right of the middle
key, which is at location k(6).

(d) Round 4
From the result of Round 3, the search location focus is now on the right of
the middle key, which is the location leading towards the end. Here, we need
to change the initial value of the location to the right of the middle key value,
which is the middle value plus one.

Change final value, initial = Middle + 1


=5+1
=6

We calculate for the middle value again:

Middle value = (Initial + End)/2


= (6 + 6)/2
= 12/2
=6

Copyright © Open University Malaysia (OUM)


TOPIC 8 SEARCHING  151

Test the middle key with the search key:

Middle key = k(6) = 39

Thus, our search is successful.

SELF-CHECK 8.2

What is the main difference between sequential search and binary


search?

A. Sequential search starts from the first element to the last element in
the array, while binary search starts from the middle of the array.

B. Sequential search starts from the middle of the array, while binary
search starts from the beginning of the array.

C. Both sequential search and binary search starts from the middle of
the array and searches each element till the data is found.

8.2 ANALYSIS OF SEARCHING ALGORITHM


Before we end this topic, let us do an algorithm analysis for the two searching
algorithms discussed earlier.

(a) Sequential Search


In the best case, the search procedure terminates after one comparison only,
whereas in the worst case it will do n comparisons. Therefore on average,
it will do approximately n/2 comparisons. Since the searching time is
proportional to the number of comparisons required to be performed, the
linear search requires an average time proportional to O(n) to search one
element.
2
Therefore, to search n elements, it requires a time proportional to O(n ).
Hence, we conclude that this searching technique is better suited when the
value of n is small. The reason for this is the difference between the n and
2
n is small for smaller values of n.

Copyright © Open University Malaysia (OUM)


152  TOPIC 8 SEARCHING

(b) Binary Search


In the binary search, the number of comparisons required for one element in
the list is not more than log2 n, where n is the size of the list.

Therefore, the binary search algorithm has a time complexity of


O(n log2 n).

ACTIVITY 8.1

1. You are given a list of integers as follows:

4 7 8 10 4 21 22 6 62 77 81 91

Using the binary search method, show a step-by-step process that


is carried out to search for number 22.

2. The previous list of numbers in Question 1 is modified to become


the following:

91 81 77 62 36 22 21 14 10 8 7 4

By using the binary search method, show a step-by-step process


that is done to find number 22.

 We use the search operation to find a data that is located in a file.

 The search algorithm is the algorithm that receives an argument a and tries to
find the record key that has the value a.

 The basic search techniques that can be applied in solving related problems
include sequential search, binary search and binary tree search (this will be
covered in Topic 9).

Copyright © Open University Malaysia (OUM)


TOPIC 8 SEARCHING  153

 Sequential search is applied to records that are arranged using arrays or linked
lists. It works well with small and unsorted arrays.

 Binary search can only be used for sorted arrays, but it is fast compared to
sequential search. In binary search, we need to find the position for a K search
key in a table.

Binary search Secondary key


Primary key Sequential search

Copyright © Open University Malaysia (OUM)


Topic  Trees
9
LEARNING OUTCOMES
By the end of this topic, you should be able to:
1. Describe the general structure of a tree;
2. Differentiate between binary tree and binary search tree (BST); and
3. Explain expression tree.

 INTRODUCTION
In the previous topics, we looked at linear data structures, which include lists,
linked lists, stacks and queues. Now in this topic, we shall look at the tree data
structure, which is different from the other data structures previously discussed.

Before you proceed further into this topic, make sure that you really understand
the linked list topic and the concept of pointer that have been learnt previously.

Did you know that elements in a tree are arranged in a hierarchical structure? What
else do we need to know about tree? Let us proceed with the lesson.

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  155

9.1 GENERAL STRUCTURE OF A TREE


Firstly, in data structure what does a tree mean?

Tree is a structure that consists of nodes that are linked with directed pointers.

Let us look at a simple example of a tree in Figure 9.1.

Figure 9.1: Example of a tree

Another example of a tree is shown in Figure 9.2.

Figure 9.2: Another example of a tree

Take note that there are several important terms that you need to know before the
tree structure can be explained. A node without a pointer pointing at it is called
root. In Figure 9.1, M is the root node. A node that has a pointer to the left or/and
to the right are the parent node, while the nodes that is being referred to is the
child nodes. In Figure 9.1, node O and W are the child nodes for node P, while
node P is the parent node for nodes O and W.

Copyright © Open University Malaysia (OUM)


156  TOPIC 9 TREES

Nodes with the same parent are called siblings. Therefore, nodes O and W in
Figure 9.1 are siblings. Nodes that do not have any child nodes are called leaves.
So, nodes G, O and W in Figure 9.1 are leaves. The directed pointer that links one
node to another is called a branch. The depth of the tree refers to the level value
that is the highest in the tree. For Figure 9.1, the depth of the tree is 3. There are
two types of trees that are important:

(a) Binary tree; and

(b) Binary search tree.

These two types of trees are further explained in the next subtopics.

9.2 BINARY TREE


What does a binary tree mean?

A binary tree is a tree in which a node can only have a maximum of two
subtrees.

In other words, a node can be zero, one or two subtrees. These subtrees are
designated as the left subtree and right subtree. Figure 9.3 shows you an example
of a binary tree.

Figure 9.3: Example of a binary tree

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  157

We can also say that a binary tree is a tree structure where each node has not more
than two child nodes. The example given in Figure 9.3 shows a binary tree that has
a character in each node. The maximum number of nodes in a binary tree with a
depth of K is 2k  1 for K  1. For Figure 9.3, the maximum number of nodes is
23  1, which is 8  1 = 7.

Note: Nodes can be represented by a circular or rectangular symbol. A binary


tree can be implemented using arrays and also linked lists. The implementation
using arrays is not covered in this topic.

9.2.1 Data Structure for Binary Tree


A binary tree can be represented using a linked structure that is very similar to a
linked list. The only difference is that each binary node has two pointers that each
points to its left and right child node. Look at the following definition of the binary
tree data structure (see Example 9.1).

Example 9.1:
typedef struct BinaryTree {
int data;
struct BinaryTree *left_child;
struct BinaryTree *right_child;
} BINARY_TREE;

BINARY_TREE *tree;

One binary tree node can be pictured as shown in Figure 9.4.

Figure 9.4: An example of a binary tree node

Copyright © Open University Malaysia (OUM)


158  TOPIC 9 TREES

Each node has two pointers or left_child and right_child and each will
point to a left subtree and a right subtree. The data in the node can contain any
format of data, like integers, floats, characters or strings.

9.3 BINARY SEARCH TREE (BST)


One main use of trees is its ability to keep nodes in a certain sequence so that it is
easily accessed. This type of tree is called a binary search tree (BST).

A binary search tree is a more specific binary tree, where the value of a node
is bigger than the value of its left child node, but smaller than the value of its
right child node.

The example in Figure 9.5 shows a binary search tree.

Figure 9.5: An example of a binary search tree

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  159

The BST data structure is as follows (see Example 9.2).

Example 9.2:
typedef struct BinaryTree {
int data;
struct BinaryTree *left_child;
struct BinaryTree *right_child;
} BINARY_TREE;

BINARY_TREE *BST;

What are the operations that can be performed on BST? The operations that can be
performed on BST are:

(a) Create BST;

(b) Search BST;

(c) Insert node into BST;

(d) Traverse nodes in BST; and

(e) Delete node in BST.

The following subtopics will discuss these operations. The programming codes
that are used in the subtopics have been modified from the book Struktur Data
Menggunakan C by Marini Abu Bakar (1998).

9.3.1 Creating BST


The CreateBST only assigns a reference to BST as NULL. We will give the NULL
value as the value to refer the BST.
void CreateBST (BST **tree){
*tree = NULL;
}

Copyright © Open University Malaysia (OUM)


160  TOPIC 9 TREES

9.3.2 Searching BST


As was discussed in Subtopic 9.3, each BST node has a value that is greater than its
left child node, but lesser than the value of its right child node. The aim of searching
a BST is to determine whether a certain node exists or not in that particular BST.

How do we achieve this? Here, the user should give the values to the data content
for each node in the BST. The following is the function that can achieve this (see
Example 9.3).

Example 9.3:

BST *SearchBST(BST *tree, int item){


while ((tree) && (item != tree -> data))
{
if (item < tree -> data)
tree = tree->left_child;
else
tree = tree->right_child;
}
return tree;
}

9.3.3 Inserting Nodes in BST


The node insertion operation in BST structures require the node to be inserted at a
suitable position for preserving the BST characteristics. Take note that once a data
item has been inserted in a BST, it cannot be re-inserted into a BST. The following
pseudo-code explains this operation.
1. Search BST for node containing the item

2. If the node exists


2.1 Display message “node exists”
2.2 End

3. If not
3.1 Insert data or item at a suitable position (as a
left or right child)

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  161

BST can be built by calling the InsertBST function repeatedly and inserting the
node in the BST by starting with the root that holds the NULL value. This function
is similar to the SearchBST, with an added pointer that points to the parent node
while it is executed. Consider the BST in Figure 9.6.

Figure 9.6: Initial state of InsertBST operation

Let us suppose that we want to insert the character „A‰ in the BST. To insert this
data, we will begin with the root node that is referred to by pointer p 2 and compare
A with the data content in the root node (see Figure 9.7).

Figure 9.7: Comparing data „A‰ with roots node

Copyright © Open University Malaysia (OUM)


162  TOPIC 9 TREES

Since A < M, we then move down the left subtree. The pointer b points to the
parent node of the current node being evaluated (see Figure 9.8).

Figure 9.8: Evaluating the parent node of the subtree

Then, we compare A with C. Since A < C then, we move to the left subtree for C,
which is NULL. The NULL value means that A does not exist in the BST and needs
to be inserted as the left child of node C that is pointed to by b (see Figure 9.9).

Figure 9.9: Insertion of „A‰ into the BST

The InsertBST function for performing the insertion function is shown in


Example 9.4.

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  163

Example 9.4:

void InsertBST (BST **p2, int item) {

BST *t, *b;

t = *p2;
b = NULL;

while (t && (item != t->data)) {

b = t;
if (item < t->data)
t = t->left_child;
else t = t->right_child;
}

if (t != NULL)
printf(“\nError: Data already exists”);

else {
t = NewBSTNode(item);
if (b == NULL)
*p2 = t;
else {
if (item < b->data)
b->left_child = t;
else b->right_child = t;
}
}
}

Copyright © Open University Malaysia (OUM)


164  TOPIC 9 TREES

This function will receive a BST and the data value that needs to be inserted. Then,
the BST will be searched to determine the insertion point and whether the node
exists. If the node with the item exists, an error message will be displayed. If
otherwise, the node will be inserted in a suitable position.

This function will call the NewBSTNode function, to reserve the node space
dynamically by using the library function malloc(). This function will receive
the data for the node and will return a pointer that refers to the node (see
Example 9.5).

Example 9.5:

BST *NewBSTNode (int item) {


BST *p = NULL;
p = (BST*) malloc (sizeof(BST));

if (p == NULL)
printf(“ERROR”);
else {
p->data = item;
p->left_child = NULL;
p->right_child = NULL;
}
return p;
}

The sequence of nodes inserted into the BST will determine the shape of the BST,
even though the data content is the same. For example, the BST that is produced
when the data with 3, 4, 5, 6, 1, 2 is inserted is completely different from the BST
produced when data with 5, 1, 3, 4, 2, 6 is inserted, because the succession of data
insertion has changed.

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  165

SELF-CHECK 9.1
Where is the insertion of a new data item „R‰ into this binary search tree
(BST)?

A. To the left of H

B. To the right of P

C. To the left of T

9.3.4 Traversing BST


What does traversing BST operation mean? The traversing BST operation means
an operation to move within the binary tree by visiting each node once. Take note
that a recursive approach is used for this operation. There are three types of
important traversals that will be touched upon in this subtopic and they are:

(a) (In-order) Traversal


This type of traversal will travel through the BST using the following steps:

(i) Visit the tree on the left;

(ii) Retrieve data from the node; and

(iii) Visit the tree on the right.

Copyright © Open University Malaysia (OUM)


166  TOPIC 9 TREES

If the BST in Figure 9.10 is traversed in this way, what will be the output?

Figure 9.10: Binary search tree

The output for Figure 9.10 will be:

5 8 9 10 16 18 20

Look at the in-order traversal that produces an ascending order number.

The function to perform this in-order traversal is as follows (see Example 9.6):

Example 9.6:

void inOrder(BST *j){


if (j){
inOrder(j->left_child);
printf(“\n%d”, j->data);
inOrder (j->right_child);
}
}

(b) (Pre-order) Traversal


Pre-order traversal will move through the BST using the following steps:

(i) Get data from node;

(ii) Visit tree on the left; and

(iii) Visit tree on the right.

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  167

Let us use the example in Figure 9.10. If the BST in Figure 9.10 is traversed
using the pre-order traversal, the output that would be produced is:

10 8 5 9 18 16 20

The function to perform this pre-order traversal is shown in Example 9.7.

Example 9.7:

void preOrder(BST *j){


if (j){
printf(“\n%d”, j->data);
preOrder(j->left_child);
preOrder (j->right_child);
}
}

(c) (Post-order) Traversal


Post-order traversal will move through the BST using the following steps:
(i) Visit tree on the left;

(ii) Visit tree on the right; and

(iii) Get data from node.

Let us use again Figure 9.10 as an example. If the BST in Figure 9.10 is
traversed using the post-order traversal, the output produced would be:

5 9 8 16 20 18 10

Copyright © Open University Malaysia (OUM)


168  TOPIC 9 TREES

The function to perform the post-order traversal is shown in Example 9.8.

Example 9.8:

void postOrder(BST *j){


if (j){
postOrder(j->left_child);
postOrder (j->right_child);
printf(“\n%d”, j->data);
}
}

9.3.5 Deleting Nodes in BST


This operation involves three node conditions:

(a) Node to be Deleted is Leaf


Look at the BST in Figure 9.11. The node „i‰ needs to be deleted. Pointer p
points to the new node that will be deleted and pointer f points to the parent
of that node.

Figure 9.11: Leaf to be deleted in BST

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  169

The algorithm is:

1. Set right_child for f to NULL

2. Free p

After deleting node „i‰, the new BST is shown in Figure 9.12.

Figure 9.12: A new BST after deleting a leaf

(b) Node to be Deleted has One Child Node


Let say node „h‰ needs to be deleted and has only one child node (see
Figure 9.13).

Figure 9.13: Deleting node „h‰

Copyright © Open University Malaysia (OUM)


170  TOPIC 9 TREES

The algorithm is as follows:

1. Set parent->left_child = x->left_child;

2. Free x

The new BST is shown in Figure 9.14.

Figure 9.14: A new BST after deleting node „h‰

(c) Node to be Deleted has Two Child Nodes


Let us look at BST in Figure 9.15. Let us suppose node „n‰ needs to be
removed.

Figure 9.15: Removing node „n‰

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  171

The algorithm is as follows:

1. Identify the following node for node „n‰ according to in-order


traversal.

The in-order sequence of BST:

a b c i k m n o p s

So, the node after „n‰ is „o‰;

2. Assign the contents that are pointed to by pointer p, which is node „n‰
with the value stored in node „o‰; and

3. Delete node „o‰ (node „o‰ has no child according to Condition 1).

The new BST is shown in Figure 9.16.

Figure 9.16: New BST after removing node „n‰

Copyright © Open University Malaysia (OUM)


172  TOPIC 9 TREES

SELF-CHECK 9.2
Consider the following binary search tree:

Which is the new root node if the root node 40 is deleted?

A. 20

B. 30

C. 70

9.4 EXPRESSION TREE


Before we end this topic, let us have a look at expression trees.

Expression trees are binary trees that are used to represent arithmetic
expressions.

Its general form is:


Operand1 Operator Operand2

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  173

The operator is the middle node (root) and operand1 and operand2 are the
left child and right child nodes, respectively. When you are given an arithmetic
expression, add the parentheses to confirm the precedence execution.

The operator that has the lowest precedence is chosen to become the root node of
the expression tree.

Look at the following expression:

A / (B * C) + D

Add parentheses.

((A / (B * C)) + D)

So, the expression tree formed can be depicted as in Figure 9.17.

Figure 9.17: Expression tree

Can you see that at the operator node, the left and right parentheses are added? If
you traverse through the expression tree in order, you will get an infix notation.

However, if you perform a post-order traversal, postfix notation is produced and


if a pre-order traversal is carried out, prefix notation is received.

Infix expression (LNR): ((A / (B * C)) + D)

Postfix expression (LRN): A B C * / D + (parentheses disregarded)

Prefix expression (NLR): + / A * B C D (parentheses disregarded)

Copyright © Open University Malaysia (OUM)


174  TOPIC 9 TREES

ACTIVITY 9.1

Build an expression tree, then perform in-order, post-order and pre-order


traversals for the following arithmetic expressions:

(a) A*(B+C)+D

(b) A+B*C–D*E

 Trees are structures that consist of nodes that are linked with directed pointers.

 A node without a pointer pointing at it is called root.

 A node that has a pointer to the left or/and to the right are the parent node,
while the node that is being referred to is the child node.

 Nodes with the same parent are called siblings.

 Nodes that do not have any child nodes are called leaves.

 The directed pointer that link one node to another is called a branch.

 The depth of the tree refers to the level value that is the highest in the tree.

 There are two types of trees: binary tree and binary search tree (BST).

 A binary tree is a tree in which a node can only have a maximum of two
subtrees. In other words, a node can be zero, one or two subtrees.

 A binary tree can be represented using a linked structure that is very similar to
a linked list. The only difference is that each binary node has two pointers that
each points to its left and right child nodes.

 A binary search tree is a more specific binary tree, where the value of a node is
bigger than the value of its left child node, but smaller than the value of its
right child node.

 Expression trees are binary trees that are used to represent arithmetic
expressions.

Copyright © Open University Malaysia (OUM)


TOPIC 9 TREES  175

Binary search tree (BST) Parent


Binary tree Post-order traversal
Expression tree Pre-order traversal
In-order traversal Root
Leaves Siblings

Marini Abu Bakar. (1998). Struktur data menggunakan C. Petaling Jaya, Malaysia:
Prentice Hall.

Copyright © Open University Malaysia (OUM)


Topic  Graphs
10
LEARNING OUTCOMES
By the end of this topic, you should be able to:
1. Describe the graph concepts and its terminologies;
2. Identify five types of graph;
3. Explain graph representation and storage structure;
4. Summarise the six basic operations of graph; and
5. Apply the breadth first search and depth first search approaches.

 INTRODUCTION
Did you know that graphs are natural models used to represent a relationship
among data objects? We often need to represent such relationship among data
objects while dealing with problems in computer science, engineering and many
other disciplines.

Therefore, the study of graphs as one of the basic data structures is important. So
are you ready to discover more? Let us start the lesson.

Copyright © Open University Malaysia (OUM)


TOPIC 10 GRAPHS  177

10.1 GRAPH CONCEPT AND TERMINOLOGIES


Firstly, what is a graph? What can you say to define it?

A graph is a collection of vertices (or nodes) and the connections between


them.

Take note that there are no limitations on the number of vertices in a graph or the
number of connections a vertex can have to another vertex. The number of vertices
is represented by V , whereas number of edges is denoted by E . An edge e in
a graph that is associated with a pair of vertices v and w, e = (v, w ), are declared
as to be incident on e. Two vertices v and w in a graph G, are said to be adjacent
vertices (or neighbours), if (v, w ) is an edge in G.

For any two vertices, they are connected if there is a path between vertices. A graph
is considered as connected if there is a path from any vertex to another vertex. A
directed graph is considered as strongly connected if there is a path from every
vertex to every other vertex in the digraph. A directed graph is weakly connected
if there are at least two vertices that are not connected. A graph is called a disjoint
graph if it is not connected.

The degree of a vertex is the number of lines (or edges) incident to it. It is denoted
by deg(v ). The outdegree of a vertex in directed graph is the number of arcs
leaving the vertex. Meanwhile, the indegree of a vertex in directed graph is the
number of arcs entering the vertex. However, a loop at a vertex will contribute
twice, which is of degree two.

Copyright © Open University Malaysia (OUM)


178  TOPIC 10 GRAPHS

10.2 TYPES OF GRAPH


There are five types of graph that will be covered in this topic. They are listed in
Figure 10.1.

Figure 10.1: Five types of graph

Let us learn these five types of graph in next subtopics.

10.2.1 Simple Graph


What is a simple graph?

Simple graph is a graph with neither parallel edges nor loops.

Copyright © Open University Malaysia (OUM)


TOPIC 10 GRAPHS  179

A simple graph G = (V, E ) consists of a nonempty set of V vertices and may be an


empty set E of edges, each edge being a set of two vertices from V. The definitions
of loop, parallel edge and isolated vertex are explained in Table 10.1.

Table 10.1: Definitions of Loop, Parallel Edge and Isolated Vertex

Term Definition
Loop An edge incident on a single vertex.
Parallel edge Edges e 2 and e 3 in graph G that are associated with the vertex v 2
and v 3 (see Figure 10.3).
Isolated vertex A vertex that is not incident on and edges.

These terms can be illustrated as in Figure 10.2.

Figure 10.2: Example of parallel edge, loop and isolated vertex

As you can see in Figure 10.3, e 1 is a loop while v4 is an isolated vertex.

10.2.2 Directed Graph and Undirected Graph


Let us see Figure 10.3 for directed graph (or digraph).

Figure 10.3: Directed graph

Copyright © Open University Malaysia (OUM)


180  TOPIC 10 GRAPHS

Directed edges are indicated by arrows. In a digraph, there is a line with direction
(arrow head) to its successor.

Do you know what is an arc?

The line in a digraph is known as arc.

The flow in digraph must follow the indicated direction illustrated by the arcs
between two vertices.

Now, let us look at Figure 10.4 which illustrates an undirected graph.

Figure 10.4: Undirected graph


As you can see in Figure 10.4, there are no arrows on the edges for an undirected
graph. In undirected graph, the flow between the two vertices can be in either
direction. The reason for this is because no arc exists. v 1 and v 2 are considered as
adjacent vertices because there is an edge connecting both vertices.

However, v 1 and v 3 are not adjacent vertices. In an undirected graph, a path may
traverse in any direction. Do you know, what is a path?

A path is defined as a sequence of vertices where every vertex is adjacent to


the next one.

For example, in an undirected graph (refer to Figure 10.4), v 1  v 2  v 3 is a path


and v 3  v 2  v 1 is also a path. In a directed graph or digraph (refer to Figure 10.3),
v 2  v 3 v 4 is a path but v 4  v 3  v 2 is not a path.

A cycle is a path which consists of at least three vertices that starts and ends
with the same vertex.

Copyright © Open University Malaysia (OUM)


TOPIC 10 GRAPHS  181

For example, in Figure 10.4, v 2  v 1  v 4  v 2 is a cycle. Meanwhile in Figure 10.3,


v 2  v 3 v 4  v 2 are cycles.

Keep in mind that a loop is a special case of a cycle, where the cycle begins and
ends with the same vertex.

The outdegree of a vertex (v 4) in a digraph (refer to Figure 10.3) is two and the
indegree of a vertex (v 4) in a digraph is one. In an undirected graph (Figure 10.4),
the degree of a vertex (v 4) is three.

10.2.3 Weighted Graph


What is a weighted graph?

A graph with numbers labelled on the edges is called a weighted graph.

If edge e is labelled with 5, then the weight of edge e is 5. Let us look at


Figure 10.5 and find out the weight for each edge.

Figure 10.5: Weighted graph

The weight for each edge in Figure 10.5 is as follows:

(a) (v 1, v 2): Weight 3

(b) (v 2, v 3): Weight 4

(c) (v 3, v 4): Weight 3

(d) (v 1, v 4): Weight 4

(e) (v 2, v 4): Weight 5

Copyright © Open University Malaysia (OUM)


182  TOPIC 10 GRAPHS

10.2.4 Complete Graph


What is a complete graph?

A complete graph on n vertices, K n, is a simple graph with n vertices.

Remember, there must be an edge between every pair of distinct vertices. The
following Figure 10.6 denotes K 3, K 4 and K 5 respectively.

Figure 10.6: Complete graphs

10.2.5 Cycle
Lastly, let us look at cycle graph.

The cycle Cn, with n  3, consists of n number of vertices and edges.

As shown in Figure 10.7, C 4 consists of four vertices and edges, while C 6 contains
six vertices and edges.

Figure 10.7: Cycles

Copyright © Open University Malaysia (OUM)


TOPIC 10 GRAPHS  183

SELF-CHECK 10.1

Describe five types of graph.

10.3 GRAPH REPRESENTATION AND STORAGE


STRUCTURE
There are several ways to represent graphs. We shall discuss three methods which
are using:

(a) Adjacency list;

(b) Adjacency matrix; and

(c) Incidence matrix.

Let us consider graph G 1 in Figure 10.8.

Figure 10.8: Graph G1

The vertex vector for graph G 1 is shown in Figure 10.9.

Figure 10.9: Vertex vector for graph G 1

Copyright © Open University Malaysia (OUM)


184  TOPIC 10 GRAPHS

(a) Adjacency List


Adjacency list specifies all vertices adjacent to each vertex of the graph. Also
called star representation, the list is being implemented as a table or linked
list. Adjacency list uses a two-dimensional ragged array to store the edges
(or arcs). Linked-list is used to store the vertices. Vertex list is a singly-linked
list of the vertices in the list. The adjacent list for graph G 1 (from Figure 10.8)
is shown in Figure 10.10.

Figure 10.10: Adjacency list for graph G 1

(b) Adjacency Matrix


Adjacency matrix of graph G = (V, E ) is a binaryV  V  matrix, such
that each entry of this matrix, aij = 1, if there exists an edge, but aij = 0, if no
edge exists. Adjacency matrix uses a vector (one-dimensional array) for the
vertices and a matrix (two-dimensional array) to store the edges (refer to
Figure 10.11).

Figure 10.11: Undirected graph G 2

Copyright © Open University Malaysia (OUM)


TOPIC 10 GRAPHS  185

The adjacency matrix using the ordering of vertices p, q, r, s (from


Figure 10.11) is shown in Figure 10.12.

Figure 10.12: Adjacency matrix for graph G 2

Meanwhile, the vertex vector for graph G 2 is shown in Figure 10.13.

Figure 10.13: Vertex vector for graph G 2

(c) Incidence Matrix


Incidence matrix is based on the incidence of vertices and edges. Incidence
matrix of graph G = (V, E ) is a V  E  matrix such that each entry of this
matrix, aij = 1, if edge ej is incident with vi , else aij = 0 if edge ej is not incident
with vi . Using the graph G 1 from Figure 10.8, the incident matrix for the
graph is shown Figure 10.14.

Figure 10.14: Incident matrix for graph G 1

Copyright © Open University Malaysia (OUM)


186  TOPIC 10 GRAPHS

10.4 GRAPH OPERATIONS


In this subtopic, we will define six basic operations of a graph. In order to maintain
a graph, the following operations (refer to Table 10.2) are required.

Table 10.2: Six Basic Operations of a Graph

Basic Operation Description


Add vertex Will insert a new vertex into the graph. The vertex at this moment
is still disjointed, since there is no edge that connects the vertices in
the graph.
Delete vertex Removes a vertex from a graph. Whenever this operation is
performed, all connected edges are removed.
Add edge Will connect a vertex to its destination vertex. Whenever a vertex
requires many edges, then add edge must be called once for each
adjacent vertex. To perform this add edge operation, two vertices
must be specified first. If it is a directed graph, then one vertex is
defined as source and the other vertex as destination.
Delete edge Removes an edge from a graph.
Find vertex Will traverse a graph looking for a vertex. When vertex is found,
then the address is returned. However, an error is returned, if
vertex is not found.
Traverse graph An application might require all vertices in a graph to be visited. It
means that the graph should be traversed. The problem is that a
graph can have multiple parents. Therefore, we must make sure
that each vertex is processed exactly once. We must also consider
that there are multiple paths to a vertex.
We can reach the vertex using more than one direction. We may
include a flag at each vertex indicating that we have arrived at the
vertex. Before graph traversal starts, the flag is set to off. Then, as
we traverse along the graph, the flag at each visited vertex is set to
on. The two approaches to traverse a graph are defined in the next
subtopic, which are breadth first search and depth first search.

Next, we will focus on graph traversal.

SELF-CHECK 10.2

Describe the six basic operations of a graph.

Copyright © Open University Malaysia (OUM)


TOPIC 10 GRAPHS  187

10.5 GRAPH TRAVERSAL


Did you know that the two algorithms for traversing a graph are known as
breadth first search algorithm and depth first search algorithm? These are further
explained in the next subtopics.

10.5.1 Breadth First Search


Did you know that the idea of breadth first search is to process all the vertices on
a certain level, before going to the next level? It is similar to level-by-level traversal
of an ordered tree. If the traversal has just visited a vertex v, then it next visits all
vertices adjacent to v, putting the adjacent vertices in a waiting list to be traversed
later, after all the vertices adjacent to have been visited.

Figure 10.15 illustrates the breadth first search  first by visiting the root, v, then
u 1, u 2, u 3, y 1 and y 2.

Figure 10.15: Breadth first search

An outline of pseudocode representing the breadth first search algorithm which


uses queue to traverse the graph, is as shown in Algorithm 1 (Gilberg & Forouzan,
1998).

Copyright © Open University Malaysia (OUM)


188  TOPIC 10 GRAPHS

Algorithm 1:
Breadth first search

Algorithm breadthFirst (val graph <graphHead pointer>)


Processes the keys of the graph in breadth-first order.

Pre : Graph is pointer to graph


Post : Vertices processed

1 if (graph->first null)
2 return
// First set all processed flags to not processed
// Flag: 0—Not processed, 1—Enqueued, 2—Processes
3 queue = createQueue
4 walkPtr = graph->first
loop (walkPtr not null)
5 walkPtr->processed = 0)
6 walkPtr = walkPtr->nextVertex
// Process each vertex in vertex list
7 walkPtr = graph->first
8 loop (walkerPtr not null)
9 if (walkPtr->processed < 2)
if (walkPtr->processed < 1)
10 // Enqueue and set process flag to queued (1)
11 Enqueue (queue, walkPtr)
12 walkPtr->processed = 1
// Now, process descendents of vertex at queue front
13 loop (not emptyQueue (queue))
14 dequeue(queue, vertexPtr)
15 // Process vertex and flag as processed
16 process(vertexPtr)
17 vertexPtr->processed = 2
// Enqueue all vertices from adjacent list
18 arcPtr = vertexPtr->arc
19 loop (arcPtr not null)
20 toPtr = arcPtr->destination
21 if (toPtr->processed zero)
22 enqueue (queue, toPtr)
23 toPtr->processed = 1
24 arcPtr = arcPtr->nextArc
25 walkPtr = walkPtr->nextVertex
26 destroyQueue(queue)
27 return
end breadthFirst

Copyright © Open University Malaysia (OUM)


TOPIC 10 GRAPHS  189

10.5.2 Depth First Search


What is the idea of depth first search? The idea of depth first search is to proceed
to the next successive levels in a tree. It is similar to a pre-order traversal of an
ordered tree. It will visit all the vertices in the graph vy processing a vertex and its
descendants before processing the adjacent vertex. Vertex v has been visited and
let u 1, u 2, ..., un be the vertices adjacent to v.

Then, we shall next visit u 1 and keep u 2, u 3, ..., uk waiting. After visiting u1, we
traverse all vertices to which it is adjacent, before returning to u 2, u 3, ..., uk.

Depth first search can be implemented using:


(a) Recursive algorithm; or
(b) Stack implementation.

The following Algorithm 2 shows a representation of depth first search as a


recursive algorithm.

Algorithm 2:
Depth first search (using recursive approach)

Algorithm depthFirstSearch
Visit (v)
For all vertices u adjacent to v do
Traverse (u, Visit)

Figure 10.16 illustrates the depth first search  first by visiting the root, v, then u 1,
y 1, y 2, u 2 and u 3.

Figure 10.16: Depth first search

Copyright © Open University Malaysia (OUM)


190  TOPIC 10 GRAPHS

A more detailed and refined outline of pseudocode representing the depth


first search algorithm which uses stack to the traverse the graph, is given in
Algorithm 3 (Gilberg & Forouzan, 1998).

Algorithm 3:
Depth first search (using stack approach)

Algorithm depthFirst (val graph <graphHead pointer>)


Processes the keys of the graph in depth-first order.
Pre : Graph is the pointer to graph head structure
Post : Vertices processed

1 if (empty graph)
2 return
// Set processed flags to not proceed
3 walkPtr = graph->first
4 loop(walkPtr)
5 walkPtr->processed = 0
6 walkPtr = walkPtr->nextVertex
// Process every vertex in the list
7 stack = createStack()
8 walkPtr = graph->first
9 loop (walkPtr not null)
10 if (walkPtr->processed < 2)
11 if (walkPtr->processed < 1)
// Push and set flag to stack
12 pushStack (stack, walkPtr)
13 walkPtr->processed = 1
// Process vertex at stack top
14 loop (not empty stack)
15 vertexPtr = popStack(stack)
16 process(vertexPtr->dataPtr)
17 vertexPtr->processed = 2
/* Push all vertices from adjacent
list */
18 arcWalker = vertexPtr->arc
19 loop(arcWalkPtr not null)
20 vertToPtr = arcWalkPtr->destination
21 if (vertToPtr->processed is 0)
22 pushStack(stack, vertToPtr)
23 vertToPtr->processed = 1
24 arcWalkPtr = arWalkPtr->nextArc
25 walkPtr = walkPtr->nextVertex
26 destroyStack(stack)
27 return
end depthFirst

Copyright © Open University Malaysia (OUM)


TOPIC 10 GRAPHS  191

ACTIVITY 10.1

1. Select the most appropriate term for a graph with numbers labelled
on the edges.

A. Directed graph

B. Simple graph

C. Weighted graph

2. The breadth first search algorithm has been implemented using the
queue data structure. One possible order of visiting the nodes in
Figure 10.17 is:

Figure 10.17: A graph

A. MNOPQR

B. NQMPOR

C. QMNPRO

Copyright © Open University Malaysia (OUM)


192  TOPIC 10 GRAPHS

 Graphs are natural models used to represent a relationship among data objects.

 A graph is a collection of vertices (or nodes) and the connections between them.

 The five types of graph are:

– Simple graph;

– Directed and undirected graph;

– Weighted graph;

– Complete graph; and

– Cycle.

 There are three ways to represent graphs, namely adjacency list, adjacency
matrix and incidence matrix.

 The six basic operations of graph are add vertex, delete vertex, add edge, delete
edge, find vertex and traverse graph.

 Breadth first search processes all the vertices on a certain level, before going to
the next level.

 Depth first search will visit all the vertices in the graph vy processing a vertex
and is descendants before processing the adjacent vertex.

Copyright © Open University Malaysia (OUM)


TOPIC 10 GRAPHS  193

Adjacency list Edge


Adjacency matrix Incidence matrix
Breadth first search Simple graph
Complete graph Traverse
Cycle Undirected graph
Depth first search Vertex
Directed graph Weighted graph

Gilberg, R. F., & Forouzan, B. (1998). Data structures: A pseudocode approach with
C. Boston, MA: PWS.

Copyright © Open University Malaysia (OUM)


MODULE FEEDBACK
MAKLUM BALAS MODUL

If you have any comment or feedback, you are welcome to:

1. E-mail your comment or feedback to [email protected]

OR

2. Fill in the Print Module online evaluation form available on myINSPIRE.

Thank you.

Centre for Instructional Design and Technology


(Pusat Reka Bentuk Pengajaran dan Teknologi )
Tel No.: 03-27732578
Fax No.: 03-26978702

Copyright © Open University Malaysia (OUM)


Copyright © Open University Malaysia (OUM)

You might also like