Top Banner
Table of Contents Course Guide vi - xiii Topic 1 Arrays 1 1.1 Concept of Arrays 1 1.2 One-dimensional Arrays 2 1.2.1 Declaring Arrays 2 1.2.2 Initialising Array Elements 4 1.2.3 Assigning and Accessing Array Elements 6 1.2.4 Operations on Array Elements 10 1.2.5 Arrays and Functions 13 1.2.6 Case Study: Yearly Rainfall Summary 16 1.3 Two-dimensional Arrays 19 1.3.1 Declaring Arrays and Initialising Array Elements 19 1.3.2 Assigning and Accessing Array Elements 21 1.3.3 Arrays and Functions 23 1.3.4 Case Study: Two-dimensional Matrix Operations 23 Summary 26 Key Terms 26 Topic 2 Characters and Strings 27 2.1 Basic Concepts of Characters and Strings 27 2.1.1 Declaring and Initialising String Values 29 2.1.2 String Referencing 30 2.1.3 Input and Output Using Standard Functions: 31 scanf() and printf() 2.2 Standard Character and String Functions 33 2.2.1 Evaluation and Manipulation Functions for 33 Characters 2.2.2 Input and Output Functions for Characters 34 and Strings 2.2.3 Manipulation Functions for Strings 36 2.3 String Arrays 37 2.4 Character and String Applications 39 Summary 41 Key Terms 41
152
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Data Structure

Table of Contents Course Guide vi - xiii Topic 1 Arrays 1

1.1 Concept of Arrays 1 1.2 One-dimensional Arrays 2

1.2.1 Declaring Arrays 2 1.2.2 Initialising Array Elements 4

1.2.3 Assigning and Accessing Array Elements 6 1.2.4 Operations on Array Elements 10 1.2.5 Arrays and Functions 13

1.2.6 Case Study: Yearly Rainfall Summary 16 1.3 Two-dimensional Arrays 19 1.3.1 Declaring Arrays and Initialising Array Elements 19

1.3.2 Assigning and Accessing Array Elements 21 1.3.3 Arrays and Functions 23 1.3.4 Case Study: Two-dimensional Matrix Operations 23

Summary 26 Key Terms 26 Topic 2 Characters and Strings 27 2.1 Basic Concepts of Characters and Strings 27 2.1.1 Declaring and Initialising String Values 29 2.1.2 String Referencing 30 2.1.3 Input and Output Using Standard Functions: 31 scanf() and printf()

2.2 Standard Character and String Functions 33 2.2.1 Evaluation and Manipulation Functions for 33 Characters 2.2.2 Input and Output Functions for Characters 34 and Strings 2.2.3 Manipulation Functions for Strings 36

2.3 String Arrays 37 2.4 Character and String Applications 39 Summary 41 Key Terms 41

Page 2: Data Structure

TABLE OF CONTENTS

iv

Topic 3 Structures 42 3.1 Concepts of Structures 42 3.2 Declaring and Initialising Structure Elements 43 3.3 Referencing Structure Element 46 3.4 Structure Type Arrays 48 3.5 Structure Type Structure 50 3.6 Structures and Functions 52 3.6.1 Return Value Functions 53 3.7 Structure Applications 54 3.8 typedef Construction 56 Summary 57 Key Terms 57

Topic 4 Pointers 58 4.1 Pointer Basics 58

4.2 Parameter Passing Using Pointers 61 4.3 Pointers and Arrays 64 4.3.1 Pointers and Strings 64

4.3.2 Pointer Type Arrays 65 4.4 Dynamic Memory 66

4.5 Pointers and Structures 68 Summary 70 Key Terms 70

Topic 5 Lists and Linked Lists 71 5.1 Lists 72

5.1.1 Basic List Operations 72 5.1.2 Implementations of Lists Using Arrays 73 5.2 Linked Lists 73 5.2.1 Basic Linked List Operations 74 5.2.2 Implementation Using Pointers 75 5.2.3 Application Using Linked Lists 82 Summary 85 Key Terms 85

Page 3: Data Structure

TABLE OF CONTENTS

v

Topic 6 Stacks 86 6.1 Basic Stack Operations 87 6.2 Implementation Using Arrays 88 6.2.1 Declaring Data Structures 89 6.2.2 Creating Stacks 89 6.2.3 Checking Empty Stacks 89 6.2.4 Checking Full Stacks 90 6.2.5 Inserting Items into Stacks 90 6.2.6 Removing Items from Stacks 90 6.2.7 Stack Application: Separating Even and Odd 91 Numbers 6.2.8 Stack Application: Reverse Polish Notation 92 Summary 96 Key Terms 97 Topic 7 Queues 98 7.1 Basic Queue Operations 99 7.2 Implementation of Queue Data Structure 100 7.2.1 Declaring Data Structures 103 7.2.2 Creating Queues 104 7.2.3 Checking Empty Queues 104 7.2.4 Checking Full Queues 104 7.2.5 Inserting Items into Queues 105 7.2.6 Removing Items from Queues 105 7.2.7 Queue Application 106 Summary 109 Key Terms 109

Topic 8 Sorting 110 8.1 Simple Selection Sort 111 8.1.1 Implementation Using Arrays 114 8.1.2 Simple Selection Sort Algorithm Efficiency 114 8.2 Linear Insertion Sort 115 8.2.1 Implementation Using Arrays 117 8.2.2 Linear Insertion Sort Algorithm Efficiency 117 8.3 Quicksort 118 8.3.1 Implementation Using Arrays 123 8.3.2 Quick Sort Algorithm Efficiency 124 8.4 Bubble Sort 124 8.5 Sorting Application 128 Summary 129 Key Terms 130

Page 4: Data Structure

TABLE OF CONTENTS

vi

Topic 9 Searching 131 9.1 Basic Methods of Searching 131 9.1.1 Sequential Search 132 9.1.2 Binary Search 133 9.2 Search Application 136 Summary 138 Key Terms 138 Topic 10 Trees 139 10.1 General Structure of Trees 140 10.2 Binary Trees 141 10.2.1 Data Structure for Binary Tree 141 10.3 Binary Search Trees (BST) 142 10.3.1 Creating BSTs 144 10.3.2 Searching BSTs 144 10.3.3 Inserting Nodes in BSTs 144 10.3.4 Traversing BSTs 150 10.3.5 Deleting Nodes in BSTs 152 10.4 BST Application 155 10.5 Expression Trees 156 Summary 157 Key Terms 158

Page 5: Data Structure

COURSE GUIDE

ix

INTRODUCTION Welcome to the Data Structures course, one of the Courses that is offered by the Faculty of Information Technology and Multimedia Communication, Open University Malaysia.

TO WHOM THIS SUBJECT IS TARGETED This Data Structures subject an extension of the Computer Programming subject. Therefore, you are encouraged to take the Computer Programming subject before attempting this subject. The basis of this subject is structuring various data that is required to ensure that it is suitable for a given application.

STUDY TIME ALLOCATION Based on the OUM standards that require students to allocate 40 study hours of learning for each credit hour, this course therefore requires a total of 120 hours of learning time. An estimated time allocation is as shown in Table 1.

Table 1: Recommended Time Allocation for the Course

Activity Hours

Understanding the course content and preliminary discussions 4

Reading 3 units of text at the rate of 20 hours per unit of text 60

Attending 5 tutorial sessions, 2 hours per session 10

Attending online discussion sessions 15

Completing one assignment, 15 hours per assignment 15

Revision 16

Total 120

Page 6: Data Structure

COURSE GUIDE

x

COURSE OBJECTIVES This subject is an extension of the basic programming subject. A data structure that is suitable with its application will guarantee that a particular system will work efficiently and is easy to maintain. There are many types of data structures that are discussed in this subject. The main objective of this subject is to describe the concept of data structures. At the end of this subject, the student will be able to:

1. Apply a data structure concept that is suitable for its application, and

2. Analyse the efficiency of an application based on the structuring of its data.

COURSE SYNOPSIS Unit 1: Basic Data Structures This unit introduces the basic data structures in the C programming language. Topic 1 discusses about arrays, which is a method of representing a group of the same type of data. Topic 2 then discusses about strings that can be represented as an array of characters. In Topic 3, you will be introduced to structures that can represent a group of different types of data. In Topic 4, data pointer types are introduced. This topic elaborates on the connection of pointers and arrays. The information in Topic 4 is very important because this concept will be utilised in Unit 2.

Unit 2: Advanced Data Structures Unit two discusses several data structures that have been modelled as lists, like the linked lists, stacks and queues. All these three techniques of storing data have their own unique strengths in ensuring the production of a more efficient system. All this is described in Topic 5, Topic 6, and Topic 7 of this units.

Unit 3: Sorting, Searching, and Trees This unit introduces three more applications of data structures. Topic 8 discusses three types of sorting and algorithms. Topic 9 explains the concept of searching while Topic 10 discusses the concept of trees.

Page 7: Data Structure

COURSE GUIDE

xi

Advice to Students: Please attempt all the programming exercises in this module to ensure that you become competent in this subject.

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

BASIC KNOWLEDGE Students of this course need to have the basic knowledge in the C programming language.

READING MATERIALS There are many books available in the market that discusses about computer programming using the C language. A list of books that has been recommended is stated in the text unit. However, the main reference book for this course is „Bahasa Pengaturcaraan C, Edisi Revisi 2000‰ by Marini Abu Bakar, Norleyza Jailani & Sufian Idris, Prentice Hall, 2000.

EVALUATION METHOD Assignment: 45% Online Participation: 5% Final Examination: 50% TOTAL: 100% Examples of the examination questions can be obtained from the OUM website.

Page 8: Data Structure

INTRODUCTION

Topic 1 is the most important topic as the basics of data structuring. Data structuring is a topic that discusses how data that is obtained from the user will be stored in the computer memory. Therefore, in this topic we shall be introduced to one of the simplest data structures, i.e the array. This topic will discuss the concept of arrays, one-dimensional arrays and two-dimensional arrays, and how to use them in programming. Therefore, are you ready? If so, then let us proceed to explore all that is related to arrays.

CONCEPT OF ARRAYS

Do you still remember variables? Can you compare the concept of variables and arrays?

1.1

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

1. Declare and perform manipulations on one-dimensional arrays and two-dimensional arrays;

2. Solve programming problems using one-dimensional arrays and two-dimensional arrays; and

3. Solve programming problems using arrays that involve functions.

LEARNING OUTCOMES

TTooppiicc 11 Arrays

Arrays are data structures that contain data items of the same type. Arrays also contain static data. This means that the size of the array is fixed from the declaration all the way to the final program implementation.

Page 9: Data Structure

TOPIC 1 ARRAYS 2

Why do we need arrays in our programming? This question can be answered by giving an example. LetÊs say that you would like to keep a record of your personal spending for the year 2002. You can file all your receipts and details of expenditure in multiple files according to the month. This means that you have 12 different files. However, wouldnÊt it be easier if you could manage a single file with 12 compartments? Let us relate this scenario to computer programming. LetÊs 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 our program by using an array that has 12 elements, that is, by storing the monthly total spending in each of the array elements.

ONE-DIMENSIONAL ARRAYS

A one-dimensional array is an array that has only one index or subscript. An index is a value that is written in the brackets [ ] after an array name. An index can identify the number of elements in an array. This is explained in the following section.

1.2.1 Declaring Arrays

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 one-dimensional arrays as follows:

data_type array_name[number_of_elements];

which: data_type - type of data that will be stored in the array array_name - the name of the array number_of_elements - a positive integer that indicates how many

elements should be stored in memory 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.

1.2

Page 10: Data Structure

TOPIC 1 ARRAYS ! 3

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

int number[10];

The above 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 that can be referred 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. Observe the illustration in the following 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 the array index or subscript. The array index always begins with 0 and ends with the size of the array subtracted by 1. In the above 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]. The array size must be an integer and consists of an expression and the expression is evaluated to determine the subscript. If a program uses an expression as an index or subscript, then the expression is evaluated to determine the subscript. For example, if a = 5 and b=6, then the statement:

c[a+b] = 3; Arrays may be declared to contain other data types. For example, an array of type char can be used to store a character string.

Page 11: Data Structure

TOPIC 1 ARRAYS 4

To enhance your understanding in the subject, do the following exercise.

1.2.2 Initialising Array Elements As for normal variables, we can also set the initial values for each array element during declaration. See Figure 1.2.

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

Array with Initial Values

Figure 1.2: Array initialisation and memory location illustration

Declare a suitable array for each of the following: (a) An array for 30 real numbers

(b) An array for a sequence of 126 characters

EXERCISE 1.1

Draw a memory location as reference for each element of the arrays that are declared as follows: char text[80]; /*character array of size 80*/ int marks[100]; /*integer array of size 100*/ float high[5]; /*real number array of size 5*/

What can you conclude from the illustration of the above arrays? How about the float high[5.5];?

ACTIVITY 1.1

Page 12: Data Structure

TOPIC 1 ARRAYS ! 5

All the array elements that are not given initial values will be set with the value of 0 automatically. See the following example:

int digit1[10] = {1, 2, 3};

The result is the digit1 array will have the following sequential values: Array without Full Initial Values

Figure 1.3: Partial initialisation of elements and memory location illustration

Another easy way of declaring 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 digit2 array is 5, based on the number of elements in the initial value list.

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

In order to ensure that you understand what has been taught, answer the following questions.

Write a suitable array declaration for each of the following:

(a) Declare a one-dimensional integer array of size 12 that is called odd. Assign the values 1, 3, 5, 6, ..., 23 to the elements of that array.

(b) Declare a one-dimensional real number array of size 6 that is called constant. Assign the following values to the array elements:

0.02, -0.45, 5.77, -2.55, 7.50, -5

EXERCISE 1.2

Draw a diagram that illustrates the memory location for thedeclaration of the digit2 array.

ACTIVITY 1.2

Page 13: Data Structure

TOPIC 1 ARRAYS 6

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 element in an array. For example, we shall 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], 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.

