Sunteți pe pagina 1din 152

Table of Contents

Course Guide Topic 1 vi - xiii Arrays 1.1 Concept of Arrays 1.2 One-dimensional Arrays 1.2.1 Declaring Arrays 1.2.2 Initialising Array Elements 1.2.3 Assigning and Accessing Array Elements 1.2.4 Operations on Array Elements 1.2.5 Arrays and Functions 1.2.6 Case Study: Yearly Rainfall Summary 1.3 Two-dimensional Arrays 1.3.1 Declaring Arrays and Initialising Array Elements 1.3.2 Assigning and Accessing Array Elements 1.3.3 Arrays and Functions 1.3.4 Case Study: Two-dimensional Matrix Operations Summary Key Terms Characters and Strings 2.1 Basic Concepts of Characters and Strings 2.1.1 Declaring and Initialising String Values 2.1.2 String Referencing 2.1.3 Input and Output Using Standard Functions: scanf() and printf() 2.2 Standard Character and String Functions 2.2.1 Evaluation and Manipulation Functions for Characters 2.2.2 Input and Output Functions for Characters and Strings 2.2.3 Manipulation Functions for Strings 2.3 String Arrays 2.4 Character and String Applications Summary Key Terms 1 1 2 2 4 6 10 13 16 19 19 21 23 23 26 26 27 27 29 30 31 33 33 34 36 37 39 41 41

Topic 2

iv

TABLE OF CONTENTS

Topic 3

Structures 3.1 Concepts of Structures 3.2 Declaring and Initialising Structure Elements 3.3 Referencing Structure Element 3.4 Structure Type Arrays 3.5 Structure Type Structure 3.6 Structures and Functions 3.6.1 Return Value Functions 3.7 Structure Applications 3.8 typedef Construction Summary Key Terms Pointers 4.1 Pointer Basics 4.2 Parameter Passing Using Pointers 4.3 Pointers and Arrays 4.3.1 Pointers and Strings 4.3.2 Pointer Type Arrays 4.4 Dynamic Memory 4.5 Pointers and Structures Summary Key Terms Lists and Linked Lists 5.1 Lists 5.1.1 Basic List Operations 5.1.2 Implementations of Lists Using Arrays 5.2 Linked Lists 5.2.1 Basic Linked List Operations 5.2.2 Implementation Using Pointers 5.2.3 Application Using Linked Lists Summary Key Terms

42 42 43 46 48 50 52 53 54 56 57 57 58 58 61 64 64 65 66 68 70 70 71 72 72 73 73 74 75 82 85 85

Topic 4

Topic 5

TABLE OF CONTENTS

Topic 6

Stacks 6.1 Basic Stack Operations 6.2 Implementation Using Arrays 6.2.1 Declaring Data Structures 6.2.2 Creating Stacks 6.2.3 Checking Empty Stacks 6.2.4 Checking Full Stacks 6.2.5 Inserting Items into Stacks 6.2.6 Removing Items from Stacks 6.2.7 Stack Application: Separating Even and Odd Numbers 6.2.8 Stack Application: Reverse Polish Notation Summary Key Terms Queues 7.1 Basic Queue Operations 7.2 Implementation of Queue Data Structure 7.2.1 Declaring Data Structures 7.2.2 Creating Queues 7.2.3 Checking Empty Queues 7.2.4 Checking Full Queues 7.2.5 Inserting Items into Queues 7.2.6 Removing Items from Queues 7.2.7 Queue Application Summary Key Terms Sorting 8.1 Simple Selection Sort 8.1.1 Implementation Using Arrays 8.1.2 Simple Selection Sort Algorithm Efficiency 8.2 Linear Insertion Sort 8.2.1 Implementation Using Arrays 8.2.2 Linear Insertion Sort Algorithm Efficiency 8.3 Quicksort 8.3.1 Implementation Using Arrays 8.3.2 Quick Sort Algorithm Efficiency 8.4 Bubble Sort 8.5 Sorting Application Summary Key Terms

86 87 88 89 89 89 90 90 90 91 92 96 97 98 99 100 103 104 104 104 105 105 106 109 109 110 111 114 114 115 117 117 118 123 124 124 128 129 130

Topic 7

Topic 8

vi