Figure 1.4: Memory element 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. In this example, we declared the digit array without initial values. Each 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.

int month[10]; /* declare month array of size 10 */

month[0] = 7; /* assign 7 to the first element */

month[1] = 5; /* assign 5 to the second element */

month[2] = 3; /* assign 3 to the third element */

Page 14: Data Structure

TOPIC 1 ARRAYS ! 7

Can you note down the values that are assigned based on

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

month[3] = ?

month[4] = ?

:

month[9] = ?

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 like 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:

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

X[0] = 2; /* assign 2 to X[0] */

X[1] = 3 + 4; /* assign (3 + 4)expression to X[1] */

X[2] = 5 * 6; /* assign (5 *6) expression to X[2] */

The expression on the right of the assignment statement can also contain elements of the same array. Look at the following example. The values that are assigned in these assignment statements are explained in Figure 1.5. 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] */

Page 15: Data Structure

TOPIC 1 ARRAYS 8

Figure 1.5: Example of assignment statements that involve Y array elements

Array elements do not necessarily have to be constant values. We can also useint type expressions 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. Example:

int a = 0;

X[a] = 5;

In this example, x[a] <==> x[0] because a=0 We can assign data from keyboard that data depend on the user key in. The program code shows how to input data from keyboard. The program must use loop. Example input data are 34, 25, 26, 45 and 48.

Page 16: Data Structure

TOPIC 1 ARRAYS ! 9

Program 1.1 /*This program was developed to input 5 integer numbers and print the average of the numbers.*/

#include <stdio.h> void main(void) { int x[5], total, i; for(i = 0; i < 5; i++){ printf(“x[%d] = “, i); scanf(“%d”, &(x[i])); total += x[i]; } printf(“Average = %f\n”, total/5); }

Output:

Average = 35.6

Think about the assignment given below. Look at the comments as aguide. Based on your understanding in the examples before this 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]*/

SELF CHECK 1.1

Page 17: Data Structure

TOPIC 1 ARRAYS 10

In order to ensure that you understand what has been taught, answer the following questions.

1.2.4 Operations on Array Elements

In C, we cannot implement an operation for the whole array. This means that, ifa 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. The program code shows how to copy the contents of array A to array B.

1. Referring to the arrays that are declared below, state the values that are assigned to each following 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};

2. 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;

EXERCISE 1.3

There are many operations that can be performed on array elements.One of the examples is the addition operation. Visit the websitehttp://www.phanderson.com/c/arraysum/html to see the techniques that are presented.

ACTIVITY 1.3

Page 18: Data Structure

TOPIC 1 ARRAYS ! 11

Program 1.2

/* copy the contents of array A to array B */

#include <stdio.h>

#define SIZE 5

void main(void) {

int A[SIZE] = {2, 4, 6, 8, 10};

int i;

int B[SIZE];

/* copy one by one each array element in A to array B */

for (i = 0; i < SIZE; i++) {

B[i] = A[i];

}

/* print both arrays */

for (i = 0; i < SIZE; i++) {

printf(“A[%d] = %d, B[%d] = %d\n”, i, A[i], i, B[i]);

}

}

Program 1.3

#include <stdio.h> #define N 10

main(){

int a[2]; float b[N];

a[0] = 11; a[1] = 22;

b[3] = 777.7 b[6] = 888.8;

printf(“a[0] = %3d, a[1] = %3d\n”, a[0], a[1]); printf(“b[3] = %8.1f, b[6] = %8.2f \n”, b[3], b[6]);

}

Using a constant to size arrays is good programming practice.

Arrays declarations. The value enclosed in brackets indicates the total number of array elements for which space is to be reserved.

These statements fill all of the elements of the a[] array.

Page 19: Data Structure

TOPIC 1 ARRAYS 12

Reading two array elements.

Using a loop to fill all of the elements of the y[] array.

Program 1.4

#include <stdio.h> main()

{ int a[3] = {11, 12}, b[ ] = {44, 55, 66}, i; float x[2], y[4];

printf(“Please enter two real numbers\n”); scanf(“%f %f”, &x[ 0 ], &x[1]);

printf(“x[0] = %.1f x[1] = %.1f\n\n”, x[0], x[1]);

for (i=0; i<4; i++) { y[ i ] = i*100.0; printf(“y[%1d] = %.2f\n”, i, y[i]); }

return 0; }

Do the following exercise to help you in your understanding.

This initialise the first two elements of the a[] array. All other elements are then automatically set to zero.

Because no array size is given (the brackets are empty) and three values are given in braces, the array is automatically declared to have a size of three with the values shown being the initial element values.

Follow Program 1.2, 1.3 and 1.4. What are the output for theprograms above?

SELF CHECK 1.2

Page 20: Data Structure

TOPIC 1 ARRAYS ! 13

1.2.5 Arrays and Functions

In the previous Computer Programming Module, we discussed about functions. With the construction of functions, our program code is more modular. We can also use this concept of arrays with functions. We can pass the entire array to a function as a parameter. The way that an array is passed to a function is quite different from the way other types of data are passed. In order to pass an array element to a function, we need to state the array name only (without any bracket symbols or index numbers) as a function parameter. In the definition of the function, the name of the array must be written in brackets, but without stating the size of the array.

1. Write a program that can read 5 integer values into an array and then find the total for that array.

2. What is the output for the following program:

#include <stdio.h>

void main() {

int M[6] = {2, 5, 7, -7, -5, -2};

int N[6], i;

N[0] = M[0];

for (i = 1; i < 6; i++)

N[i] = M[i] + N[i-1];

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

printf(“N[%d] = %d\n”, i, N[i]);

}

EXERCISE 1.4

Visit http://www.phanderson.com/c/arraysum.html again. Thistime, examine how functions are used with arrays. Modify all theprogram code if functions are not used. Will the answers still be the same?

ACTIVITY 1.4

Page 21: Data Structure

TOPIC 1 ARRAYS 14

Look at the simple example. Program 1.5

#include <stdio.h> void modifyHours(int [], int); /*function definition*/

main(){int WorkingHours[24]; : modifyHours(WorkingHours, 24);/*function call*/ }

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

An individual element in an array can be passed call by value

To pass an element of an array to a function, use the subscripted name of the array element as an argument in the function call

Look at the following example. We input 10 integer values and store them in an array. Then, we would like to sort the contents of the array in an ascending order. The sorting operation is performed by the function numberSort(). Then, we print the contents of the array. Program 1.6

/* Read 10 integer values and sort the numbers using numberSort()

*/

#include <stdio.h>

void numberSort (int []); /* function prototype */

void main(void) {

int number[10];

int i;

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

scanf(“%d”, &(number[i]));

numberSort(number) /* function call */

printf(“Values have been sorted\n”);

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

printf(“%d”, &(number[i]));

}

Page 22: Data Structure

TOPIC 1 ARRAYS ! 15

void numberSort(int num[]) { /* function definition */

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;

}

}

}

} /* end of function */

Look at the way we write the function prototype, function call, and the definition of the function numberSort().

1. Modify the solution to Question 1 in Exercise 1.4, but this time use a function. Other than the main() function, write three other functions to solve the problem i.e a function to read values, a function to find the total of element values, and a function to print values.

2. Write a program that can read a group of data that represents daily temperatures in an area in Kuala Lumpur for the month of November 2001. Your program should produce the following output:

(a) The number of days that is hot (temperatures greater than 85F), moderate (temperatures between 60 and 85F) and cold (temperatures less than 60F).

(b) The average temperature for that month.

(c) The number of days that have temperatures greater than the average.

EXERCISE 1.5

Please refer to the detailed explanation for similar program code inthe reference Bahasa Pengaturcaraan C, 2000 Revised Edition, that is Program 11.3.

ACTIVITY 1.5

Page 23: Data Structure

TOPIC 1 ARRAYS 16

1.2.6 Case Study: Yearly Rainfall Summary

Problem Statement You are given a table that shows the total distribution of monthly rainfall for 2001 for an area in Kuala Lumpur.

Month Jan Feb Mac Apr May June July Aug Sep Oct Nov Dec

Total

Rainfall 190 195 268 307 235 144 105 193 215 223 235 208

Based on the given information, you are required to write a program that can produce the following summary:

(a) Total yearly rainfall

(b) Average rainfall for 2001

(c) Wettest month

(d) Driest month Data Design

Input: rainfallDistribution[12] : integer type array

Output:

totalRainfall : Integer type averageRainfall : Real type wettestMonth : Integer type

driestMonth : Integer type Solution Design The structural chart for this program is as follows in Figure 1.6.

Page 24: Data Structure

TOPIC 1 ARRAYS ! 17

Figure 1.6: Structural chart for the yearly rainfall summary problem

Implementation

The following is the program solution. Program 1.7 /* Yearly Rainfall Summary Program */

#include <stdio.h>

#define N 12

void readRainDistribution(int []);

int calculateTotalRain(int []);

float calculateAverageRainfall(int);

int confirmWettestMonth(int []);

int confirmDriestMonth(int []);

void printReport(int, float, int, int);

void main() {

int rain[N], tot, max, wet, dry;

float average;

readRainDistribution(rain);

tot = calculateTotalRain(rain);

average = calculateAverageRainfall(rain);

wet = confirmWettestMonth(rain);

dry = confirmDriestMonth(rain);

printReport(tot, average, wet, dry);

}

Page 25: Data Structure

TOPIC 1 ARRAYS 18

void readRainDistribution(int rain[]) {

int i;

printf(“enter the total monthly rainfall distribution \n”);

for (i = 0; i < N; i++) {

printf(“month %d : “, i+1);

scanf(“%d”, &rain[i]);

}

}

int calculateTotalRain(int rain[]) {

int i, tot=0;

for (i = 0; i < N; i++) {

tot = tot +rain[i];

}

return tot;

}

float calculateAverageRainfall(int total) {

float average;

average = (float) total / N;

return average;

}

int confirmWettestMonth(int rain[]) {

int i, max;

max = 0;

for (i = 1; i < N-1; i++) {

if (rain[i] > rain[max]) {

max = i;

}

}

return max;

}

int confirmDriestMonth(int rain[]);

{

int i, min;

min=0;

for (i = 1; i <= N; i+t) {

if (rain[i] < rain[min]) ;

} min = i;

return min;

}

void printMonthName(int i) {

switch (i) {

case 1: printf(“January”); break;

case 2: printf(“February”); break;

case 3: printf(“March”); break;

case 4: printf(“April”); break;

case 5: printf(“May”); break;

Page 26: Data Structure

TOPIC 1 ARRAYS ! 19

case 6: printf(“June”); break;

case 7: printf(“July”); break;

case 8: printf(“August”); break;

case 9: printf(“September”); break;

case 10: printf(“October”); break;

case 11: printf(“November”); break;

case 12: printf(“December”); break;

}

printf(“\n”);

}

void printReport(int tot, float ave, int wet, int dry) {

printf (“Total Rainfall %d\n”, tot);

printf (“Average Rainfall %3.2f\n”, ave);

printf (“The wettest Month is”);

printMonthName(wet);

printf (“The driest Month is”);

printMonthName(dry);

}

TWO-DIMENSIONAL ARRAYS

Two-dimensional arrays can be regarded as a two-dimensional matrix that has rows and columns.

1.3.1 Declaring Arrays and Initialising Array 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

The [ ] [ ] (brackets) identify the two dimensional array and the enclosed numbers indicate the number of rows and column.

1.3

Page 27: Data Structure

TOPIC 1 ARRAYS 20

For example, the statement: int table [3] [4];

declares an integer type two-dimensional that consist of three rows and four columns. The compiler creates the array table, which reserve memory space for twelve integer type elements. 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][100];

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

Figure 1.7: 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 student, as shown in Figure 1.7 above. 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}};

Page 28: Data Structure

TOPIC 1 ARRAYS ! 21

The element contents of the square array can be illustrated as shown in the following Figure 1.8:

Figure 1.8: Memory cell content for the declared square array

In order to ensure that you understand what has been taught, answer the following questions.

1.3.2 Assigning and Accessing Array Elements

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

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

EXERCISE 1.6

„Array From the Twilight Zone‰ in the websitehttp://home.twcny.rr.com/amanthoan/cweb/dimary.html. Look atthe example of two-dimensional array used.

ACTIVITY 1.6

Page 29: Data Structure

TOPIC 1 ARRAYS 22

int square[4][4];

int i,j;

for (i = 0; i < 4; i++) /* loop i */

for (j = 0; j < 4; J++) /* loop j */

scanf(“%d”, &(square[i][j]));

In order to help you in your understanding, answer the following exercises.

1. Regarding the arrays that are declared below, 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}};

2. Write a program segment that declares a two-dimensional array with 4 rows and 5 columns and assign each array element with the value -1 (Note: use loops for the assignment operation).

EXERCISE 1.7

Try and predict the output if the above program segment is changed in the following way:

for(i = 0; i < 4; i++) { /* loop i */

for(j = 0; j < 4; j++) /* loop j */

} scanf(“%d”, &(square[i][j]));

SELF CHECK 1.3

Look Table 11.2 that explains that program segment that is similar to the one above, in the reference book, Bahasa Pengaturcaraan C, 2000 Revised Edition

ACTIVITY 1.7

Page 30: Data Structure

TOPIC 1 ARRAYS ! 23

1.3.3 Arrays and Functions

Passing two-dimensional arrays to a function is by referencing, which is the same as passing a one-dimensional array to a function. Only the name of the array need to be stated in the function invocation. Observe the following program.

void main(){

int rain[5][12];

read5YearRainfallDistribution(rain);

}

void read5YearRainfallDistribution(int rain[][12]) {

int i, j, yr;

for (i = 0; i < 5; i++) {

yr = 1997 + i;

printf(“enter total rain distribution for year %d\n”,

yr);

for (j = 0; j < 12; j++) {

printf(“month %d :”, j+1);

scanf(“%d”, &rain[i][j]);

}

}

}

1.3.4 Case Study: Two-dimensional Matrix Operations