TABLE OF CONTENTS

Topic 9

Searching 9.1 Basic Methods of Searching 9.1.1 Sequential Search 9.1.2 Binary Search 9.2 Search Application Summary Key Terms Trees 10.1 General Structure of Trees 10.2 Binary Trees 10.2.1 Data Structure for Binary Tree 10.3 Binary Search Trees (BST) 10.3.1 Creating BSTs 10.3.2 Searching BSTs 10.3.3 Inserting Nodes in BSTs 10.3.4 Traversing BSTs 10.3.5 Deleting Nodes in BSTs 10.4 BST Application 10.5 Expression Trees Summary Key Terms

131 131 132 133 136 138 138 139 140 141 141 142 144 144 144 150 152 155 156 157 158

Topic 10

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 Understanding the course content and preliminary discussions Reading 3 units of text at the rate of 20 hours per unit of text Attending 5 tutorial sessions, 2 hours per session Attending online discussion sessions Completing one assignment, 15 hours per assignment Revision Total

Hours 4 60 10 15 15 16 120

COURSE GUIDE

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. 2. Apply a data structure concept that is suitable for its application, and 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.

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: Online Participation: Final Examination: TOTAL: 45% 5% 50% 100%

Examples of the examination questions can be obtained from the OUM website.

T o p ic

1 X Arrays

LEARNING OUTCOMES
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 twodimensional arrays; and 3. Solve programming problems using arrays that involve functions.

X 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 twodimensional 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.

1.1

CONCEPT OF ARRAYS

Do you still remember variables? Can you compare the concept of variables and 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.

X TOPIC 1 ARRAYS

Why do we need arrays in our programming? This question can be answered by giving an example. Lets 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, wouldnt it be easier if you could manage a single file with 12 compartments? Let us relate this scenario to computer programming. Lets 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.

1.2

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 array_name number_of_elements -

type of data that will be stored in the array the name of the array 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.

TOPIC 1 ARRAYS W 3

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

X TOPIC 1 ARRAYS

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

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

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

EXERCISE 1.1
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

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

TOPIC 1 ARRAYS W 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 } ;

ACTIVITY 1.2
Draw a diagram that illustrates the memory location for the declaration of the digit2 array.

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

EXERCISE 1.2
Write a suitable array declaration for each of the following: (a) (b) 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. 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

X TOPIC 1 ARRAYS

1.2.3

Assigning and Accessing Array Elements

We have looked at the array index that enables us to differentiate every element in an array. The array index also enables us to refer to the 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 */

TOPIC 1 ARRAYS W 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]; Y[0] = 1; Y[1] = Y[0] Y[2] = Y[1] Y[3] = Y[2] Y[4] = Y[3] /* /* /* /* /* /* array declaration of 5 elements */ assign 1 to Y[0] */ assign Y[0] * 2 expression to Y[1] assign Y[1] * 3 expression to Y[2] assign Y[2] * 4 expression to Y[3] assign Y[3] * 5 expression to Y[4]

* * * *

2; 3; 4; 5;

*/ */ */ */

X TOPIC 1 ARRAYS

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 use int 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.

TOPIC 1 ARRAYS W 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

SELF CHECK 1.1


Think about the assignment given below. Look at the comments as a guide. 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]; */ int i = 0, j = 1; S[i] = S[j] = S[j+1] S[j*3] S[j*4] 8; S[i] + 5; = S[i] * S[j]; = S[i+2]; = S[j*2]; /* declare array with 5 elements

/* /* /* /* /*

assign assign assign assign assign

8 to S[0] */ S[0]+5 to S[1] */ S[0]* S[1] to S[2]*/ S[2] to S[3]*/ S[2] to S[4]*/

10 X TOPIC 1 ARRAYS

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

EXERCISE 1.3
1. Referring to the arrays that are declared below, state the values that are assigned to each following array element. (a) (b) (c) 2.
int abc[6] = {0, 2, 4, 6, 8, 10}; float c[5] = {2.0, 0.5, 1.2, 0.3}; int xyz[10]= {5, 10, 0, 10, 5, 0, 0};

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}; M[2] = M[1] * 3; M[3] = M[2] * 1; M[4] = M[0] * 2 * 3;

(b)