Problem Statement Assume that you would like to find the result of addition of two two-dimensional matrices where:

c[i][j] = a[i][j] + b[i][j]

and then print the result that is produced. Data Design Input: a[][], b[][] : two-dimensional integer matrix Output:

c[][] : two-dimensional integer matrix that represents the addition

Page 31: Data Structure

TOPIC 1 ARRAYS 24

Solution Design The structural chart for this program is as shown in Figure 1.9:

Figure 1.9: Structural chart for the two-dimensional matrix operation problem

Implementation Below is the solution program. Program 1.4 /* Two-dimensional Matrix Operation Program */

#include <stdio.h>

#define MAXRow 10

#define MAXColumn 10

void readMatrix(int x[] [MAXColumn], int, int);

void calculateAddition(int a[] [MAXColumn], int b[][MAXColumn],

int c[][MAXColumn], int, int);

void printMatrix(int x[][MAXColumn], int, int);

void main() {

int row, column;

int a [MAXRow] [MAXColumn], b [MAXRow] [MAXColumn],

c [MAXRow] [MAXColumn];

printf(“Input number of rows”);

scanf(“%d”, &row);

printf(“Input number of columns”);

scanf(“%d”, &column);

Page 32: Data Structure

TOPIC 1 ARRAYS ! 25

printf(“\n\nInput Matrix A\n”);

readMatrix(a, row, column);

printf(“\n\nInput Matrix B\n”);

readMatrix(b, row, column);

calculateAddition(a, b, c, row, column);

printf(“Addition of A and B is\n”);

printMatrix(c, row, column);

}

void readMatrix(int x[][MAXColumn], int row, int column){

int i,j;

for (i = 0; i < row; i++) {

printf (“Enter data for row %d \n”, i+1);

for (j = 0; j < column; j++)

scanf(“%d”, &x[i][j]);

}

}

void calculateAddition(int a[][MAXColumn], int b[][MAXColumn],

int c[][MACColumn], int row, int column) {

int i,j;

for (i = 0; i < row; i++) {

for (j = 0; j < column; j++)

c[i][j] = a[i][j] + b[i][j];

}

}

void printMatrix(int x[][MAXColumn], int row, int column) {

int i, j;

for (i = 0; i < row; i++) {

for (j = 0; j < column; j++)

printf(“%4d”, x[i][j]);

printf(“\n”);

}

}

Page 33: Data Structure

TOPIC 1 ARRAYS 26

An array is a data structure:

(i) That consists of data items that are related

(ii) That is of the same type

(iii) That is of one or more dimension Also in this topic, methods for declaring, initialising values, sorting, and

searching one and two-dimensional array elements has been described. Subsequent to this, the topic also discussed about the relationship between

arrays and functions as well as the techniques for using them. Besides that, 2 case studies that related are to one or two-dimensional arrays are also provided for the students.

One-dimensional Arrays Two-dimensional Arrays

Page 34: Data Structure

INTRODUCTION

In this topic, we will discuss about characters and strings. A character is a basic data type in C, while a strings is represented as a type array of characters. Therefore, the information about arrays in the previous topic is required. This topic is a continuation of the previous topic on arrays. This topic also introduces the standard libraries for characters and strings that will enable us to write codes that handles characters and strings.

BASIC CONCEPTS OF CHARACTERS AND STRINGS

In your opinion, why do we need strings since we already have characters? We have already seen in the previous Computer Programming Module that a character is a type of simple data provided in C that can be declared as type

2.1

TTooppiicc 22 Characters and Strings

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

1. Use functions to manipulate characters in ctype.h library in writing your program;

2. Use functions containing input and output characters and strings (in the stdio.h standard library) in writing your program; and

3. Use string creation functions (in stdlib.h library) as well as string manipulation functions (in the string.h library) in writing your program.

LEARNING OUTCOMES

Page 35: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

28

char. Characters can consist of a single letter, digit or even special symbol. Each character constant is bounded by single quotation marks  Ê. Before we go further into this topic, it is better if we find out more about the string. A string is the combination of one or more characters. In C, a string does not have its own type definition. In order to declare strings, we need to use a character array. Each character in a string is stored as an element in an array. In manipulating the characters, we need to perform operations on each character individually. However, in solving certain types of problems, a string needs to be manipulated as a whole. In order to do this, we usually use a function in a specific standard library. String constants are bounded by double quotation marks „ ‰. You should include a „mark in front and a‰ mark at the end of the string constant. The following are examples of string constants: “Open University Malaysia” “03-89251000” Strings are character arrays that are ended with a null character (‘\0’). See Figure 2.1 that shows the „computer‰ string.

‘c’ ‘o’ ‘m’ ‘p’ ‘u’ ‘t’ ‘e’ ‘r’ ‘\o’

Figure 2.1: Representation of “computer” string In order to help you understand this topic further, answer the following questions:

State whether each of the following is a valid array constant or string constant. If it is not valid, then give reasons as to why.

(a) ‘%’ (b) “%”

(c) ABC (d) ‘abc’

(e) ‘/n’ (f) “Enter value :

EXERCISE 2.1

Page 36: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

29

2.1.1 Declaring and Initialising String Values

Is the string declaration and initialisation values that are the same as the integer or float array? Strings are declared as character array like in the following example:

char word[10]; In this declaration, the word is a string that can store 9 characters as well as the null ‘\0’ that represents the end character of the array. Declaring a string is the same as initialising array values, for example:

char animal[] = “cat”;

that can also be written as:

char animal[] = {‘c’, ‘a’, ‘t’, ‘\0’};

When a string is declared without stating the array size, space is automatically reserved based on the size of the array plus an extra space for character ‘\0’. In the above example, the size of the array is 4.

Draw the memory space for the assignment:

char animal[] = {‘c’, ‘a’, ‘t’, ‘\0’};

SELF-CHECK 2.1

Page 37: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

30

Answer the following exercise to test your understanding.

2.1.2 String Referencing

When declaring and initialising strings, we can also state the string length (which is the size of the array) of that string. Look at the following example:

char city[20] = “Bandar Baru Bangi”; city is declared as an array that has 20 spaces that are assigned with the string “Bandar Baru Bangi”. Since a string is also a character array, each character in the string can also be referred just like how we would refer other array elements like in Figure 2.2 below:

Figure 2.2: Representation of city string

1. Below is a declaration of character arrays. State the value that is

assigned to each array element.

(a) char status[6] = {‘T’, ‘R’, ‘U’, ‘E’};

(b) char status[6] = “TRUE”;

(c) char status[6] = “FALSE”; 2. Write a suitable declaration for each of the following:

(a) Declare direction as a character array. Assign the value “NORTH” to the array elements.

(b) Declare ipt as a character array of size 6. Assign characters ‘O’, ‘U’, and ‘M’ to that array elements.

EXERCISE 2.2

Page 38: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

31

Answer the following exercise to test your understanding.

2.1.3 Input and Output Using Standard Functions: scanf( ) and printf( )

As was learned in the module „Computer Programming‰ previously, character input and output using functions scanf() and printf() is by using the %c specification. Look at the following example:

char chr; scanf(“%c”, &chr); /* character input */ printf(“%c”, chr); /* character output */

For the input and output of strings, we use the specification as shown in the following:

char animal[10]; scanf(“%s”, animal); /* string input */ printf(“%s”, animal); /* string output */

The string that is input is assigned to animal. The function scanf() will read the string until a space, new line or end-of-file character (eof) is encountered. This means that we cannot input a string that has space characters like “sea horse” using the function scanf(). To do this, we need to use the function gets( ) that will be discussed in the next section. Please observe that the input string cannot be more than 9 in length and it is the same as the number of characters that was declared (reserving space for the null character ‘\0’).

Look at the programming segment below. What is the output?

int i; char text[] = “C programming is very

interesting”; i = 0; while (text[i] != ‘\0’ {

if ((i % 2) == 0) printf(“%c%c”, text[i], text [i]); i++;

}

EXERCISE 2.3

Page 39: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

32

To ensure that you understand what has been studied, answer the following questions

Observe the following program.

#include <stdio.h> void main() { char word[10]; int i, value;

printf(“enter a word: “); scanf(“%s”, word);

i = 0; value = 0;

while (word[i] != ‘\0’) { if ((word[i] >= ‘a’) && (word[i] <=‘z’)) {

value += word[i] – ‘a’ +1; i++; } } printf(“The value for %s is %d\n”, word,value); }

What is the output if the input is: (a) xyz

(b) oum

EXERCISE 2.4

In order to get a deeper understanding, please review Program 12.1in the reference book Bahasa Pengaturcaraan C, 2000 RevisedEdition.

ACTIVITY 2.1

Page 40: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

33

STANDARD CHARACTER AND STRING FUNTIONS

In this section, we shall look at several standard functions in the C library that are related with the evaluation and manipulation of characters and strings.

2.2.1 Evaluation and Manipulation Functions for Characters

The C library has several functions that are useful for testing and manipulating characters and strings in the ctype.h library. Among them are listed in Table 2.1 as follows:

Table 2.1: File Manipulation Functions for ctype.h Library

Function Prototype Function Description

int isdigit (int c) Returns the true value, if c is a digit and false (0) if otherwise

int isalpha (int c) Returns the true value, if c is a letter and false (0) if otherwise

int islower (int c) Returns the true value, if c is a lowercase letter and false (0) if otherwise

int isupper (int c) Returns the true value, if c is an uppercase letter and false (0) if otherwise

int tolower (int c) If c is an uppercase letter, tolower() will return its corresponding lowercase letter. If otherwise, tolower() will return the character without any changes.

int toupper (int c) If c is a lowercase letter, toupper() will return its corresponding uppercase letter. If otherwise, toupper() will return the character without any changes.

To help you understand the use of library functions, you can refer to Program 2.1. This program reads an input word and changes the case of each character in that word, which means that lowercase letters are changed to uppercase letters while uppercase letters are changed to lowercase letters.

2.2

Page 41: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

34

Program 2.1 /* Read a word and change the letter case */ #include <stdio.h> #include <ctype.h> void main (void) {

char word[20], newWord[20]; int i = 0;

printf(“Enter a word “); scanf(“%s”, word);

while (word[i] != ‘\0’) { if (islower(word[i]))/* test for lowercase letter */ newWord[i] = toupper(word[i]); else if (isupper(word[i]))/* test for uppercase letter */

newWord[i] = tolower(word[i]); i++; }

newWord[i] = ‘\0’; /* end character of string */ printf(“The word %s is case inverted to: %s\n”, word, newWord); } Look at the while loop in Program 2.1 where it contains the function islower() to test whether a character is a lowercase letter. If that test is true, then the program will change that character to an uppercase letter by using the toupper() function. This uppercase letter is assigned to the newWord array. If the islower() test returns false, then the program will use the isupper( ) function to test whether the character is uppercase, and if true, it will change the character to lowercase by using the tolower() function before it is copied into the newWord array. This process is repeated until the end of the string is met.

2.2.2 Input and Output Functions for Characters and Strings

The stdlib.h library provides several input and output functions that are more effective than scanf() and printf(). You may recall that presently, we can only input a text that does not contain any space, end of line, and end of file characters. Table 2.2 lists several input and output functions for characters and strings.

Page 42: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

35

Table 2.2: Input and Output Functions for Characters and Strings in the stdlib.h Library

Function Prototype Function Description

int getchar (); Inputs the following character from the standard input device and returns the character as a value.

int putchar (int c); Prints the c character to the standard output device.

char *gets (char str); Inputs a string from the standard input device and stores it in str until the ‘\n’ or <eof> character is found. The ‘\0’ character is added to the end of the str string.

int puts (char *str); Prints the str string to the standard output device.

int fflush (FILE *file); Empties the file buffer.

Normally, when a character or a string is input through the keyboard, there is an extra character (like ‘\n’) that still exists in the buffer. If this character is not removed, the following reading process will read that character and not the input data. In order to empty the buffer before the following input, we use the function fflush(stdin). stdin means the standard input device, which is usually the keyboard.

To ensure that you understand this topic, answer the following questions:

Write a program that reads a single line of text. Then change all space characters (‘‘) to the character ‘*’, character ‘.’ and character ‘,’ to character Â:Ê, digit characters to character Â#Ê. Show the resulting output string.

EXERCISE 2.5

Refer to Program 12.3 from the book Bahasa Pengaturcaraan C, 2000 Revised Edition for an example of the application of the abovestandard functions.

ACTIVITY 2.2

Page 43: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

36

2.2.3 Manipulation Functions for Strings

String manipulation functions are made available in the string.h library, among them are for copying strings, finding the length of a string, and comparing strings. The following is a list of string manipulation functions. char *strcopy(char s1[], char s2[]); Copies s2 string to s1 string and

returns the value of s1.

size_t strlen(char s1[]); Returns the number of characters in s1 string.

char *strcat(char s1, char s2); Copies s2 string on the end of s1 string.

int strcmp(char s1, char s2); Compares s1 and s2 strings lexicographically. This function returns the value 0, less that 0, and greater than 0 when s1 is the same, less than or greater than s2, respectively.

char *strtok(char *s1, char *s2); Generates tokens in s1 string. A token is a logical string (like a word) in a single line of text that is separated by the s2 string. The first call needs to forward s1 as the first parameter. In order to get the next token, we need to forward NULL in the first parameter.

Answer the following to test your understanding.

Write a program that can input two strings and then use the function strcmp() to test those strings. Your program should give an output to indicate whether the first string is less than, the same, or greater than the second string.

EXERCISE 2.6

Page 44: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

37

STRING ARRAYS

What is the difference between strings and string arrays, since the string itself is an array? Many applications require us to create an array of type string. Since a string is an array, thus a string array is actually a two-dimensional character array where each array line is a single string. Look at the example below:

#define NO_STUDENTS 50 #define NAME_LENGTH 30 char studentName[NO_STUDENTS][NAME_LENGTH];

studentName is a string array that contains 50 strings which represent the name of students. Each of these strings can contain a maximum of 30 characters. Figure 2.3 below shows the memory space that is reserved for studentName.

Figure 2.3: Memory space for the definition of studentName

We can also assign values to a string array. Look at the following example:

char day[7][10] = {“Monday”,“Tuesday”,“Wednesday”,“Thursday”, “Friday”,“Saturday”, “Sunday”};

The memory space that is reserved for the above declaration is as follows in Figure 2.4.

2.3

Page 45: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

38

Figure 2.4: Memory space for the declaration of day

For the input operation of string arrays, we can use the %s specification for the printf() and scanf() functions. Look at the following program segment.

#define NO_STUDENTS 50 #define NAME_LENGTH 30

char studentName[NO_STUDENT][NAME_LENGTH]; int i;

for (i = 0; i < NO_STUDENTS; i++) { printf(“Enter student name “); scanf(“%s”, studentName[i]);

} for (i = 0; i < NO_STUDENTS; i++) { printf(“%s”, studentName[i]);

}

Passing string arrays to a function is the same as forwarding two-dimensional arrays to a function. Refer back to Topic 1, Section 1.3.3.

As an additional exercise, look at Program 12.4 from the bookBahasa Pengaturcaraan C, 2000 Revised Edition.

ACTIVITY 2.3

Page 46: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

39

Answer the following exercise to test your understanding.

CHARACTER AND STRING APPLICATIONS

Problem Statement You are given two string codes as follows:

char code1[] = “JMARTYVWBDLQNCXGZEKIPUFOHS”; char code2[] = “abcdefghijklmnopqrstuvwxyz”;

Your program needs to read a line of text and then encode the text as a secret or encrypted text. The encoding of the text is based on:

• For each upper-case or capital letter, your program should identify the index of that letter in code1, and refer to the character at the same position index in code2 as its secret code.

• Conversely, for each lower-case or small letter, the letter index is identified in the code2 string. Based on this index, the secret code is the character at that particular index in code1.

2.4

1. Write a program that can input 10 strings that are assigned to a

string array. For each string, do the following:

(a) Change the first character and last character to capital letters.

(b) Change all vowel characters to the Â*Ê character.

Then print out the modified strings.

2. You are required to write a program that is able to input 20 strings that are assigned to a string array. For each string, you should count the number of vowel characters (which are ÂaÊ, ÂeÊ, ÂiÊ, ÂoÊ, and ÂuÊ, including capital vowel letters)

Then you need to calculate the percentage of each vowel in the overall string and print out the percentage value.

EXERCISE 2.7

Page 47: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

40

Implementation The following is the solution program. Program 2.2 /* Read a single input and identify the abbreviated name */ #include <stdio.h> #include <ctype.h> int checkIndex(char); char code1[] = “JMARTYVWBDLQNCXGZEKIPUFOHS”; char code2[] = “abcdefghijklmnopqrstuvwxyz”; void main (void) { char text[80], secret[80]; int i, gdn, index; printf(“Enter a line of text: “); gets(text); gdn = strlen(text); for (i = 0; i < gdn; i++) {

if (isupper(text[i]) { index = checkIndex(text[i]); secret[i] = code2[index];

} else if (islower(text[i])) {

index = (int) text[i] – (int)(‘a’); secret[i] = code1[index];

} } secret[gdn] = ‘\0’; printf(“The secret text is: %s\n”, secret);

} int checkIndex(char c) { int i; for (i = 0; i < strlen(code1); i++) {

if (c == code1[i]) return i;

} }

Page 48: Data Structure

TOPIC 2 CHARACTERS AND STRINGS

41

• In programming, data is not limited to numerical data only. We often need to

manipulate data in the form characters and strings.

• In this topic, we have looked at the basic characters and strings, and also how to manipulate strings using two methods.

• The first method is by directly manipulating the character array. While the second method is by using the standard functions that is provided by ctype.h, stdlib.h, and string.h libraries.

Characters Strings

String Arrays

Page 49: Data Structure

INTRODUCTION

In Topic 1, we learned about arrays. If you recall, arrays are data structures that have all elements of the same type of data. In this topic, we shift our focus to structures that is a group of data. The elements consist 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. In this topic, 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 structures and arrays, as well as the function shall also be discussed.

CONCEPTS OF STRUCTURES

What is your understanding of structures? Can you compare structures with variables and arrays? Before we go further into the topic of structures, it is better to firstly understand the concept of structures. A structure is the combination of bits of data from different sources and types. Unlike arrays, structures can combine data of different types and can be referred to using the same name.

3.1

TTooppiicc 33 Structures

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

1. Identify the concepts and techniques of declaring structures;

2. Explain the elements in three structure conditions; and

3. Use the structure concept with function application.

LEARNING OUTCOMES

Page 50: Data Structure

TOPIC 3 STRUCTURES

43

Let us assume that we want to create an account. We would need the following information:

Account number

Type of account

Name of account holder

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

Table 3.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

DECLARING AND INITIALISING STRUCTURE ELEMENTS

In general, the template for declaring structures is by using the struct construction, which is as follows:

struct struct_name { data_1_definition; data_2_definition;

: data_n_definition;

};

3.2

1. What are the advantages of structures compared with arrays?

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

EXERCISE 3.1

Page 51: Data Structure

TOPIC 3 STRUCTURES

44

Where

• struct_name - name of the constructed struct that must fulfil the requirements naming a variable rule

• data_*_definition - data type definition for each element that forms the structure

struct account {

int accountNo; char accountType; char name[30]; float balance;

};

Before using the declaration of the struct in a program, we need to declare the variable of struct type. This variable of type struct can be declared as follows:

struct struct_name variable_name;

where

• struct_name - name for the structure that has been declared

• variable_name - name for the variable that represents the struct Observe that

struct account myAccount;

declares the myAccount variable as an account structure. Based on the variable declaration above, the memory space that is reserved for myAccount is as shown in Figure 3.1.

Variable Structure name

Page 52: Data Structure

TOPIC 3 STRUCTURES

45

Figure 3.1: Memory space myAccount

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.

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};

Can you sketch the memory space for the account struct myAccountif it is initialised in the following way:

struct account myAccount = {1234, ‘S’, “Nadiah”,1998.88};

SELF-CHECK 3.1

Page 53: Data Structure

TOPIC 3 STRUCTURES

46

REFERENCING STRUCTURE ELEMENT

The elements of a structure are normally processed individually, i.e. separately. Therefore, we must be able to access each of the structure elements. This can be achieved by using an operator .(dot), as follows:

variable.data_definition

where

• variable - name of structure

• data_definition - element in the structure that is need to be referred

Observe the example below. 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.

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

3.3

1. Write the structure declaration for date.

2. Find the errors in each of the following: (a) struct human { char name[30];

int age;

}

(b) By assuming that the struct human has been declared properly, make corrections to the following statement:

human hmn;

EXERCISE 3.2

Page 54: Data Structure

TOPIC 3 STRUCTURES

47

Let us have a look at the following programming segment. This program shows how the input and output of structure elements are performed.

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

Savings balance : %.2f\n”, myAccount.name, myAccount.accountNo, myAccount.accountType, myAccount.balance);

Observe that the & operator is used to represent the address for each structure element that is to be assigned with a new value.

There are several examples in the website: http://www.eng.ukm.my/~kbj/p7/acpp70.html. Spend a little time to explore that site.

ACTIVITY 3.1

Page 55: Data Structure

TOPIC 3 STRUCTURES

48

To test your understanding of this topic, answer the following questions.

STRUCTURE TYPE ARRAYS

To represent a group of data from the same type of structure, we use an array representation of a structure type. We declare the array of structure type as follows:

struct account customer[500]; Above is the declaration of customers as an array of 500 elements of account structure type. Each field for the array elements can be referred to directly.

3.4

1. Given the following declaration:

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

} customer;

Write the statement to access the following structure elements:

(a) name element for a customer (b) customerNo element for the customer structure (c) telephoneNo element for a customer

2. Using the same declaration in (1), write statements that assign the

following information to the customer.

(a) The name of the customer is Aisyah (b) The customer number is 1226 (c) The customerÊs telephone number is 011-333011

EXERCISE 3.3

You have previously sketched the memory space for arrays in Topic 1. Try and think back. What is the memory space sketch for the structure type array.

SELF-CHECK 3.2

Page 56: Data Structure

TOPIC 3 STRUCTURES

49

For example, we can assigned customer[14].accountNo (since the index begins with 0) as the reference for the 15th customer account number. We can also refer the savings balance for the last customer as customer[499].balance. We can also refer the first character for the name of the first customer as customer[0].name[0]. Look at several statement examples and outputs in the following:

customer[14].accountNo = 122; customer[88].balance = 8755.02; printf(“The name of the first customer begins with the letter %c\n”, customer[0].name[0]);

Do the following exercise to test your understanding.

Given the following structure declaration:

struct BOOK { char title[50]; int year; float price;

} book[50];

Write a program that can perform the following: (a) Read data from data.dat file into the book structure array. The

format of the file is as follows:

C Programming, revised edition 200033.00 OO.Java, revised edition 200235.00 Data Structures Using C 199822.00

: :

(b) Print the information store in the book structure.

EXERCISE 3.4

Page 57: Data Structure

TOPIC 3 STRUCTURES

50

STRUCTURE TYPE STRUCTURE

We can also declare a structure element as another type of structure. Look at the following example:

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

}; struct account2 {

int accountNo; char accountType; char name[30]; float balance; struct date transaction;

};

transaction represents the last transaction date that is declared as a structure type date. This declaration is shown in the following Figure 3.2:

Figure 3.2: Memory space for the declaration of account2

Assuming that we declare the following:

struct account2 newAccount; we can refer the month of the last transaction for newAccount as

newAccount.transaction.month

3.5

Page 58: Data Structure

TOPIC 3 STRUCTURES

51

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 (refer to Figure 3.2)

To ensure that you understand the topic, answer the following questions.

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:

(a) name element for customer

(b) customerNo element for customer structure

(c) telephoneNo element for customer

(d) postCode element for customer

EXERCISE 3.5

For other examples, refer to Program 15.1 of Bahasa Pengaturcaraan C, 2000 Revised Edition.

ACTIVITY 3.2

Page 59: Data Structure

TOPIC 3 STRUCTURES

52

STRUCTURES AND FUNCTIONS

In C, 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. Observe the following example. The tkh structure 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 tkh structure in the main() function is still the same as the value before the increasDate() function was called. This means that the output that is printed is 20/1/2001. void main( ) {

struct date dte = {20, 1, 2001}; increaseDate (dte);

printf(“%d/%d/%d”, dte.day, dte.month, dte.year); } void increaseDate(struct date t) {

(t.year)++; /* the year element is increased */ }

3.6

The tkh structure is passed to the increaseDate function by value and the original dte structure is still maintained.

2. Using the same declaration given in (1) above, write the statement for assigning the following information to the customer structure.

(a) The customerÊs name is Aisyah

(b) The customerÊs number is 1226

(c) The customerÊs telephone number is 011-333011

(d) The customerÊs address is No. 21, Jalan Kenangan

(e) The post code is 02000

(f) The city is Seri Intan

(g) The state is Darul Mulia

Page 60: Data Structure

TOPIC 3 STRUCTURES

53

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

3.6.1 Return Value Functions

We can return a structure from a function using the statement return. Look at the example below. The structure dte 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 = 2001 + 3 = 2004). Then, the t structure (with the day =31, month = 10, year = 2004 values) is returned with the return statement. The value that is returned is assigned to the t1 structure.

struct date addYear(struct date dte, int);

void main() { struct date dte = {31, 10, 2001}; struct date t1; t1 = addYear(dte, 3);

} struct date addYear(struct date t, int i) { t.year +=i; return t;

} Do the following exercise to test your understanding. Good Luck!

1. Re-write the solution to Question 1 in Exercise 3.4 with the following

modifications:

(a) Write the void readInfo(struct BOOK book[]); function to read the book information.

(b) Write the void printInfo(struct BOOK book[]); function to print the book information.

(c) Write a program that can implement both the above functions.

EXERCISE 3.6

Page 61: Data Structure

TOPIC 3 STRUCTURES

54

STRUCTURE APPLICATIONS

Problem Statement

You are required to write a program that can grade the marks of an objective exam paper. There are 25 questions in that paper and each question can be answered using four character values, which are A, B, C, or D. There were 200 students who sat for this exam. The correct answers are kept in the answer array, as follows:

char answer[ ] = {“CABDCABDCABDCABDCABDCABDC”} The number matrix and answer by the students is read from the answer.dat file in the following format:

1221 AAAAABBBBBCCCCCDDDDDABCDA 1222 BBCCDDAABBCCDDAABBCCDDAAB 1223 ABCDABCDABCDABCDABCDABCDA

: :

Each correct answer gives four marks. You need to calculate the marks that the students get and then print their matriculation number followed by their marks.

3.7

2. Modify the solution to Question 1 above in the following way:

(a) Change the size of the book array to 100.

(b) Change the readInfo() function so that data from a file can be read until it reaches the end-of-file (EOF).

(c) Write the void sortInfo(struct BOOK book[]); function to sort the book information according to the title.

(d) Write the void changePrice(struct BOOK book[], float rate); function to calculate the new price that is higher than the original price, by the percentage rate given.

(e) Modify the main program to implement the above functions before printing the book information.

Page 62: Data Structure

TOPIC 3 STRUCTURES

55

Data Design

Input: Declared as the following structural array:

struct student {

int matric; char answer[25]; int marks;

};

struct student exam[2000];

Output: Answer element in the exam[] structure type array.

Implementation The following is the program solution. Program 3.1

#include <stdio.h> #define NO 200 struct student{

int matric; char answer[27]; int marks;

}; struct student exam[NO]; void readInfo(exam); void calculateMarks(struct student [], char []); void printMarks(struct student []);

void main() {

char answer[] = {“CABDCABDCABDCABDCABDCABDC”}; readInfo(exam); calculateMarks(exam, answer); printMarks(exam);

}