int R[4], I = R[i-1] = 8; R[i] = R[i-1] R[i+1] = R[i] R[i+2] = R[i]

1; * 8; + 10; * 5;

1.2.4

Operations on Array Elements


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

In C, we cannot implement an operation for the whole array. This means that, if a and b are of the same arrays (having the same data type, size, and dimension), operations like assignment, comparison and the like should be performed element by element. This is usually done by using the loop structure, where each loop will perform an operation on a single array element. The number of loops is usually the same as the number of elements in the array. Look at the following example. The program code shows how to copy the contents of array A to array B.

TOPIC 1 ARRAYS W 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]); } } Using a constant to size arrays is good programming practice.

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;

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.

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

12 X TOPIC 1 ARRAYS

Program 1.4 #include <stdio.h> main()

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.

int a[3] = {11, 12}, float x[2], y[4];

b[ ] = {44, 55, 66}, i;


Reading two array elements.

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]);

Using a loop to fill all of the elements for (i=0; i<4; i++) of the y[] array. { y[ i ] = i*100.0; printf(y[%1d] = %.2f\n, i, y[i]); }

return 0; }

SELF CHECK 1.2


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

Do the following exercise to help you in your understanding.

TOPIC 1 ARRAYS W 13

EXERCISE 1.4
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]);

1.2.5

Arrays and Functions

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

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.

14 X TOPIC 1 ARRAYS

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) { : }

x x

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 []); void main(void) { int number[10]; int i; /* function prototype */

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

TOPIC 1 ARRAYS W 15

void numberSort(int num[]) { int j, k, temporary;

/* function definition */

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

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

EXERCISE 1.5
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.

16 X TOPIC 1 ARRAYS

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 Total Rainfall Jan 190 Feb 195 Mac 268 Apr 307 May 235 June 144 July 105 Aug 193 Sep 215 Oct 223 Nov 235 Dec 208

Based on the given information, you are required to write a program that can produce the following summary: (a) (b) (c) (d) Total yearly rainfall Average rainfall for 2001 Wettest month Driest month

Data Design Input:


rainfallDistribution[12] : integer type array

Output:
totalRainfall averageRainfall wettestMonth driestMonth

: Integer type : Real type : Integer type : Integer type

Solution Design The structural chart for this program is as follows in Figure 1.6.

TOPIC 1 ARRAYS W 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); }

18 X TOPIC 1 ARRAYS

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;

TOPIC 1 ARRAYS W 19

case case case case case case case

6: 7: 8: 9: 10: 11: 12:

printf(June); break; printf(July); break; printf(August); break; printf(September); break; printf(October); break; printf(November); break; 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);

1.3

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

data_type array_name number_of_row number_of_column

type of data stored in the array name for the array a positive integer that represents the rows of the array 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.

20 X TOPIC 1 ARRAYS

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

TOPIC 1 ARRAYS W 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

ACTIVITY 1.6
Array From the Twilight Zone in the website http://home.twcny.rr.com/amanthoan/cweb/dimary.html. Look at the example of two-dimensional array used. In order to ensure that you understand what has been taught, answer the following questions.

EXERCISE 1.6
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.

1.3.2

Assigning and Accessing Array Elements

In order to assign initial values or to access an array element in a twodimensional 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.

22 X TOPIC 1 ARRAYS

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]));

SELF CHECK 1.3


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]));

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

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

ACTIVITY 1.7
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

TOPIC 1 ARRAYS W 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 twodimensional 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

24 X TOPIC 1 ARRAYS

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

TOPIC 1 ARRAYS W 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); } }

26 X TOPIC 1 ARRAYS

An array is a data structure: (i) (ii) That consists of data items that are related 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

T o p ic

Characters and Strings

LEARNING OUTCOMES
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.

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.

2.1

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

28

TOPIC 2 CHARACTERS AND STRINGS

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:

EXERCISE 2.1
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) (c) (e)
% ABC /n

(b) (d) (f)

% abc Enter value :

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.

SELF-CHECK 2.1
Draw the memory space for the assignment:
char animal[] = {c, a, t, \0};

30

TOPIC 2 CHARACTERS AND STRINGS

Answer the following exercise to test your understanding.

EXERCISE 2.2
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.

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

TOPIC 2 CHARACTERS AND STRINGS

31

Answer the following exercise to test your understanding.

EXERCISE 2.3
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++; }

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); printf(%s, animal);

/* string input */ /* 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).

32

TOPIC 2 CHARACTERS AND STRINGS

ACTIVITY 2.1
In order to get a deeper understanding, please review Program 12.1 in the reference book Bahasa Pengaturcaraan C, 2000 Revised Edition. To ensure that you understand what has been studied, answer the following questions

EXERCISE 2.4
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

TOPIC 2 CHARACTERS AND STRINGS

33

2.2

STANDARD FUNTIONS

CHARACTER

AND

STRING

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 int isdigit (int c) int isalpha (int c) int islower (int c) int isupper (int c) int tolower (int c) Function Description Returns the true value, if c is a digit and false (0) if otherwise Returns the true value, if c is a letter and false (0) if otherwise Returns the true value, if c is a lowercase letter and false (0) if otherwise Returns the true value, if c is an uppercase letter and false (0) if otherwise If c is an uppercase letter, tolower() will return its corresponding lowercase letter. If otherwise, tolower() will return the character without any changes. If c is a lowercase letter, toupper() will return its corresponding uppercase letter. If otherwise, toupper() will return the character without any changes.

int toupper (int c)

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.

34

TOPIC 2 CHARACTERS AND STRINGS

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.

TOPIC 2 CHARACTERS AND STRINGS

35

Table 2.2: Input and Output Functions for Characters and Strings in the stdlib.h Library Function Prototype int getchar (); int putchar (int c); Function Description Inputs the following character from the standard input device and returns the character as a value. 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. Prints the str string to the standard output device. Empties the file buffer.

int puts (char *str); int fflush (FILE *file);

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.

ACTIVITY 2.2
Refer to Program 12.3 from the book Bahasa Pengaturcaraan C, 2000 Revised Edition for an example of the application of the above standard functions. To ensure that you understand this topic, answer the following questions:

EXERCISE 2.5
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.

36

TOPIC 2 CHARACTERS AND STRINGS

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[]); size_t strlen(char s1[]); char *strcat(char s1, char s2); int strcmp(char s1, char s2); Copies s2 string to s1 string and returns the value of s1. Returns the number of characters in s1 string. Copies s2 string on the end of s1 string. 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. 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.

char *strtok(char *s1, char *s2);

Answer the following to test your understanding.

EXERCISE 2.6
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.

TOPIC 2 CHARACTERS AND STRINGS

37

2.3

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.

38

TOPIC 2 CHARACTERS AND STRINGS

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.

ACTIVITY 2.3
As an additional exercise, look at Program 12.4 from the book

Bahasa Pengaturcaraan C, 2000 Revised Edition.

TOPIC 2 CHARACTERS AND STRINGS

39

Answer the following exercise to test your understanding.

EXERCISE 2.7
1. Write a program that can input 10 strings that are assigned to a string array. For each string, do the following: (a) (b) Change the first character and last character to capital letters. 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.

2.4

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.

40

TOPIC 2 CHARACTERS AND STRINGS

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

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

T o p ic

Structures

LEARNING OUTCOMES
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.

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.

3.1

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.

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 Account number Type of Account Name of account holder Savings balance Integer Character 30 character string Real Data Type

EXERCISE 3.1
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.

3.2

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

44

TOPIC 3 STRUCTURES

Where

struct_name
the requirements

data_*_definition the structure


struct account {

- name of the constructed struct that must fulfil naming a variable rule - data type definition for each element that forms

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 variable_name

- name for the structure that has been declared - name for the variable that represents the struct

Observe that struct account myAccount;

Structure name

Variable

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.

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

SELF-CHECK 3.1
Can you sketch the memory space for the account struct myAccount if it is initialised in the following way:
struct account 1998.88}; myAccount = {1234, S, Nadiah,

46

TOPIC 3 STRUCTURES

EXERCISE 3.2
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;

3.3

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 element in the structure that is need to be referred

data_definition -

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;

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

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

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

48

TOPIC 3 STRUCTURES

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

EXERCISE 3.3
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 customers telephone number is 011-333011

3.4

STRUCTURE TYPE ARRAYS


SELF-CHECK 3.2
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.

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.

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.

EXERCISE 3.4
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 OO.Java, revised edition Data Structures Using C : : 200033.00 200235.00 199822.00

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

50

TOPIC 3 STRUCTURES

3.5

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

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)

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

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

EXERCISE 3.5
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

52

TOPIC 3 STRUCTURES

2. Using the same declaration given in (1) above, write the statement for assigning the following information to the customer structure. (a) The customers name is Aisyah (b) The customers number is 1226 (c) The customers telephone number is 011-333011 (d) The customers address is No. 21, Jalan Kenangan (e) The post code is 02000 (f) The city is Seri Intan (g) The state is Darul Mulia

3.6

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

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

increaseDate (dte); printf(%d/%d/%d, dte.day, dte.month, dte.year); } void increaseDate(struct date t) { (t.year)++; /* the year element is increased */ }

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!