void readInfor(struct student p[]) { FILE *file; int i; file = fopen(“student.dat”, “r”); for (i = 0; i < NO; i++) {

Page 63: Data Structure

TOPIC 3 STRUCTURES

56

fscanf(file, “%d”, &(p[i].matric)); fgets(p[i].answer, 26, file); printf(“%d %s\n”, p[i].matric, p[i].answer);

} fclose(file); } void calculateMarks(struct student p[], char ans[]) {

int i, j; for (i = 0; i < NO; i++ {

p[i].marks = 0; for (j = 0; j < 25; j++) {

if (p[i].answer[j] == ans[j]) p[i].marks +=4;

} }

}

void printMarks(struct student p[]) { int i; for (i = 0; i < 5; i++) {

printf(“%d %d\n”, p[i].matric, p[i].marks); }

}

typedef CONSTRUCTION

Other than using the struct command 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>; Example: typedef int input; ---------(i) input positive_input, negative_input; -------(ii) In statement (i) above 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 vatiables in (ii) is actually of integer type. In (ii), we have replaced the command int with input.

3.8

Page 64: Data Structure

TOPIC 3 STRUCTURES

57

The typedef command can also be used in the structure declaration. Consider the following example:

typedef struct biodata {

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

} Bio; Based on the above 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 sections. It is a data type declaration of structure type.

Using structures is an easy way to group information from several related

items by using the same variable name. Unlike arrays, the structure elements do not necessarily have to be of the same type.

• In this topic, we have looked at how to declare structures and refer to structure elements.

• We have also looked at how to declare structures of structure type and arrays

of structure type. • The use of structures in a medium-sized program was also described.

Structure Structure Duplication

Page 65: Data Structure

INTRODUCTION

Lists and linked lists are two different terms. Hopefully you will not be confused with the two terms. A list is a general term that is defined by one type of sequential data items, like the list of winners for the „Dial and Win Quiz on Era Radio‰, list of courses that is being offered to students by MARA, and others. Whereas linked list is a specific term that is used in programmes and is defined as a group of data items that is sequential with its data items having links between each other. The difference between both terms is that in linked lists, its data items have links between each other (which is why it is named linked list) but this is not the case in list data items.

TTooppiicc 55 Lists and Linked Lists

By the end of the topic, you should be able to:

1. Differentiate between lists and linked lists;

2. Apply basic linked list operations correctly; and

3. Implement the linked list concept using pointers.

LEARNING OUTCOMES

Page 66: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

72

LISTS

Lists in programming can be implemented by using arrays. It is easier because each of its data item is not linked with each other, but it is arranged sequentially and forms a list like the array location that is illustrated below:

5.1.1 Basic List Operations There are several basic operations that can be performed by using linked lists, which include: (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.

(b) Test Whether a List is Empty or Not A list needs to be confirmed empty or otherwise before the process of

deletion can be performed. This is because, if the list is empty, deletion cannot be performed.

(c) Traverse List The traversal operation is a process of traversing from one node to another

node until the end of the list. Usually, this operation is performed for printing each data item that is contained in the list.

(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. If the data item is to be inserted early in the list, then many shifting 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.

5.1

Page 67: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

73

(e) Delete an Item from the List The deletion operation for a sorted list also involves the process of shifting.

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. The prerequisite for a deletion operation is that the list must not be empty.

5.1.2 Implementations of Lists Using Arrays

As stated previously, a list is data items that are sequential. From this definition, it will encourage us to use arrays 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. In order to further understand this topic, complete the following exercise:

LINKED LISTS

In your opinion, what is the difference between lists and linked lists? In the previous sections, you saw how arrays could improve the arrangement and efficiency of your programming. However, arrays are not practical for modification or for inserting and deleting data. This weakness can be overcome by using linked lists.

5.2

Let us assume that the data ÂCÊ is deleted. What will happen next?

EXERCISE 5.1

Page 68: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

74

Linked list are collections of data items lined up in a row insertions and deletions are made any where in a linked list. Linked lists consist of sequential items that are known as nodes. Each node is made up of two parts, which are:

1. Data, which is the element in the list

2. Link, which is the link to the next node in the list

The linked list structure can be illustrated as shown in Figure 5.1 below:

Figure 5.1: Linked list structure

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

• Arrays

• Pointers

The implementation of linked lists using arrays will not be discussed in this course. Only the implementation of linked lists using pointers will be discussed.

5.2.1 Basic Linked List Operations

In linked lists, 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 lists in Topic 5.1.1. However, there are several additions.

(a) Create empty linked list

(b) Test whether list is empty or not

(c) Traverse linked list

(d) Insert new item (add new item in linked list)

(e) Delete item from linked list To refresh your memory on the above operations, refer to topic 5.1.1. Basic

List Operations.

Page 69: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

75

(f) Create new nodes Before a new node can be assigned a value, it has to be given sufficient

memory space to store data. To reserve memory space dynamically, we can use the malloc( ) function.

(g) Search linked list linearly A search is a process of finding a data item in a linked list.

5.2.2 Implementation Using Pointers

We redefine the linked list abstract data type as a group of data items that are sequential with the basic operations that are stated above. 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:

typedef char ELEMENT; typedef struct node {

ELEMENT data; struct node *next;

} NODE;

We define the variable of the above structure type in our program using the following statement

NODE *list; struct node *pnode;

Refer to the topic on Structure, in Unit 1, if you do not understand why it has to be defined as such.

(b) Creation of Empty Linked List

The basic CreateList can be written as: /* Receive : Reference to sList list

Process : Create new list Return : New list reference */

void CreateList (NOD **sList) {

*sList = NULL; }

Page 70: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

76

An example of a procedure call to this function is as follows: CreateList(&list); The list linked list is sent by reference (observe the & symbol that is used). This means, in the CreateList function, sList will receive the address for the list pointer. At the end of this function, list will have the value NULL, which is a new list that is empty.

Figure 5.2: New empty list

(c) Creation of New Node

For the operation of creating a new node, we declare the NewNode function as follows:

/* 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;

}

Figure 5.3 illustrates the node that will be returned after the execution of this function. LetÊs just say that dataelement has a value of ‘X’.

Page 71: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

77

Figure 5.3: 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. typedef enum bool {FALSE, TRUE} BOOL; /* BOOL is of type enum with FALSE = 0, TRUE = 1 */

The following is the declaration of EmptyList function. /* Return TRUE value if empty, FALSE if not */ BOOL EmptyList (NODE *sList) {

return ((BOOL) (sList == NULL)); }

(e) Traversal of Linked List The process for the TraverseList operation all depends on the type of application, such as printing all the data items, counting the number of data items and other applications. In Figure 5.4 below, the TraverseList operation will print each element in the list.

/* Traverse and print each element in list */ void TraverseList (NODE *sList) {

NODE *pnode; for (pnode = sList; pnode != NULL; pnode = pnode->next)

printf(“pnode.data : %c -> \n”, pnode -> data); printf(“NULL”);

}

Figure 5.4: List traversal

Refer to the book Struktur Data by Marini A. Bakar to see the declaration of the BOOL data type.

ACTIVITY 5.1

Page 72: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

78

(f) Searching Linked List Linearly The following is the function for searching a list that is not sorted. /* Search the list until a node is found that contain the item that is required */ BOOL SearchList (NODE *sList,

ELEMENT dataelement, NODE **pnode)

{ NODE *qNODE; qNODE = sList; *pnode = NULL; while (qNODE != NULL) {

if (qNODE->data = dataelement) return (BOOL) (TRUE);

else {

*pnode = qNODE; qNODE = qNODE->next;

} } return (BOOL) (FALSE);

} (g) Insertion of Node in Linked List

There are three positions for the insertion operation, which are:

1. Insert at the start of the list

2. Insert between two nodes in the list (middle of list)

3. Insert at the end of the list

(i) Insert Node at the Start of the List The following are steps to insert a node at the start of the list.

Step 1

Assuming that the temp node is to be inserted at the start of the sList list.

Page 73: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

79

Step 2 Set temp.next = sList

Step 3 Set sList = temp

The list that is produced is:

(ii) Insert Node in the Middle of the Linked List The following are steps to insert a node in between two nodes.

Let us suppose pointer t 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 p that points to the location where node t is to be inserted. At the end of this operation, p will be inserted after the node that is identified (pointed) by p. The following figure illustrated this situation before the insertion.

Page 74: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

80

The algorithm for this operation is as follows:

1. Set t->next = p->next

2. Set p->next = t

The following figure shows the effects of both steps above:

(iii) Insert Node at the End of the Linked List The following are the steps to insert a node at the end of a linked list. Let us suppose that the temp node is to be inserted at the end of the sList list.

Step 1 Set temp->next = p->next /* point to NULL value */ The effect of the above command is as shown in the figure below:

Page 75: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

81

Step 2 Set p->next = temp. The effect is:

The function for inserting a node in a linked list for all the above cases is as follows:

void InsertList (NODE **sen, NODE *temp, NODE *p) {

if (p == NULL) { temp->next = *sen;

*sen = temp; }

else { temp->next = p->next;

p->next = temp; } } //InsertList The pointer p points to the location where the node needs to be inserted. If p is NULL, the new node will be inserted at the start of the list. (h) Deletion of Node from Linked List The node deletion operation also has three situations, which are delete first

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

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

{ NODE *temp;

if (EmptyList(*sList)) {

Page 76: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

82

printf(“Deletion Error: Empty List”); return;

} if (pnode == NULL)

{ temp = *sList; *sList = temp->next;

} else // if pnode is not null

{ temp = pnode->next; pnode->next = temp->next;

} free(temp);

}

To understand this topic further, answer the following exercise.

5.2.3 Application Using Linked List

The following is a complete programming example that has been tested. You can try to execute this program in your computer and observe its implementation. This program will build a linked list for characters that are input and print the data elements that are found in the linked list.

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

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

Draw the change that occurs after this statement. pList = pList->next;

EXERCISE 5.2

Page 77: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

83

Program 5.1

/* Linked List data structure declaration */ struct listNode {

char data; struct listNode *nextPtr;

}; typedef struct listNode LIST; typedef LIST *ListPtr; typedef enum bool {FALSE, TRUE} BOOL;

/* Function prototype declaration */ void CreateList(LIST **); LIST *NewNode(char); void InsertList(LIST **sList, LIST *dataelement, LIST *pnode); void TraverseList(LIST *sList);

/* Main program */ main () {

char item; LIST *list, *tempNode; /* Create empty list */ CreateList(&list); /* Read data and insert into linked list */ printf(“Enter word ending with ‘$’ symbol: “); while ((item = getchar()) != ‘$’) {

tempNode = NewNode(item); InsertList(&list, tempNode, NULL);

} /* Traverse linked list to print all data elements */ TraversList(list); printf(“\n”);

} /* Type the full functions for the basic operations that

will be used. You can refer to or copy those functions from this topic */

Page 78: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

84

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 2 linked lists:

Draw the changes that occur after the following statements have been executed. (a) temp = pList1;

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

temp->next = pList2;

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

temp = temp->next; temp->next = pList1;

(Use your own paper to answer the questions in this exercise)

EXERCISE 5.3

Page 79: Data Structure

TOPIC 5 LISTS AND LINKED LISTS

85

• Using pointers to implement linked lists is a little difficult. However, if you

do a lot of exercises and write programs, it will become easier. Writing functions like CreateList, InsertList, and the like repeatedly may get boring.

• To make things easier, you may gather the declaration of data structure,

function prototypes and declaration of basic functions into a header file (which is named list.h).

• The actual implementation of the basic operations for linked list is written in a

separate program file (let us assume the file name is list.c). Refer to the book Struktur Data by Marini Abu Bakar to for more detailed explanation.

Linked lists Lists

Page 80: Data Structure

INTRODUCTION In the previous topic, we were introduced to lists and linked lists. Among the important things that were highlighted were the use of pointers and basic operations. This time, we will be introduced to another way of structuring data i.e stack. It can be depicted 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.

Figure 6.1: Illustration of the stack concept

TTooppiicc 66 Stacks

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

1. State the main meaning and characteristics of stacks correctly;

2. Apply basic stack operations in the proper manner;

3. Apply the stack data structure in the form of an array; and

4. Write complete stack application functions.

LEARNING OUTCOMES

Page 81: Data Structure

TOPIC 6 STACKS

87

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 end. For this reason or a main characteristic of stack is LIFO structure (Last-In First-Out).

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: (i) Create Stack The stack creation operation is for creating an empty stack. This operation

is performed before all the following operations can be carried out.

(ii) Test Empty Stack This operation is to test whether the stack is empty or not. Testing is

performed before the item removal operation is executed. This is because, if the stack is empty, then there is no item that can be removed.

(iii) Test Full Stack This operation is performed if the implementation is done using arrays. If

the implementation is done using pointers, this test is not needed. This operation is to test whether a stack is full or not. This operation is performed before the insertion operation is carried out. This operation is performed because arrays have an item limit. Now items cannot be inserted in a stack if the stack is full.

(iv) Remove Element from Stack This operation is to remove an item from a stack. The prerequisite is that

the stack must not be empty. (v) Add Element to Stack This operation is for inserting an item into a stack. The prerequisite is that

the stack must not be full.

6.1

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

Page 82: Data Structure

TOPIC 6 STACKS

88

In order to enhance your understanding, answer the exercise below.

IMPLEMENTATION USING ARRAYS

The stack data structure can be implemented in two ways, which are:

1. Using pointers

2. Using arrays

The implementation using arrays is easier compared to the implementation using pointers. So, here, we will only discuss its implementation using arrays. Below show how to add data into stack and remove data from stack.

1. Add D

2. Add A

3. Add H

1. Remove H

2. Remove A

6.2

If in a stack there are 10 items, and all those items need to be removed, how many times does the removal operation need to be carried out.

EXERCISE 6.1

H

A

D

D

Page 83: Data Structure

TOPIC 6 STACKS

89

6.2.1 Declaring Data Structures

The stack data structure can be defined as follows: #define MAXSTK 10; typedef int ELEMENTTYPE; typedef struct stk {

int top; ELEMENTTYPE element [MAXSTK];

} STK; In the above definition, the stack maximum was set to just 10 items. This limit changes according to the application.

6.2.2 Creating Stacks

The basic stack creation operation can be written as follows: /* Create empty stack */ void createStk (STK *t) {

t->top = 0; }

If the stack is empty, t->top is 0. 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.

6.2.3 Checking Empty Stacks

The basic operation to test whether a stack is empty or not can be written as follows:

/* 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.

Page 84: Data Structure

TOPIC 6 STACKS

90

6.2.4 Checking Full Stacks

The basic operation to test whether a stack is full or not can be written as follows:

/* Check if the stack is full */ BOOL fullStk (STK *t) {

(return (BOOL) (t->top >= MAXSTK)); }

This function will return the value TRUE is the stack is full and the value FALSE if the stack can still be filled with a new item.

6.2.5 Inserting Items into Stacks

The basic operation for inserting into a stack can be written as follows:

/* Insert an item into a stack t or display an error message If t is full */ void insertStk (ELEMENTTYPE item, STK *t); {

if (fullStk(t)) printf(“\nStack Full \n”);

else {

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

} }

6.2.6 Removing Items from Stacks

The basic operation for removing an item from the top of the stack can be written as follows:

/* Remove an item from a stack t or display an error message if t is empty */ void removeStk (ELEMENTTYPE *item, STK *t); {

if (emptyStk(t)) printf(“\nStack Empty \n”);

else {

t->top--; *item = t->element[t->top];

} }

Page 85: Data Structure

TOPIC 6 STACKS

91

Before going onto the next topic, you are encouraged to try and answer to following exercise to enhance you understanding.

6.2.7 Stack Application: Separating Even and Odd Numbers

Try to understand the Program 6.1 below line by line and then type and execute the program using a computer and observe the results! The following Program 6.1 will read 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. Then the contents of both stacks will be printed onto screen. Program 6.1

/* Declaration of Stack data structure */ #define MAXSTK 10; typedef int ELEMENT; typedef enum bool { FALSE, TRUE } BOOL; typedef struct node {

int top; ELEMENT data [MAXSTK];

} STK;

/* Declaration of function prototypes */ void CreateStk (STK *t); BOOL EmptyStk (STK *t); BOOL FullStk (STK *t); void InsertStk (ELEMENT item, STK *t); void RemoveStk (ELEMENT *item, STK *t);

main ( ) {

int counter, number, temp; STK odd, even;

Let us suppose that the stk variable is declared as STK type, and the num variable is of type ELEMENTTYPE. Write statements to call the CreateStk, InsertStk, and RemoveStk functions.

EXERCISE 6.2

Page 86: Data Structure

TOPIC 6 STACKS

92

/* Create even and odd stacks */ CreateStk(&odd); CreateStk(&even); /* Read data & insert into the related stack */ for (counter = 1; counter <= 10; counter ++)

{

printf(“\nInput number : “); scanf(“\n%d, &number); if (number%2 == 0)

InsertStk(number, &even); else

InsertStk(number, &odd); }

/* Print contents of odd stack */ printf(“\nPrinting Odd Numbers : “); while (!EmptyStk (&odd)) {

removeStk (&temp, &odd); printf(“%d “, temp);

} /* Print contents of even stack */ printf(“\nPrinting Even Numbers : “); while (!EmptyStk (&even)) {

removeStk (&temp, &even); printf(“%d “, temp);

} /* Type the codes for the full functions here for the basic operations that need to be used */

6.2.8 Stack Application: Reverse Polish Notation

Arithmetic expression can be written using an infix notation like M + N * P where the operator is located in between two operands. The compiler will change this infix notation expression into a postfix notation or prefix notation.

Notation Expression

Infix M + N Postfix M N + Prefix + M N

In infix notation, parentheses will determine the precedence or the operation. For example, 2 * ( 3 + 2 ) and 2 * 3 + 2 will give different answers. In postfix notation,

Page 87: Data Structure

TOPIC 6 STACKS

93

the parentheses are not required in determining the precedence of operations, and it is also known as the reverse Polish notation. EXAMPLE:

(a) Postfix Expression Algorithm The 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 given below:

A. Create a stack

B. Repeat until the end of the expression is read

(a) Read the next token in the expression (b) If the token is an operand, then

(i) Insert the token into the stack

(c) If the token is an operator, then

(i) Remove two top most values from stack (ii) Perform operation (iii) Insert result into the stack

If the end of the expression is found, the value on top of the stack is the result.

The following is an example of trace of a postfix expression algorithm. The following expression example is used. You must read start from left to right.

Change the following infix expression to a postfix expression using the addition of parentheses ( ).

(a) J * K / L + M

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

EXERCISE 6.3

Page 88: Data Structure

TOPIC 6 STACKS

94

20 4 / 9 2 - + (postfix expression) Insert 20 Insert 4

4

20

5

Next a Â/Ê is read, so 4 and 20 popped and 20/4 = 5 is pushed or inserted

2

9

5

Now, 9 and 2 is pushed or inserted

7

5

Next a Â-Ê is read, so 2 and 9 popped and 9 - 2 = 7 is pushed or inserted

Page 89: Data Structure

TOPIC 6 STACKS

95

Below are given postfix expressions. Using the postfix expression evaluation algorithm, evaluate the expressions.

(a) 21 3 / 10 7 3 / *

(b) 3 5 * 2 6 - *

EXERCISE 6.4

1. A data structure and identifier definition is given as follows:

typedef struct stack {

int top; ELEMENTTYPE element[5];

} STK; STK stk1, stk2; int a, b, c;

By using the basic stack operations for the abstract data type, sketch the contents of the stack that is shown by stk1, stk2, and the values of a, b, c after the following program segment is performed. If there are any errors, state them!

CreateStack(&stk1); a = 15; b = 20; InsertStack(a, &stk1); InsertStack(b, &stk1); RemoveStack(&c, &stk1); InsertStack(c, &stk2);

EXERCISE 6.5

12

Next a Â+Ê is read, so 7 and 5 popped and 5 + 7 = 13 is pushed or inserted

Page 90: Data Structure

TOPIC 6 STACKS

96

The implementation of the data structure using arrays has limitations in the

maximum number of items in the stack. This problem can be solved with the implementation using a linked list because the data item or node can be inserted without limit. However, as was previously stated, the implementation using arrays is much easier compared to using linked lists.

• At the end of this topic, you should already be able to understand how the

stack operations are implemented. • You should also be able to write a stack application program.

2. Given the definition for the following data structure:

#define MAXSTK = 10; typedef char ELEMENT; typedef struct node {

int top; ELEMENT data[MAXSTK];

} STK; STK stk1, stk2;

By using the basic stack operations (like CreateStk, InsertStk, RemoveStk, and others), write the functions that can implement the following tasks:

STK *CopyStack (STK *t1, STK *t2);

/* Receive : Stack t1 and t2 Process : Copy the contents of stack t1 into stack t2 where the contents of t2 is arranged such that it is inverted to the contents of t1. This means that the top most element in t1 is the bottom most element in t2, while the bottom most element in t1 is the top most element in t2. Return : Stack t2 */

(Use your own paper to answer all the questions in this exercise.)

Page 91: Data Structure

TOPIC 6 STACKS

97

• In order to become for competent in writing programs, you need to write a lot of programs. Do it honestly so that the success is your very own.

Even numbers Odd numbers

Stacks

Page 92: Data Structure

INTRODUCTION

We shall 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 5 and Topic 6. Therefore, let us broaden our knowledge in the data structure subject with this topic on queues. Similar to stacks, queues also have a wide application. In our daily lives, we can see queues as waiting lines in banks or cars at toll gates. Customers or cars that arrive first will be attended to first, while those that come after will be attended to when their turn comes. We shall disregard cases of jumping queues or cutting in lines.

TTooppiicc 77 Queues

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

1. Define the main characteristics of queues correctly;

2. Apply basic queue operations in a correct manner; and

3. Implement queue functions using arrays.

LEARNING OUTCOMES

Page 93: Data Structure

TOPIC 7 QUEUES

99

Figure 7.1: People queuing up to get forms

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 above definition, we can say that the main characteristic of a queue is also known as FIFO (First in First out).

BASIC QUEUE OPERATIONS

Like all the basic data structure operations previously mentioned, queue operations are just as similar. Queue operations also perform the following: (a) 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.

(b) Test Empty Queue

Conducting a test to see whether a queue is empty is first needed before the removing an item from the queue operation is performed.

(c) Test Full Queue Conducting a test to see whether a queue is full is first required before the

addition of an item to the queue operation is performed.

7.1

Page 94: Data Structure

TOPIC 7 QUEUES

100

(d) Remove One Element From Queue This operation is for removing one item or element from the queue. The

prerequisite for this operation is that the queue must not be empty. (e) Add One Element to Queue This operation is for the addition of one item or element to the queue. The

prerequisite for this operation is that the queue must not be full, which means that there must still be room to insert another item.

To test your understanding, answer the following exercise.

IMPLEMENTATION OF QUEUE DATA STRUCTURE

Queue data structures can be implemented in two ways, which are

(i) By using pointers

(ii) By using arrays

However, here we will only discuss the implementation using arrays. We shall use arrays to keep queue data items and two variables to represent the front and back queue locations (Remember! We also use a variable to represent the top of stacks). 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 and item leaves the queue (the item leaves through the front of the queue). Observe the following case; assuming that the maximum for queue elements is 5. The create queues operation will create an empty queue with the front and back being 0, which means that both are pointing to position index 0.

7.2

What operation becomes the prerequisite to execute the removal of an item operation from the queue? Why?

EXERCISE 7.1

Page 95: Data Structure

TOPIC 7 QUEUES

101

Step 1 CreateQueue

Step 2 EnterQueue A EnterQueue B EnterQueue C Step 3 Remove two items from the front of the queue, thus the front variable is increased. ExitQueue ExitQueue

Insert two more new items. EnterQueue D EnterQueue E

Page 96: Data Structure

TOPIC 7 QUEUES

102

After two more items 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. 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, the second item at index 1, and the 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. As for the above case, observe the following: Step 1 Insert three items into the queue. EnterQueue A EnterQueue B EnterQueue C

Step 2 The value of the back variable is increased by the number of items that are inserted. Then, remove two items. ExitQueue ExitQueue

Page 97: Data Structure

TOPIC 7 QUEUES

103

Step 3 The value of the front variable will be increased by as many items that are removed. Insert two more items. EnterQueue D EnterQueue E

Here, observe that after two more items have been inserted, the value of the back variable is 0. This enables other items to be inserted in the queue.

7.2.1 Declaring Data Structures

Similar to what has been discussed above, queue data structures 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. Since we are using arrays, then the maximum number of array elements needs to be declared before hand. Below, we assume the maximum is 10. However, this value can be changed according to the application. The queue data structure can be defined as follows:

#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;

Page 98: Data Structure

TOPIC 7 QUEUES

104

7.2.2 Creating Queues

The function for the basic operation to create empty queues can be written as follows:

/* 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; }

7.2.3 Checking Empty Queues

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 follows:

/* 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)); }

7.2.4 Checking Full Queues

The test to see whether or not a queue is full can be written as follows:

/* 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));

}

Page 99: Data Structure

TOPIC 7 QUEUES

105

7.2.5 Inserting Items into Queues

The operation to insert items into queues involves two steps, which are: 1. Assigning the item that is inserted into the element with a back index value

(because the item is inserted from the back). 2. Then, the back value is increased. The value that is added needs to be

modulo with QLimit so that the back value is always in the region of 0 and QLimit - 1.

The function for this operation can be written as:

/* Receive : one data item and one queue g

Process : insert data item to the back of the queue Return : the updated queue */ void InsertQ(ELEMENTTYPE item, QUEUE *g) {

if (FullQ(g)) printf(“ ERROR : FULL QUEUE\n”);

else {

g->element[g->back] = item; g->back = (g->back + 1) % QLimit;

} }

7.2.6 Removing Items from Queues

The RemoveQ 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 modulo with QLimit in the same way as the InsertQ function. The function to remove items from a queue can be written as:

/* Receive : queue g Process : remove data item from front of queue Return : the data item is removed and the queue is updated */

void RemoveQ(ELEMENTTYPE *item, QUEUE *g) {

if (EmptyQ(g)) printf(“ ERROR : EMPTY QUEUE \n”);

else {

Page 100: Data Structure

TOPIC 7 QUEUES

106

*item = g->element[g->front]; g->front = (g->front +1) % QLimit;

} } To ensure that you understand what has been taught, answer the following answers.

7.2.7 Queue Application

The following is a complete programming example for a queue application. Try and follow this program line by line and then type and execute using a computer. Observe the result. This program will read a set of positive and negative integer numbers. These numbers will be inserted in a queue. Then the numbers in the queue will be removed one by one. The negative integer numbers will be discarded from the queue and the positive integer numbers will be re-inserted into the queue.

/* Declaration of queue data structure */ #define QLimit 10 typedef enum bool { FALSE; TRUE } BOOL; typedef int ELEMENTTYPE; typedef struct queue { int front; int back; ELEMENTTYPE element[QLimit];

} QUEUE; /* Declaration of function prototypes */ void CreateQ (QUEUE *g); BOOL EmptyQ (QUEUE *g); BOOL FullQ (QUEUE *g); void InsertQ (int item, QUEUE *g); void RemoveQ (int *item, QUEUE *g);