EXERCISE 3.6
1. Re-write the solution to Question 1 in Exercise 3.4 with the following modifications: void readInfo(struct (a) Write the function to read the book information. BOOK book[]);

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

54

TOPIC 3 STRUCTURES

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.

3.7

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 1222 1223 : AAAAABBBBBCCCCCDDDDDABCDA BBCCDDAABBCCDDAABBCCDDAAB 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.

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++) {

56

TOPIC 3 STRUCTURES

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

3.8

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.

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

T o p ic

Lists and Linked Lists

LEARNING OUTCOMES
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.

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.

72

TOPIC 5 LISTS AND LINKED LISTS

5.1

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

(b)

(c)

(d)

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:

EXERCISE 5.1
Let us assume that the data C is deleted. What will happen next?

5.2

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.

74

TOPIC 5 LISTS AND LINKED LISTS

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. 2. Data, which is the element in the list 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) (b) (c) (d) (e) Create empty linked list Test whether list is empty or not Traverse linked list Insert new item (add new item in linked list) Delete item from linked list To refresh your memory on the above operations, refer to topic 5.1.1. Basic List Operations.

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. Search linked list linearly A search is a process of finding a data item in a linked list.

(g)

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

76

TOPIC 5 LISTS AND LINKED LISTS

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. Lets just say that dataelement has a value of X.

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

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