If given QLimit = 10, the variable value of front = 6, and back = 5, follow the FullQ function. What value (TRUE or FALSE) is returned?

EXERCISE 7.2

Page 101: Data Structure

TOPIC 7 QUEUES

107

/* Main program */ main() {

/* Declaration of variables */ QUEUE q; int i, dataelement; /* Create queue */ CreateQ (&q); /* Insert data into queue */ printf(“\nEnter a set of integer numbers: “); for (i = 1; i < QLimit; i++)

{ scanf(“%d”, &dataelement); InsertQ(dataelement, &q);

} /* Separate positive and negative integers */ printf(“\nRemoving negative numbers ...”); for (i = 1; i <= QLimit; i++) {

RemoveQ(&dataelement, &q); if (dataelement >= 0) InsertQ(dataelement, &q);

} }

Page 102: Data Structure

TOPIC 7 QUEUES

108

1. Given the following definition:

#define MAX 5 typedef struct queue {

int front, back; int element[MAX];

} QUEUE;

QUEUE qs, qk; Int i,j;

Give the content of qs.element as well as the values of qs.front and qs.back after the following program segment is executed. If there are any errors, state them.

CreateQ(&qs); CreateQ(&qk); for (i = 1; i <= MAX, i++)

InsertQ(i*2, &qs); for (i = 1; i <= MAX, i++) {

RemoveQ (&j, &qs); If (i%2 == 0)

InsertQ(j, &qk); }