(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

78

TOPIC 5 LISTS AND LINKED LISTS

(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. 2. 3. (i) Insert at the start of the list Insert between two nodes in the list (middle of list) Insert at the end of the list 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.

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.

80

TOPIC 5 LISTS AND LINKED LISTS

The algorithm for this operation is as follows: 1. 2. Set t->next = p->next 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:

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

82

TOPIC 5 LISTS AND LINKED LISTS

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

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

To understand this topic further, answer the following exercise.

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

Draw the change that occurs after this statement.


pList = pList->next;

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.

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

84

TOPIC 5 LISTS AND LINKED LISTS

EXERCISE 5.3
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)

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

T o p ic 6
LEARNING OUTCOMES

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.

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

TOPIC 6 STACKS

87

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

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

6.1

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

(ii)

(iii)

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

88

TOPIC 6 STACKS

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

EXERCISE 6.1
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.

6.2
1. 2.

IMPLEMENTATION USING ARRAYS

The stack data structure can be implemented in two ways, which are: Using pointers 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. 2. 3. Add D Add A Add H H A D 1. 2. Remove H Remove A

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.

90

TOPIC 6 STACKS

6.2.4

Checking Full Stacks


/* Check if the stack is full */ BOOL fullStk (STK *t) { (return (BOOL) (t->top >= MAXSTK)); }

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

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

TOPIC 6 STACKS

91

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

EXERCISE 6.2
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.

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;

92

TOPIC 6 STACKS

/* 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 Postfix Prefix M+N MN+ +MN

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,

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:

EXERCISE 6.3
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

(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. B. Create a stack Repeat until the end of the expression is read (a) (b) Read the next token in the expression 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.

94

TOPIC 6 STACKS

20 4 / 9 2 - + (postfix expression)

Insert 20 Insert 4

4 20

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

Now, 9 and 2 is pushed or inserted

2 9 5

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

7 5

TOPIC 6 STACKS

95

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

12

EXERCISE 6.4
Below are given postfix expressions. Using the postfix expression evaluation algorithm, evaluate the expressions. (a) (b) 21 3 / 10 35*26-* 73/*

EXERCISE 6.5
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);

96

TOPIC 6 STACKS

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

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.

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

T o p ic 7
LEARNING OUTCOMES

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.

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.

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

7.1

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

(b)

(c)

100

TOPIC 7 QUEUES

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

(e)

To test your understanding, answer the following exercise.

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

7.2

IMPLEMENTATION STRUCTURE

OF

QUEUE

DATA

Queue data structures can be implemented in two ways, which are (i) (ii) By using pointers 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.

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

102

TOPIC 7 QUEUES

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

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;

104

TOPIC 7 QUEUES

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

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

2.

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 {

106

TOPIC 7 QUEUES

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

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

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

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

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

108

TOPIC 7 QUEUES

EXERCISE 7.3
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)

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

Topic 8 X Sorting
LEARNING OUTCOMES
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.

X 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: Programs = Data Structures + Algorithms 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 students attendance list where he would arrange the name of the students beginning with

TOPIC 8 SORTING W

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

8.1

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) (b) (c) The way to use it. Its implementation in programming. The differences between each sorting

112

X TOPIC 8 SORTING

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. Compare element 2 with elements 3 to 7. Element 2 is the smallest, so no changing of positions of elements is necessary. 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 Repeat this process of comparing and changing places as per step 1 to 6 as step 3 above. The result that is obtained is a sorted list of numbers.

Step 2: Step 3: Step 4: Step 7:

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

TOPIC 8 SORTING W

113

Figure 8.4: Steps for sorting in ascending order

114

X TOPIC 8 SORTING

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. 2. You need to compare the first element with the rest. You need to know when and how to change the position of the element.

TOPIC 8 SORTING W

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.

8.2

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.

116

X TOPIC 8 SORTING

Figure 8.5: Steps for linear insertion sort

TOPIC 8 SORTING W

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

118

X TOPIC 8 SORTING

8.3

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) (b) Participation phase it works out where to divide the work Sort phase simply sort the two smaller problems that are generated in the partition phase.

The recursive algorithm consists of four steps: (a) (b) (c) (d) If there are one or less elements in the array to be sorted, return immediately. Pick an element in the array to serve as a pivot point. (Usually the leftmost element in the array is used). Split the array into two parts one with elements larger than the pivot and the other with elements smaller that the pivot. 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 sublist 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.

TOPIC 8 SORTING W

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.

120

X TOPIC 8 SORTING

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.

TOPIC 8 SORTING W

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.

122

X TOPIC 8 SORTING

Figure 8.12: Step 3(c) for quick sort

TOPIC 8 SORTING W

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

124

X TOPIC 8 SORTING

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 sublists with less than 20 elements, this quick sort method is not so efficient.

8.3

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:

TOPIC 8 SORTING W

125

Loop 1

126

X TOPIC 8 SORTING

Loop 2

Loop 3

TOPIC 8 SORTING W

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.

128

X TOPIC 8 SORTING

8.5

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

TOPIC 8 SORTING W

129

EXERCISE 8.1
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)

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.

130

X TOPIC 8 SORTING

Bubble Sort Linear Insertion Sort

Quick Sort Simple Selection Sort

T o p ic 9

Searching

LEARNING OUTCOMES
By the end of this topic, you should be able to: 1. Explain the basic search techniques; and 2. Apply two types of search techniques.

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

9.1

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.

132

TOPIC 9 SEARCHING

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

(b)

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) (b) (c) (d) Sequential Search Technique Binary Search Technique Table or File Search Technique 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 A[1] K2 A[2] K3 A[3] K4 A[4] ... ... Kn A[n]

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

EXERCISE 9.1
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?

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

134

TOPIC 9 SEARCHING

Round 1 We find the middle value first. Middle value = (initial + final)/2 = (0 + 9)/2 = 9/2 =4 Test the middle key with the search key. Middle key = k(4) = 20 20 < 39

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

40 < 39

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

25 < 39

In this round we found that the search key value (39) is bigger than the middle key (25), so the focus of the search is only to the right of the middle key, which is 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

136

TOPIC 9 SEARCHING

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.

EXERCISE 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?

9.2

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

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

EXERCISE 9.3
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)

138

TOPIC 9 SEARCHING

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

T o p ic 1 0
LEARNING OUTCOMES
1. Explain about trees;

X Trees

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

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.

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.

140 X TOPIC 10 TREES

10.1 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

TOPIC 10 TREES W

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) (b) Binary Tree Binary Search Tree (BST)

10.2 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

142 X TOPIC 10 TREES

each points to its left and right child node. Look at the following definition of the binary tree data structure:
typedef struct BinaryTree { int data; struct BinaryTree *left_child; struct BinaryTree *right_child; } BINARY_TREE; BINARY_TREE *tree;

One binary tree node can be pictured as shown in Figure 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.

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

TOPIC 10 TREES W

143

Figure 10.5: An example of a BST

The BST data structure is as follows:


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

The operations that can be performed on BST are: (a) (b) (c) (d) (e) Create BST Search BST Insert node into BST Traverse nodes in BST 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).

144 X TOPIC 10 TREES

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. void CreateBST (BST **tree){ *tree = NULL; }

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:

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

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. 2. 2.1 Search BST for node containing the item If the node exists display message node exists

TOPIC 10 TREES W

145

2.2 3. 3.1

end If not 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.

146 X TOPIC 10 TREES

Figure 10.7: An example of InsertBST

Figure 10.8: An example of a InsertBST

TOPIC 10 TREES W

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.

148 X TOPIC 10 TREES

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

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.

TOPIC 10 TREES W

149

BST *NewBSTNode (int item) { BST *p = NULL; P = (BST*) malloc (sizeof(BST)); if (p == NULL) printf(ERROR); else { p -> data = item; p -> left_child = NULL; p -> right_child = NULL; } return p; }

The sequence of nodes inserted into the BST will determine the shape of the BST even though the data content is the same. For example, the BST that is produced when the data with 3, 4, 5, 6, 1, 2, is inserted is completely different from the BST produced when data with 5, 1, 3, 4, 2, 6, because the succession of data insertion has changed.

EXERCISE 10.1
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?

150 X TOPIC 10 TREES

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) (ii) Visit the tree on the left 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

TOPIC 10 TREES W

151

The function to perform this in-order traversal is as follows: void inOrder(BST *j){ if (j){ inOrder(j -> left_child); printf(\n%d, j -> data); inOrder (j -> right_child); } } (b) (Pre-order ) Traversal Pre-order traversal will move through the BST using the following steps: (i) (ii) Get data from node 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: void preOrder(BST *j){ if (j){ printf(\n%d, j -> data); preOrder(j -> left_child); preOrder (j -> right_child); } }

(c)

(Post-order) Traversal Post-order traversal will move through the BST using the following steps: (i) (ii) Visit tree on the left Visit tree on the right

(iii) Get data from node

152 X TOPIC 10 TREES

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: void postOrder(BST *j){ if (j){ postOrder(j -> left_child); postOrder (j -> right_child); printf(\n%d, j -> data); } }

10.3.5 Deleting Nodes in BSTs


This operation involves three node conditions: (i) (ii) Node is leaf (no child nodes) 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. 2. Set right_child for f to NULL Free p

TOPIC 10 TREES W

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. 2. set parent -> left_child = x -> left_child; Free x

154 X TOPIC 10 TREES

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. 3. Assign the contents that are pointed to by pointer p, which is node n with the value stored in node o. Delete node o (node o has no child according to Condition 1).

TOPIC 10 TREES W

155

EXERCISE 10.2
Consider the BST below.

(a) (b)

Show the changes in BST when the nodes containing values 5, 60, 80, 90, 65, and 75 are inserted. What BST is formed if nodes 30, 60, and 70 are deleted from the BST that was produced in (a) above?

10.4 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, preorder 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

156 X TOPIC 10 TREES

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

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

TOPIC 10 TREES W

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)

EXERCISE 10.3
Build an expression tree, then perform in-order, post-order, and pre-order traversals for the following arithmetic expressions: (a) (b) A*(B+C)+D A+B*C D*E

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.

158 X TOPIC 10 TREES

Binary Tress Binary Search Trees In-order Traversal

Post-order Traversal Pre-order Traversal

S-ar putea să vă placă și