2. By assuming that a queue is implemented using arrays, use the

basic queue operation to complete the following functions:

(i) int SizeQ (QUEUE *QG) /* Receive : Queue QG

Process : Count the number of elements in queue Return : The number of elements in queue */

(ii) void ShowQ (QUEUE *QG) /* Receive : Queue QG

Process : Show the contents of queue QG from the front to the back without changing its contents */

(Use your own paper to answer the questions in this exercise)

EXERCISE 7.3

Page 103: Data Structure

TOPIC 7 QUEUES

109

• Just like stack data structures, queues can also be implemented using a linked

list. • Since this topic only discusses the implementation using arrays, perhaps if

you are interested to know about how to implement queues using linked lists, then you can refer to the many related books available.

Queues

Page 104: Data Structure

INTRODUCTION In the previous topics, we have been introduced to data structures (lists, stacks, and queues) and algorithms. Both of these topics go hand in hand and have a close relationship. It can perhaps be shown as follows: Therefore, to produce an effective program, the selection of data structure 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. This topic will discuss several algorithms for sorting. 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

TTooppiicc 88 Sorting

By the end of this topic, you will be able to:

1. Classify the types of sorting algorithm into selection, exchange, insert, and bubble sort;

2. Differentiate the efficiency of several algorithms; and

3. Apply sorting algorithms to related problems.

LEARNING OUTCOMES

Programs = Data Structures + Algorithms

Page 105: Data Structure

TOPIC 8 SORTING ! 111

the letter ÂAÊ and followed by the next letter, as illustrated in Figure 8.1 below. The process of arranging according to a given rule is called sorting.

Figure 8.1: Example of use

SIMPLE SELECTION SORT

Throughout this topic, we will focus on four types of sorting. Figure 8.2 below shows there are four types of sorting i.e simple selection sort, quick sort, linear insertion sort and bubble sort.

Figure 8.2: Types of sorting

Give attention to each type of sorting from the aspects of:

(a) The way to use it.

(b) Its implementation in programming.

(c) The differences between each sorting

8.1

Page 106: Data Structure

TOPIC 8 SORTING 112

Let us firstly fully focus on simple selection sort. Simple selection sort is the easiest method of sorting. In this method, we will choose the smallest or biggest in a list and place it on the most appropriate position. In Figure 8.3, the following list is given.

Figure 8.3: An unsorted list

Consider the following list that is to be sorted in ascending order. There are 7 numbers that are labelled with the respective position.

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

Step 1: Compare element 1 with elements 2 to 7. Find the smallest element compared to 1. Element 3 is smallest. Therefore, we change the position of element 1 with element 3.

Step 2: Compare element 2 with elements 3 to 7. Element 2 is the smallest, so no changing of positions of elements is necessary.

Step 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

Step 4: Repeat this process of comparing and changing places as per step 1 to 6 as step 3 above.

Step 7: The result that is obtained is a sorted list of numbers.

Simple selection sort is a selection sort because the process of selection occurs and exchanging of positions also occurs.

Page 107: Data Structure

TOPIC 8 SORTING ! 113

Figure 8.4: Steps for sorting in ascending order

Page 108: Data Structure

TOPIC 8 SORTING 114

8.1.1 Implementation Using Arrays

The following is an example of a function for simple selection sort that is implemented using arrays, where the list of numbers that is to be sorted is the elements of an array.

void SelectSort (int x[], int n)

{

int i, indx, j, large;

indx = 0;

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

{

smallest = x[i];

for (j = 1; j < n; j++)

if (x[j] < smallest)

{

smallest = x[j];

indx = j;

}

x[indx] = x[i];

x[i] = smallest;

}

}

8.1.2 Simple Selection Sort Algorithm Efficiency

The execution time is basically represented by the form of O(f(n)) where n is the number of data elements. For simple selection sort, the execution time depends on the time to compare the values to determine their positions. (n -1) + (n – 2) + . . . + 2 + 1 = n(n-1)

2

= O(n2)

Check 7(7-1)= 21

2 (n - 1)+(n - 2)+(n - 3)+(n - 4)+(n - 5)+(n - 6) = 6 + 5 + 4 + 3 + 2 + 1

21

How about it? Do you understand? In brief:

1. You need to compare the first element with the rest.

2. You need to know when and how to change the position of the element.

Page 109: Data Structure

TOPIC 8 SORTING ! 115

Let us now look at the next type of sorting. Perhaps with another type of sorting, you can make a comparison with the previous sorting technique.

LINEAR INSERTION SORT

In the 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 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 seen in Figure 8.5. 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 a sorted list. Consider the data following data elements with the assumption that the first element is the element for a sorted sub-list. In the first loop, the first two elements are compared. It is found that the 2nd element is smaller than the 1st element, so, we shift the first element to the right to insert the second element. Now (step 2), the second element has become the first element of the sorted sub-list. We then compare the 3rd element with the elements in the sub-list. Since element 3 is the smallest compared to the elements of the sub-list, we then shift number 33 and 67 in order to insert number 21. And the process repeats where small numbers are inserted in the correct positions and the elements to the right will be shifted to the right. This can be pictured in Figure 8.5 below.

8.2

Page 110: Data Structure

TOPIC 8 SORTING 116

Figure 8.5: Steps for linear insertion sort

Page 111: Data Structure

TOPIC 8 SORTING ! 117

8.2.1 Implementation Using Arrays

The following is an example of a function for linear insertion sort that is implemented using arrays.

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;

}

}

8.2.2 Linear Insertion Sort Algorithm Efficiency

The worst case scenario for the linear insertion sort when a list is sorted is in the inverted sequence that is required.

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

2 + 3 + . . . + n = n(n-1)/2-1 So, the efficiency of the linear insertion sort algorithm is O(n2).

Page 112: Data Structure

TOPIC 8 SORTING 118

QUICKSORT

The quick sort is an in-place, divide-and-conquer, massively recursive sort and a very efficient and fasted sorting algorithm in practice. Quicksort has two phase:

(a) Participation phase it works out where to divide the work

(b) Sort phase simply sort the two smaller problems that are generated in the partition phase.

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 that the pivot.

(d) Recursively repeat the algorithm for both halves of the original array. This method is based on frequently changing elements similar to the bubble sort method. In short, in this quick sort, a value is known as the 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 sub-list on the left and the sub-list on the right of the pivot. For example, we use the same data used in the sorting method above. This is to show to you the difference in efficiencies of sorting methods. Step 1 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 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 8.6 will clarify this first step.

8.3

Page 113: Data Structure

TOPIC 8 SORTING ! 119

Figure 8.6: Step 1(a) for quick sort

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 8.7 as follows.

Figure 8.7: Step 1(b) for quick sort

Step 2 We repeat the search from the right of the list to find a value smaller that 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. Figure 8.8 illustrates this step.

Page 114: Data Structure

TOPIC 8 SORTING 120

Figure 8.8: Step 2(a) for quick sort

Now, the pivot value is between the left sub-list and right sub-list. Look at Figure 8.9 for evidence.

Figure 8.9: Step 3(a) for quick sort

Step 3 We repeat step 1 for the left sub-list, 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 8.10 shows illustrates this.

Page 115: Data Structure

TOPIC 8 SORTING ! 121

Figure 8.10: Step 3(a) for quick sort

Since the index value for number 21 is smaller than the index value for 50, so we exchange number 21 with the pivot value. Look at Figure 8.11 for evidence of this.

Figure 8.11: Step 3(b) for quick sort

Repeat the search operation and exchanges for the left sub-list for the pivot value of 67, also for the left and right sub-lists for the pivot value of 49. Look at the following Figure 8.12 to explain all the steps for quick sort fully.

Page 116: Data Structure

TOPIC 8 SORTING 122

Figure 8.12: Step 3(c) for quick sort

Page 117: Data Structure

TOPIC 8 SORTING ! 123

8.3.1 Implementation Using Arrays

We can write the quick sort method as a recursive function using arrays, as follows:

void QuickSort (ELEMENTYPE x[ ], int start, int end)

{

int pos;

if (start < end)

{

Partition(x, start, end, &pos);

QuickSort(x, start, pos-1);

QuickSort(x, pos+1, end);

}

}

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. void Partition (ELEMENTTYPE x[], int start, int end, int *pos)

{

int left, right;

ELEMENTTYPE pivot;

pivot = x[start];

left = start;

right = end;

while (left < right)

{

while (x[right] > pivot)

right = right - 1;

while (x[right] <= pivot) && (left < right)

left = left + 1;

if (left < right)

Exchange(&x[left], &x[right]);

}

*pos = right;

x[start] = x[*pos];

x[*pos] = pivot;

}

Page 118: Data Structure

TOPIC 8 SORTING 124

8.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). The processing time for normal cases is O(n log2n) 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 sub-lists. For sub-lists with less than 20 elements, this quick sort method is not so efficient.

BUBBLE SORT

This sorting performs adjacent element exchanges until all elements are arranged according to the requirements. The following is the implementation of the bubble sort:

/* Input a list with n elements in an array */

1. Set number = n-1

2. Repeat

2.1 Set end = 0;

/* end is the last location that was exchanged */

2.2 For i = until number -1 is performed

2.2.1 if x[i] > x [i + 1] then

i. exchange x[i] with x[i + 1]

ii. set end = 1

2.2.2 set number = end – 1

Until number = 0

In order to understand the above algorithm, consider the following number list:

8.3

Page 119: Data Structure

TOPIC 8 SORTING ! 125

Loop 1

Page 120: Data Structure

TOPIC 8 SORTING 126

Loop 2

Loop 3

Page 121: Data Structure

TOPIC 8 SORTING ! 127

Loop 4

Loop 5

Loop 6

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. For each loop, the largest value is brought to the end of the list. In the above example, even though in loop 2 the list seems to be already sorted, this algorithm still continues until loop 6.

Page 122: Data Structure

TOPIC 8 SORTING 128

SORTING APPLICATION

The following is a complete example of a simple selection sort that is implemented using arrays. You can modify this program by adding another sorting method as a programming exercise.

/* Declarations of function prototype */

void ReadData(int x[], int n);

void SelectSort(int x[], int n);

main()

{

int i, no = 5;

int data[no];

int selection;

/* Read Data */

printf(“Read Data: \n”);

ReadData(data, no);

/* Select Sort */

printf(“Select Sort: \n”);

SelectSort(data, no);

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

printf(“\ndata[%d] = %d”, i, data[i]);

}

void ReadData(int x[], int n)

{

int i;

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

{

printf(“data[%d]”, i);

scanf(“%d”, &x[i]);

}

}

/* Type the full function for the “SelectSort” function in

Section 8.1.1 here */

8.5

Page 123: Data Structure

TOPIC 8 SORTING ! 129

Sorting is the process of arranging data in either ascending or descending order.

This topic has exposed you to four types of sorting i.e simple selection sort, quick sort, linear insertion sort, and bubble sort.

You also should be able to evaluate the strengths and weaknesses of each sorting technique.

In general, all sorting procedures will produce the same results and the only thing that differentiates them is the aspect of efficiency.

Given the function SortData as shown below. Show step by step how the list {25, 57, 48, 37, 12} is sorted using the function below:

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;

}

}

(Use your own paper to answer this exercise)

EXERCISE 8.1

Page 124: Data Structure

TOPIC 8 SORTING 130

Bubble Sort Linear Insertion Sort

Quick Sort Simple Selection Sort

Page 125: Data Structure

INTRODUCTION We have learned about sorting elements in data structures. The efficiency of a sorting technique depends on the position of elements in the list that is to be sorted. The efficiency of searching techniques also depends on the position of element that is to be searched. The searching technique operates efficiently in sorted lists. Searching is a process of finding an element or data that is required in a data structure. In this topic we will look at only two search methods, which are sequential search and binary search.

BASIC METHODS OF SEARCHING

We use the search operation to find a data that is located in a file. That data could be a record or a record field. A record is a single or group of fields in a record. One of the fields is nominated as the record key, which is a unique signature for that record, for example, your IC or MyKad, whereas 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 the internal key. A key that is kept outside of the record is named the external key. For the external key cases, we use pointers to refer to the matching record.

9.1

TTooppiicc 99 Searching

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.

LEARNING OUTCOMES

Page 126: Data Structure

TOPIC 9 SEARCHING

132

There are two types of keys:

(a) Primary key, which is a key field with a unique value for each record. There are no two records that can have the same key value, for example your MyKad, where each individual will have a different MyKad.

(b) Secondary key, which is a key field that is not unique to the record. There can be two or more records with the same key. For example the name of a state, where there can exist two or more people that originate from the same state.

The 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. For successful searches, we call this an access operation. For the operation to delete a key value, it is called the 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

(c) Table or File Search Technique

(d) Binary Tree Search Technique (which will be reviewed in the next topic)

9.1.1 Sequential Search

This technique is the simplest but not so efficient. This technique is applied to records that are arranged using arrays or linked lists. Searching begins with the first record and this is done sequentially until the data is found. For example, observe the following: Say A[1], A[2], ... , A[n] are arrays that consists of n keys Ki; (1 <= i <= n) that are different.

K1 K2 K3 K4 ... Kn A[1] A[2] A[3] A[4] ... A[n]

Page 127: Data Structure

TOPIC 9 SEARCHING

133

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 i value

End_for

9.1.2 Binary Search

In binary search, what needs to be found is the position for a K search key in a table. The search key is compared to a key in the middle of the table. The algorithm 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 not, the search process continues for the elements below the middle key in the table.

For example, find search key 39.

Number of data = 10 Initial value = 0 (array index value starts from 0) Final value = 9

This question is based on the sequential search algorithm that is given above. If the value that is being searched is in the first location (index = 0), will the search continue until the end of the array?

EXERCISE 9.1

Page 128: Data Structure

TOPIC 9 SEARCHING

134

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

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).

Round 2 The result of round 1 found that the focus location for the search is on the right of the middle key, which are the locations that goes toward 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

20 < 39

40 < 39

Page 129: Data Structure

TOPIC 9 SEARCHING

135

In this round, we found that the value of the search key (39) is less that the middle key (40), therefore, the focus of the search will only by 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 Round 3 The result of the second round 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 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

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 location k(5). Therefore, our search is successful. Round 4 From the result of round 3, the search location focus is now on the right of the middle key, which are the locations leading toward the end. Here, we need to change the initial value of the location to the left of the milddle key value, which is the middle minus one.

Change final value,initial = middle + 1 = 6 + 1 = 7

25 < 39

Page 130: Data Structure

TOPIC 9 SEARCHING

136

We calculate for the middle value again. Middle value = (initial + end) / 2

= (7 + 6)/2 =13 / 2 = 6

Test the middle key with the search key. Middle key = k(6) = 39

Thus, our search is successful. Answer the exercise below to help you understand this topic.

SEARCH APPLICATION

The following is a complete example program of a sequential search. This program will search a list to find the required value. /* Declaration of function prototype */ int SequentialSearch(int list[], int leastIndx, int target) /* Main program */ main() {

/* Declaration of local variables */ int i, data [12]; int num, found; /* Enter data into an array of size 12 */ for (i = 0; i < 12; i++) {

printf(“Enter data %d: “, i); scanf(“\n%d”, &data[i]);

}

9.2

1. Can the binary search technique be used for searching a list that is not

sorted like (say you want to search for 22).

4 21 36 14 62 91 8 22 7 81 77 10 2. If you are required to search the list of numbers shown above, what

would you need to do first?

EXERCISE 9.2

Page 131: Data Structure

TOPIC 9 SEARCHING

137

/* Search Operation */ printf(“What number do you want to search? : “); scanf(“\nd%”, &num); found = SequentialSearch(data, i, num); printf(“Found number %d at the index %d\n”, num, found);

} /* Function to search list */ int SeaquentialSearch (int list[], int lastIndx, int target) {

int indx;

for (indx = 0; indx <= lastIndx; indx++) {

if (target == list[indx]) return (indx);

} }

1. You are given a list of integers as follows:

4 7 8 10 14 21 22 36 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 above list of numbers 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 step by step the process

that is done to find number 22.

(Use your own paper to answer these questions)

EXERCISE 9.3

Page 132: Data Structure

TOPIC 9 SEARCHING

138

• Now you have learned the search techniques that can be applied in solving related problems. What is given in this topic is only the algorithm to search and not the actual search program. This is because the algorithm is just in general and gives an idea of how a search is to be performed. Modifications can be done on those algorithms.

Binary Search Primary Key

Secondary Key Sequential Search

Page 133: Data Structure

INTRODUCTION

In the previous topics, we looked at linear type data, which includes lists, linked lists, stacks and searches. In this topic, we shall look at the tree data structure which is different from the other data structures previously discussed. Elements in a tree are arranged in a hierarchical structure.

NOTE: Make sure that you really understand the linked list topic and the concept of pointers that have been learnt before this before you proceed further into this topic.

TTooppiicc 1100 Trees

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

1. Explain about trees;

2. Differentiate between binary trees and binary search trees;

3. Describe the linked binary tree data structure;

4. Describe the linked data structure and the operations that can be performed on binary search trees; and

5. Develop C programming containing tree data structures to solve a programming problems.

LEARNING OUTCOMES

Page 134: Data Structure

TOPIC 10 TREES 140

GENERAL STRUCTURE OF TREES

Trees are a structure that consists of nodes that are linked with directed pointers. An example of a tree is shown in the Figure 10.1 and Figure 10.2.

Figure 10.1: Example of a tree

Figure 10.2: Example of a tree

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 the root. In Figure 10.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 10.1, node O and W are the child nodes for node P, while node P

10.1

Page 135: Data Structure

TOPIC 10 TREES ! 141

is the parent node for nodes O and W. Nodes with the same parent are called siblings. Nodes O and W in Figure 10.1 are siblings. Nodes that do not have any child nodes are called leaves. So, nodes G, O, and W in Figure 10.1 are leaves. The directed pointers that link one node to another are called the branch. The depth of the tree refers to the level value that is the highest in the tree. For Figure 10.1, the depth of the tree is 3. There are two types of trees that are important:

(a) Binary Tree

(b) Binary Search Tree (BST)

BINARY TREES

A binary tree is a tree in which no node can have more than 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. The Figure 10.3 shows an example of a Binary Tree. A binary tree is a tree structure where each node has not more than 2 child nodes. The example below shows a binary tree that has character in each node. The maximum number of nodes in a binary tree with a depth of K is 2k-1 for K >=1.

Figure 10.3: Example of a binary tree

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 no longer in the scope of this topic.

10.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 had two pointers that

10.2

Page 136: Data Structure

TOPIC 10 TREES 142

each points to its left and right child node. Look at the following definition of the binary tree data structure: One binary tree node can be pictured as shown in Figure 10.4 below:

Figure 10.4: An example of a binary tree node

Each node has two pointers or left_child and right_child and each will point to a left sub-tree and a right sub-tree. The data in the node can contain any format of data, like integers, floats, characters, Boolean values or strings.

BINARY SEARCH TREES (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 the 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 10.5 shows a binary search tree.

10.3

typedef struct BinaryTree { int data; struct BinaryTree *left_child; struct BinaryTree *right_child; } BINARY_TREE;

BINARY_TREE *tree;

Page 137: Data Structure

TOPIC 10 TREES ! 143

Figure 10.5: An example of a BST

The BST data structure is as follows: 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

(e) Delete node in BST The following sections will discuss these operations. The programming codes that are used in the following sections have been modified from the book Struktur Data Menggunakan C by (Marini Abu Bakar, 1998).

typedef struct BinaryTree {

int data;

struct BinaryTree *left_child;

struct BinaryTree *right_child;

} BINARY_TREE;

BINARY_TREE *BST;

Page 138: Data Structure

TOPIC 10 TREES 144

10.3.1 Creating BSTs

The CreateBST only assigns a reference to BST as NULL. We will give the NULL value as the value to refer the BST.

10.3.2 Searching BSTs

As was discussed in Section 10.3, each BST node has a value that is greater than its left child nod, 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. To achieve this, 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:

10.3.3 Inserting Nodes in BSTs

The node insertion operation in BST structures require the node to be inserted at a suitable position for preserving the BST characteristics. Once a data item has been inserted in a BST, it cannot be re-inserted into a BST. This process is illustrated in the following pseudo-code:

1. Search BST for node containing the item

2. If the node exists

2.1 display message „node exists‰

void CreateBST (BST **tree){ *tree = NULL;

}

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; }

Page 139: Data Structure

TOPIC 10 TREES ! 145

2.2 end

3. If not

3.1 insert data/item at a suitable position (as a left/right child)

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 the following Figure 10.6.

Figure 10.6: An example of InsertBST

Let us suppose that we want to insert the character A in the above BST. To insert this data, we will begin with the root node that is referred to by pointer p2 and compare A with the data content in the root node. Since A < M, we then move down the right sub-tree. The pointer b points to the parent node while the current node is being evaluated.

Page 140: Data Structure

TOPIC 10 TREES 146

Figure 10.7: An example of InsertBST

Figure 10.8: An example of a InsertBST

Page 141: Data Structure

TOPIC 10 TREES ! 147

Figure 10.9: An example of a InsertBST

Then we compare A with C. Since A < C then we move to the left sub-tree 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. Figure 10.6 until 10.9 shows this entire process. The InsertBST function for performing the insertion function is given below. That particular function will receive a BST and the data value that needs to be inserted. Then, the BST will be searched to determine whether the node exists and the insertion point. If the node with the item exists, an error message will be displayed. If otherwise, the node will be inserted in a suitable position.

Page 142: Data Structure

TOPIC 10 TREES 148

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.

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;

}

}

}

Page 143: Data Structure

TOPIC 10 TREES ! 149

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, because the succession of data insertion has changed.

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;

}

1. Draw a BST produced when data containing 3, 4, 5, 6, 1, 2, is inserted one by one.

2. Draw a BST produced when data containing 5, 1, 3, 4, 2, 6, is inserted one by one.

3. What is the conclusion that you can make about the BST produced from questions (1) and (2) above?

EXERCISE 10.1

Page 144: Data Structure

TOPIC 10 TREES 150

10.3.4 Traversing BSTs

The traversing BST operation means an operation to move within the binary tree by visiting each node once. A recursive approach is used for this operation. There are three types of important traversals that will be touched upon in this section, which 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

(iii) Visit the tree on the right If the BST in Figure 10.10 is traversed in this way, the output that will be produced would be:

5 8 9 10 16 18 20

Look at the in-order traversal that produces an ascending order number.

Figure 10.10: BST tree

Page 145: Data Structure

TOPIC 10 TREES ! 151

The function to perform this in-order traversal is as follows:

(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

(iii) Visit tree on the right

If the BST in Figure 10.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 as follows:

(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

(iii) Get data from node

void inOrder(BST *j){ if (j){

inOrder(j -> left_child); printf(„\n%d‰, j -> data); inOrder (j -> right_child);

} }

void preOrder(BST *j){ if (j){

printf(„\n%d‰, j -> data); preOrder(j -> left_child); preOrder (j -> right_child);

} }

Page 146: Data Structure

TOPIC 10 TREES 152

If the BST in Figure 10.10 is traversed using the post-order traversal, the output produced would be:

5 9 8 16 20 18 10

The function to perform the post-order traversal is as follows:

10.3.5 Deleting Nodes in BSTs

This operation involves three node conditions:

(i) Node is leaf (no child nodes)

(ii) Node has 1 child node

(iii) Node has 2 child nodes Condition 1: Node to be Deleted is Leaf Look at the BST below. The node ÂiÊ needs to be deleted, pointer p points to the new node that will be deleted and pointer f is the parent of that node.

The algorithm is: 1. Set right_child for f to NULL

2. Free p

void postOrder(BST *j){ if (j){

postOrder(j -> left_child); postOrder (j -> right_child); printf(„\n%d‰, j -> data);

} }

Page 147: Data Structure

TOPIC 10 TREES ! 153

After deleting node ÂiÊ, the BST is as follows:

Condition 2: Node to be Deleted has 1 Child Node Nod h needs to be deleted and has 1 child node.

The algorithm is as follows:

1. set parent -> left_child = x -> left_child;

2. Free x

Page 148: Data Structure

TOPIC 10 TREES 154

Condition 3: Node to be Deleted has 2 Child Nodes

Referring to the new BST below, let us suppose node ÂnÊ needs to be removed.

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Ê.

3. Delete node ÂoÊ (node ÂoÊ has no child according to Condition 1).

Page 149: Data Structure

TOPIC 10 TREES ! 155

BST APPLICATION

The following program shows an example of using BST. The aim of the program is to read 10 integer numbers from the user and insert them in a BST. Then, the program will display the content of the BST in the form of in-order traversal, pre-order traversal, and post-order traversal.

#include <stdio.h>

#include <stdlib.h>

typedef struct BinaryTree {

int data;

struct BinaryTree *left_child;

struct BinaryTree *right_child;

} BINARY_TREE;

typedef BINARY_TREE BST;

void CreateBST (BST **tree);

void InsertBST (BST **p2, int item);

BST *NewBSTNode (int item);

void inOrder (BST *j);

void preOrder (BST *j);

void postOrder (BST *j);

void main() {

int a, data;

BST *bst; // pointer definition for the BST

10.4

Consider the BST below.

(a) Show the changes in BST when the nodes containing values 5, 60, 80, 90, 65, and 75 are inserted.

(b) What BST is formed if nodes 30, 60, and 70 are deleted from the BST that was produced in (a) above?

EXERCISE 10.2

Page 150: Data Structure

TOPIC 10 TREES 156

CreateBST(&bst);

for (a = 1; a < 10; a++) {

printf (“\nEnter a number : “)’

scanf(”%d”, &data);

InsertBST (&bst, data);

}

printf(“In-order traversal : \n”);

inOrder(bst);

printf(“Post-order traversal : \n”);

postOrder(bst);

printf(“Pre-order traversal : \n”);

preOrder(bst);

}

/* put in the implementation for the functions here*/

EXPRESSION TREES

Expression trees are binary trees that are used to represent arithmetic expressions. Its general form is:

Operand 1 Operator Operand 2

The operator is the middle node (root) and operand 1 and operand 2 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 )

10.5

Page 151: Data Structure

TOPIC 10 TREES ! 157

So the expression tree formed looks like:

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. 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 ) ) + 1 ) Postfix expression (LRN): A B C * / D + (disregard parentheses) Prefix expression (NLR): + / A * B C D (disregard parentheses)

In this topic, we looked at the tree data structure. Trees are largely used in applications. This includes the development of compilers and gaming software. Trees give the facility to easily store and access data effectively.

There are several other forms of trees based on the BST that have been developed, for example the AVL tree. However, this AVL tree is beyond the scope of the syllabus for this course.

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

EXERCISE 10.3

Page 152: Data Structure

TOPIC 10 TREES 158

Binary Tress Binary Search Trees In-order Traversal

Post-order Traversal Pre-order Traversal