1. Trang chủ
  2. » Công Nghệ Thông Tin

IT training c programming an advanced course kalicharan 2008 08 11

224 72 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 224
Dung lượng 892,44 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

1 Sorting, searching and merging In this chapter, we will explain: • how to sort a list of items using insertion sort • how to add a new item to a sorted list so that the list remains s

Trang 2

© Noel Kalicharan, 2006

nkalicharan@fsa.uwi.tt

All rights reserved

The text of this publication, or any part thereof, may not

be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, storage in an information retrieval system, the Internet, or otherwise, without prior written permission

of the author

Trang 3

This book takes up where C Programming – A Beginner’s Course leaves off It assumes

you have a working knowledge of basic programming concepts such as variables, constants, assignment, selection (if else) and looping (while, for) It also assumes you are comfortable with writing functions and working with arrays If you are not, it is

recommended that you study A Beginner’s Course before tackling the material in this

book

As in the first book, the emphasis is not on teaching the C language, per se, but rather, on using C to teach concepts that any budding programmer should know The major topics covered are sorting, searching, merging, structures, pointers, linked lists, stacks, queues, recursion and random numbers

Chapter 1 deals with sorting a list, searching a list and merging two ordered lists

Chapter 2 introduces an important concept—the structure Structures allow you to group

a set of related data and manipulate them as one This chapter shows you how to search and sort an array of structures and how to create useful user-defined types using typedef and structs

Chapter 3 covers that elusive but very powerful concept—pointers Many programmers will tell you that this is probably the most difficult concept to grasp and the one that gives them the most headache We hope that, after reading this chapter, you will agree that it does not have to be so

Chapter 4 deals with linked lists—an important data structure in its own right but also the foundation for more advanced structures such as trees and graphs

Chapter 5 is devoted specifically to stacks and queues, perhaps the most useful kinds of linear lists They have important applications in Computer Science

Chapter 6 introduces a powerful programming methodology—recursion There is no doubt that recursion takes a bit of getting used to But, once mastered, you would be able

to solve a whole new world of problems that would be difficult to solve using traditional techniques

We all like to play games But what lurks inside these game-playing programs? Random numbers Chapter 7 shows you how to use random numbers to play some simple games and simulate real-life situations

Almost anything we need to store on a computer must be stored in a file We use text files for storing the kinds of documents we create with a text editor or word processor

We use binary files for storing photographic image files, sound files, video files and files

of ‘records’ Chapter 8 shows how to create and manipulate text and binary files And it also explains how to work with that most versatile kind of file—a random access file

I wish to express my thanks to Anisa Sawh-Ramdhan for her careful reading of the manuscript Any errors that remain are all mine

Noel Kalicharan

Trang 4

1 Sorting, searching and merging 1

1.1 Sorting an array – insertion sort 1

1.2 Inserting an element in place 7

1.3 Sorting an array of strings 8

1.4 Sorting parallel arrays 10

1.5 Binary search 10

1.6 Searching an array of strings 13

1.7 Example – word frequency count 13

1.8 Merging ordered lists 19

Exercises 1 22

2 Structures 24

2.1 How to declare a structure 25

2.2 Working with an array of structures 29

2.3 Searching an array of structures 30

2.4 Sorting an array of structures 31

2.5 Putting it all together 32

2.6 Nested structures 35

2.7 Fractions 36

2.8 A voting problem 39

2.9 Passing structures to functions 46

Exercises 2 47

3 Pointers 48

3.1 Passing pointers as arguments 50

3.2 More on passing an array as an argument 52

3.3 Character pointers 54

3.4 Pointer arithmetic 55

3.5 Pointers to structures 58

3.6 Pointers to functions 60

3.7 Void pointers 63

Exercises 3 65

4 Linked lists 67

4.1 Basic operations on a linked list 69

4.1.1 Counting the nodes in a linked list 69

4.1.2 Searching a linked list 71

4.1.3 Finding the last node in a linked list 72

4.2 Dynamic storage allocation – malloc, calloc, sizeof, free 72

4.3 Building a linked list – adding new item at the tail 76

4.4 Insertion into a linked list 79

4.5 Building a linked list – adding new item at the head 82

4.6 Deletion from a linked list 83

4.7 Building a sorted linked list 85

4.8 Example – palindrome 89

4.9 Merging two sorted linked lists 92

Exercises 4 96

5 Stacks and queues 98

5.1 Abstract data types 98

5.2 Stacks 98

Trang 5

5.2.2 Implementing a stack using a linked list 104

5.3 Creating a stack header file 107

5.4 A general stack type 108

5.4.1 Example – convert from decimal to binary 112

5.5 How to convert from infix to postfix 113

5.5.1 How to evaluate a postfix expression 118

5.6 Queues 120

5.6.1 Implementing a queue using an array 120

5.6.2 Implementing a queue using a linked list 125

Exercises 5 131

6 Recursion 132

6.1 Recursive functions in C 133

6.2 Recursive decimal to binary 136

6.3 Printing a linked list in reverse order 139

6.4 Towers of Hanoi 140

6.5 The power function 142

6.6 Merge sort 144

6.7 static variables 147

6.8 Counting organisms 149

6.9 Finding a path through a maze 154

Exercises 6 158

7 Random numbers, games and simulation 160

7.1 Random numbers 160

7.2 Random and pseudo-random numbers 161

7.3 Generating random numbers by computer 162

7.4 A guessing game 165

7.5 Drills in addition 165

7.6 Nim 167

7.7 Non-uniform distributions 171

7.7.1 Collecting bottle caps 173

7.8 Simulation of real-life problems 176

7.9 Simulating a queue 177

7.10 Estimating numerical values using random numbers 181

Exercises 7 184

8 Working with files 186

8.1 Reading data from a file 186

8.2 Sending output to a file 189

8.3 Text and binary files 191

8.4 Internal vs external file name 191

8.5 fopen and fclose 192

8.6 getc and putc 195

8.7 feof and ferror 195

8.8 fgets and fputs 197

8.9 Input/output for binary files 199

8.9.1 fread and fwrite 200

8.10 Random access files 202

8.11 Indexed files 206

8.12 Updating a random access file 212

Exercises 8 216

Trang 7

1 Sorting, searching and merging

In this chapter, we will explain:

• how to sort a list of items using insertion sort

• how to add a new item to a sorted list so that the list remains sorted

• how to sort an array of strings

• how to sort related (parallel) arrays

• how to search a sorted list using binary search

• how to write a program to do a frequency count of words in a passage

• how to merge two sorted lists to create one sorted list

1.1 Sorting an array - insertion sort

Sorting is the process by which a set of values are arranged in ascending or

descending order There are many reasons to sort Sometimes we sort in order to produce more readable output (for example, to produce an alphabetical listing) A teacher may need to sort her students in order by name or by average score If we have a large set of values and we want to identify duplicates, we can do so by sorting; the repeated values will come together in the sorted list There are many

ways to sort We will discuss a method known as insertion sort

Consider the following array:

Think of the numbers as cards on a table and picked up one at a time in the order

in which they appear in the array Thus, we first pick up 57, then 48, then 79, and

so on, until we pick up 52 However, as we pick up each new number, we add it

to our hand in such a way that the numbers in our hand are all sorted

When we pick up 57, we have just one number in our hand We consider one number to be sorted

When we pick up 48, we add it in front of 57 so our hand contains

65 4

15 5

33 6 52 num

Trang 8

When we pick up 65, we place it after 57 so our hand contains

The numbers have been sorted in ascending order

The method described illustrates the idea behind insertion sort The numbers in

the array will be processed one at a time, from left to right This is equivalent to picking up the numbers from the table, one at a time Since the first number, by itself, is sorted, we will process the numbers in the array starting from the second When we come to process num[j], we can assume that num[0] to num[j-1] are sorted We then attempt to insert num[j] among num[0] to num[j-1] so that num[0] to num[j] are sorted We will then go on to process num[j+1] When we

do so, our assumption that num[0] to num[j] are sorted will be true

Sorting num in ascending order using insertion sort proceeds as follows:

Trang 9

We can picture this as follows:

The insertion of 15 in its correct position proceeds as follows:

• Compare 15 with 79; it is smaller so move 79 to location 4, leaving

location 3 free This gives:

• Compare 15 with 65; it is smaller so move 65 to location 3, leaving

location 2 free This gives:

• Compare 15 with 57; it is smaller so move 57 to location 2, leaving

location 1 free This gives:

• Compare 15 with 48; it is smaller so move 48 to location 1, leaving

location 0 free This gives:

0

48 1

57 2

65 3

79

33 6 52

num

15 key

0

48 1

57 2

65

79 5

33 6 52

num

15 key

0

48 1

57

65 4

79 5

33 6 52

num

15 key

0

48

57 3

65 4

79 5

33 6 52

num

15 key

num

15 key

Trang 10

• There are no more numbers to compare with 15 so it is inserted in location

0, giving

• We can express the logic of placing 15 by saying that as long as key is less than num[k], for some k, we move num[k] to position num[k + 1] and move on to consider num[k - 1], providing it exists It won’t exist when k is actually 0 In this case, the process stops and key is inserted in position 0

5 th pass

• Process num[5], that is, 33 This involves placing 33 so that the first six numbers are sorted This is done as follows:

• Store 33 in key, leaving location 5 free;

• Compare 33 with 79; it is smaller so move 79 to location 5, leaving

• Compare 33 with 15; it is bigger; insert 33 in location 1 This gives:

• We can express the logic of placing 33 by saying that as long as key is less than num[k], for some k, we move num[k] to position num[k + 1] and move on to consider num[k - 1], providing it exists If key is greater than or equal to num[k] for some k, then key is inserted in position k + 1 Here, 33

is greater than num[0] and so is inserted into num[1]

6 th pass

• Process num[6], that is, 52 This involves placing 52 so that the first seven (all) numbers are sorted This is done as follows:

• Store 52 in key, leaving location 6 free;

• Compare 52 with 79; it is smaller so move 79 to location 6, leaving

48 2

57 3

65 4

79 5

33 6 52

num

15 key

0

15 1

33 2

48 3

57 4

65 5

79 6 52

num

33 key

Trang 11

• Compare 52 with 57; it is smaller so move 57 to location 4, leaving

location 3 free;

• Compare 52 with 48; it is bigger; insert 52 in location 3 This gives:

The array is now completely sorted

The following is an outline to sort the first n elements of an array, num, using insertion sort:

for j = 1 to n - 1 do

insert num[j] among num[0] to num[j-1] so that

num[0] to num[j] are sorted

endfor

Using this outline, we write the function insertionSort using the parameter list

void insertionSort(int list[], int n) {

//sort list[0] to list[n-1] in ascending order

int j, k, key;

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

key = list[j];

k = j - 1; //start comparing with previous item

while (k >= 0 && key < list[k]) {

to the next number on the left ( k)

We exit the while loop if k is equal to -1 or if key is greater than or equal to list[k], for some k In either case, key is inserted into list[k + 1]

If k is -1, it means that the current number is smaller than all the previous

numbers in the list and must be inserted in list[0] But list[k + 1] is list[0] when k

is -1, so key is inserted correctly in this case

The function sorts in ascending order To sort in descending order, all we have to

do is change < to > in the while condition, thus:

0

15 1

33 2

48 3

52 4

57 5

65 6 79

num

52 key

Trang 12

while (k >= 0 && key > list[k])

Now, a key moves to the left if it is bigger

We write Program P1.1 to test whether insertionSort works correctly Only main

is shown in the box below Adding the function completes the program

printf("\nThe sorted numbers are\n");

for (v = 0; v < n; v++) printf("%d ", num[v]);

printf("\n");

}

The program requests up to 10 numbers (since the array is declared to be of size 10), stores them in the array num, calls insertionSort, then prints the sorted list The following is a sample run of the program:

Type up to 10 numbers followed by 0

57 48 79 65 15 33 52 0

The sorted numbers are

15 33 48 52 57 65 79

We could easily generalize insertionSort to sort a portion of a list To illustrate,

we re-write insertionSort (next page) to sort list[lo] to list[hi] where lo and hi are passed as arguments to the function

Since element lo is the first one, we start processing elements from lo + 1 until element hi This is reflected in the for statement Also now, the lowest subscript is

lo, rather than 0 This is reflected in the while condition k >= lo Everything else remains the same as before

Trang 13

void insertionSort(int list[], int lo, int hi) {

//sort list[lo] to list[hi] in ascending order

int j, k, key;

for (j = lo + 1; j <= hi; j++) {

key = list[j];

k = j - 1; //start comparing with previous item

while (k >= lo && key < list[k]) {

1.2 Inserting an element in place

Insertion sort uses the idea of adding a new element to an already sorted list so that the list remains sorted We can treat this as a problem in its own right (nothing to do with insertion sort) Specifically, given a sorted list of items from list[m] to list[n], we want to add a new item (newItem, say) to the list so that list[m] to list[n + 1] are sorted

Adding a new item increases the size of the list by 1 We assume that the array has room to hold the new item We write the function insertInPlace to solve this problem

void insertInPlace(int newItem, int list[], int m, int n) {

//list[m] to list[n] are sorted

//insert newItem so that list[m] to list[n+1] are sorted

Trang 14

void insertionSort(int list[], int lo, int hi) {

//sort list[lo] to list[hi] in ascending order

void insertInPlace(int, int [], int, int);

int j;

for (j = lo + 1; j <= hi; j++)

insertInPlace(list[j], list, lo, j - 1);

}

1.3 Sorting an array of strings

Consider the problem of sorting a list of names in alphabetical order Recall that each name is stored in a character array To store several names, we need a two-dimensional character array For example, we can store 8 names as follows:

To do so will require a declaration such as:

char list[8][15];

To cater for longer names, we can increase 15 and to cater for more names, we can increase 8

The process of sorting list is essentially the same as sorting an array of integers

The major difference is that whereas we use < to compare two numbers, we must use strcmp to compare two names In the function insertionSort on the previous page, the while condition changes from

while (k >= lo && key < list[k])

to

while (k >= lo && strcmp(key, list[k]) < 0)

where key is now declared as char key[15]

Also, we must now use strcpy (since we can’t use = for strings) to assign a name

to another location Here is the complete function:

Trang 15

void insertionSort(char list[][15], int lo, int hi) {

//sort list[lo] to list[hi] in alphabetical order

int j, k;

char key[15];

for (j = lo + 1; j <= hi; j++) {

strcpy(key, list[j]);

k = j - 1; //start comparing with previous item

while (k >= lo && strcmp(key, list[k]) < 0) {

Recall that when a two-dimensional array is used as a parameter, the second

dimension must be specified using a constant (or a #defined constant identifier) The first dimension can be left unspecified, similar to when a one-dimensional array is used as a parameter

We write a simple main routine to test this version of insertionSort Here it is:

char name[8][15] = {"Taylor, Victor", "Duncan, Denise",

"Ramdhan, Kamal", "Singh, Krishna", "Ali, Michael",

"Sawh, Anisa", "Khan, Carol", "Owen, David" };

n = 8;

insertionSort(name, 0, n-1);

printf("\nThe sorted names are\n\n");

for (j = 0; j < n; j++) printf("%s\n", name[j]);

}

The declaration of name initializes it with the eight names as shown on page 8 When run, the program produces the following output:

Trang 16

The sorted names are

1.4 Sorting parallel arrays

It is quite common to have related information in different arrays For example, suppose, in addition to name, we have an integer array id such that id[j] is an identification number associated with name[j], as in the following:

To achieve this, each time a name is moved during the sorting process, the corresponding id number must also be moved Since the name and id number must be moved “in parallel”, we say we are doing a “parallel sort” or we are sorting “parallel arrays” We re-write insertionSort to illustrate how to sort parallel arrays We call it parallelSort, shown on the next page

44 5

49 6 56 num

7

66 8

72 9

78 10

Trang 17

void parallelSort(char list[][15], int id[], int lo, int hi) {

//sort list[lo] to list[hi] in alphabetical order, ensuring that

//each name remains with its original id number

int j, k, m;

char key[15];

for (j = lo + 1; j <= hi; j++) {

strcpy(key, list[j]);

m = id[j]; // extract the id number

k = j - 1; //start comparing with previous item

while (k >= lo && strcmp(key, list[k]) < 0) {

Suppose we wish to search for 66 The search proceeds as follows:

• First, we find the middle item in the list This is 56 in position 6 We

compare 66 with 56 Since 66 is bigger, we know that if 66 is in the list at

all, it must be after position 6, since the numbers are in ascending order In our next step, we confine our search to locations 7 to 12

• Next, we find the middle item from locations 7 to 12 In this case, we can choose either item 9 or item 10 The algorithm we will write will choose item 9, that is, 78

We compare 66 with 78 Since 66 is smaller, we know that if 66 is in the

list at all, it must be before position 9, since the numbers are in ascending order In our next step, we confine our search to locations 7 to 8

• Next, we find the middle item from locations 7 to 8 In this case, we can choose either item 7 or item 8 The algorithm we will write will choose item

7, that is, 66

We compare 66 with 66 Since they are the same, our search ends

successfully, finding the required item in position 7

Suppose we were searching for 70 The search will proceed as above until we compare 70 with 66 (in location 7)

• Since 70 is bigger, we know that if 70 is in the list at all, it must be after

position 7, since the numbers are in ascending order In our next step, we confine our search to locations 8 to 8 This is just one location

Trang 18

• We compare 70 with item 8, that is, 72 Since 70 is smaller, we know that

if 70 is in the list at all, it must be before position 8 Since it can’t be after position 7 and before position 8, we conclude that it is not in the list

At each stage of the search, we confine our search to some portion of the list Let

us use the variables lo and hi as the subscripts which define this portion In other words, our search will be confined to num[lo] to num[hi]

Initially, we want to search the entire list so that we will set lo to 0 and hi to 12, in this example

How do we find the subscript of the middle item? We will use the calculation

mid = (lo + hi) / 2;

Since integer division will be performed, the fraction, if any, is discarded For example when lo is 0 and hi is 12, mid becomes 6; when lo is 7 and hi is 12, mid becomes 9; and when lo is 7 and hi is 8, mid becomes 7

As long as lo is less than or equal to hi, they define a non-empty portion of the list

to be searched When lo is equal to hi, they define a single item to be searched If

lo ever gets bigger than hi, it means we have searched the entire list and the item was not found

Based on these ideas, we can now write a function binarySearch To be more general, we will write it so that the calling routine can specify which portion of the array it wants the search to look for the item

Thus, the function must be given the item to be searched for (key), the array (list), the start position of the search (lo) and the end position of the search (hi) For example, to search for the number 66 in the array num, above, we can issue the call binarySearch(66, num, 0, 12)

The function must tell us the result of the search If the item is found, the function will return its location If not found, it will return -1

int binarySearch(int key, int list[], int lo, int hi) {

//search for key from list[lo] to list[hi]

//if found, return its location; otherwise, return -1

int mid;

while (lo <= hi) {

mid = (lo + hi) / 2;

if (key == list[mid]) return mid; // found

if (key < list[mid]) hi = mid - 1;

else lo = mid + 1;

}

return -1; //lo and hi have crossed; key not found

}

Trang 19

If item contains a number to be searched for, we can write code as follows:

int ans = binarySearch(item, num, 0, 12);

if (ans == -1) printf(“%d not found\n”, item);

else printf(“%d found in location %d\n”, item, ans);

If we wish to search for item from locations i to j, we can write

int ans = binarySearch(item, num, i, j);

1.6 Searching an array of strings

We can search a sorted array of strings (names in alphabetical order, say) using the same technique we used for searching an integer array The major differences are in the declaration of the array and the use of strcmp, rather than == or <, to compare two strings Here is the string version of binarySearch

int binarySearch(char key[15], char list[][15], int lo, int hi) {

//search for key from list[lo] to list[hi]

//if found, return its location; otherwise, return -1

int mid, cmp;

while (lo <= hi) {

mid = (lo + hi) / 2;

The function can be tested with main shown on the next page

This sets up the array name with the names in alphabetical order It then calls binarySearch with various names and prints the result of each search

1.7 Example - word frequency count

Let us write a program to read an English passage and count the number of times each word appears Output consists of an alphabetical listing of the words and their frequencies

Trang 20

char name[8][15] = {"Ali, Michael","Duncan, Denise",

"Khan, Carol","Owen, David", "Ramdhan, Kamal",

"Sawh, Anisa", "Singh, Krishna", "Taylor, Victor"};

n = binarySearch("Ali, Michael", name, 0, 7);

printf("%d\n", n); //will print 0, location of Ali, Michael

n = binarySearch("Taylor, Victor", name, 0, 7);

printf("%d\n", n); //will print 7, location of Taylor, Victor

n = binarySearch("Owen, David", name, 0, 7);

printf("%d\n", n); //will print 3, location of Owen, David

n = binarySearch("Sandy, Cindy", name, 0, 7);

printf("%d\n", n); //will print -1 since Sandy, Cindy is not in the list }

We can use the following outline to develop our program:

while there is input

get a word

search for word

if word is in the table

add 1 to its count

else

add word to the table

set its count to 1

If the search fails, the word is put in the table and its count set to 1

A major design decision here is how to search the table which, in turn, will depend on where and how a new word is inserted in the table The following are two possibilities:

(1) A new word is inserted in the next free position in the table This implies that a sequential search must be used to look for an incoming word since the words would not be in any particular order This method has the advantages

Trang 21

of simplicity and easy insertion, but searching takes longer as more words are put in the table

(2) A new word is inserted in the table in such a way that the words are always

in alphabetical order This may entail moving words which have already been stored so that the new word may be slotted in the right place However, since the table is in order, a binary search can be used to search for an incoming word

For this method, searching is faster but insertion is slower than in (1) Since, in general, searching is done more frequently than inserting, (2) might be preferable

Another advantage of (2) is that, at the end, the words will already be in alphabetical order and no sorting will be required If (1) is used, the words will need to be sorted to obtain the alphabetical order

We will write our program using the approach in (2) The complete program is shown as Program P1.4

int getWord(FILE *, char[]);

int search(char [], char[][MaxLength+1], int);

void addToList(char[], char [][MaxLength+1], int[], int, int);

void printResults(FILE *, char [][MaxLength+1], int[], int);

char wordList[MaxWords+1][MaxLength+1], word[MaxLength+1];

int frequency[MaxWords+1], numWords = 0, j, loc;

Trang 22

for (j = 1; j <= MaxWords; j++) frequency[j] = 0;

while (getWord(in, word) != 0) {

loc = binarySearch(word, wordList, 1, numWords);

if (loc > 0) ++frequency[loc];

else //this is a new word

if (numWords < MaxWords) { //if table is not full

addToList(word, wordList, frequency, -loc, numWords); ++numWords;

int getWord(FILE * in, char str[]) {

// stores the next word, if any, in str; word is converted to lowercase // returns 1 if a word is found; 0, otherwise

char ch;

int n = 0;

// read over white space

while (!isalpha(ch = getc(in)) && ch != EOF) ; //empty while body

int mid = (lo + hi)/2;

int result = strcmp(item, list[mid]);

if (result == 0) return mid;

Trang 23

void addToList(char item[], char list[][MaxLength+1], int freq[], int p, int n) {

//adds item in position list[p]; sets freq[p] to 1

//shifts list[n] down to list[p] to the right

When Program P1.4 was run with the following data:

The quick brown fox jumps over the lazy dog

Congratulations!

If the quick brown fox jumped over the lazy dog then

Why did the quick brown fox jump over the lazy dog?

Trang 24

Comments on Program P1.4

• For our purposes, we assume that a word begins with a letter and consists of letters only If you wish to include other characters (like a hyphen or

apostrophe), you need only change the getWord function

• MaxWords denotes the maximum number of distinct words catered for For testing the program, we have used 50 for this value The arrays are declared using MaxWords + 1 We will store words from wordList[1] to

wordList[MaxWords] We will not use wordList[0] This will make it slightly more convenient to write a flexible binarySearch routine (see below)

If the number of distinct words in the passage exceeds MaxWords (50, say), any words after the 50th will be read but not stored and a message to that effect will be printed However, the count for a word already stored will be incremented if it is encountered again

• MaxLength (we use 10 for testing) denotes the maximum length of a word Strings are declared using MaxLength + 1 to cater for \0 which must be added

at the end of each string

• main checks that the input file exists and that the output file can be created Next, it initializes the frequency counts to 0 It then processes the words in the passage based on the outline on page 14

• getWord reads the input file and stores the next word found in its string argument It returns 1 if a word is found and 0, otherwise If a word is longer than MaxLength, only the first MaxLength letters are stored; the rest are read and discarded For example, congratulations is truncated to congratula using

a word size of 10

All words are converted to lowercase so that, for instance, The and the are counted as the same word

• binarySearch is written so that if the word is found, its location is returned If

the word is not found, and n is the location in which it should be inserted, -n

is returned It is for this reason that we do not use wordList[0] If we did, we

would not be able to easily distinguish between a word found in location 0 and

a word that needs to be inserted in location 0 (since 0 = -0)

• addToList is given the location in which to insert a new word Words to the right of, and including, this location, are shifted one position to make room for the new word

• Whereas the latest C standard allows a variable to be declared in a for

statement, as in

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

some (older) compilers will not allow it If you use one of these compilers, just declare the variable at the head of the function, as illustrated in addToList and printResults

• In declaring a function prototype, some compilers allow a two-dimensional

array parameter to be declared as in char [][], with no size specified for either

Trang 25

dimension Others require that the size of the second dimension must be

specified Specifying the size of the second dimension should work on all compilers

1.8 Merging ordered lists

Merging is the process by which two or more ordered lists are combined into one ordered list For example, given two lists of numbers, A and B, as follows:

We look at the top two cards, 21 and 16 The smaller, 16, is removed and placed

in C This exposes the number 25

The top two cards are now 21 and 25 The smaller, 21, is removed and added to C which now contains 16 21 This exposes the number 28

The top two cards are now 28 and 25 The smaller, 25, is removed and added to C which now contains 16 21 25 This exposes the number 47

The top two cards are now 28 and 47 The smaller, 28, is removed and added to C which now contains 16 21 25 28 This exposes the number 35

The top two cards are now 35 and 47 The smaller, 35, is removed and added to C which now contains 16 21 25 28 35 This exposes the number 40

The top two cards are now 40 and 47 The smaller, 40, is removed and added to C which now contains 16 21 25 28 35 40 This exposes the number 61

Trang 26

The top two cards are now 61 and 47 The smaller, 47, is removed and added to C which now contains 16 21 25 28 35 40 47 This exposes the number 54 The top two cards are now 61 and 54 The smaller, 54, is removed and added to C which now contains 16 21 25 28 35 40 47 54 The list B has no more numbers

We copy the remaining elements (61 75) of A to C, which now contains:

16 21 25 28 35 40 47 54 61 75

and the merge is completed

At each step of the merge, we compare the smallest remaining number of A with the smallest remaining number of B The smaller of these is added to C If the smaller comes from A, we move on to the next number in A; if the smaller comes from B, we move on to the next number in B

This is repeated until all the numbers in either A or B have been used If all the numbers in A have been used, we add the remaining numbers from B to C If all the numbers in B have been used, we add the remaining numbers from A to C

We can express the logic of the merge as follows:

while (at least one number remains in both A and B) {

if (A has ended) add remaining numbers in B to C

else add remaining numbers in A to C

Implementing the merge

Assume that an array A contains m numbers stored in A[0] to A[m-1] and an array

B contains n numbers stored in B[0] to B[n-1] Assume that the numbers are

stored in ascending order We wish to merge the numbers in A and B into another array C such that C[0] to C[m+n-1] contains all the numbers in A and B sorted in ascending order

We will use integer variables i, j and k to subscript the arrays A, B and C, respectively “Moving on to the next position” in an array can be done by adding

1 to the subscript variable We can implement the merge with the following code:

Trang 27

i = 0; //i points to the first (smallest) number in A

j = 0; //j points to the first (smallest) number in B

k = -1; //k will be incremented before storing a number in C[k]

else // j == n, copy A[i] to A[m-1] to C

for ( ; i < m; i++) C[++k] = A[i];

Program P1.5 shows a simple main function which tests the above logic We write the merge as a function which, given the arguments A, m, B, n and C, performs the merge and returns the number of elements, m + n, in C When run, the program prints the contents of C, thus:

int merge(int A[], int m, int B[], int n, int C[]) {

int i = 0; //i points to the first (smallest) number in A

int j = 0; //j points to the first (smallest) number in B

int k = -1; //k will be incremented before storing a number in C[k]

else // j == n, copy A[i] to A[m-1] to C

for ( ; i < m; i++) C[++k] = A[i];

return m + n;

}

Trang 28

As a matter of interest, we can also implement merge as follows:

int merge(int A[], int m, int B[], int n, int C[]) {

int i = 0; //i points to the first (smallest) number in A

int j = 0; //j points to the first (smallest) number in B

int k = -1; //k will be incremented before storing a number in C[k]

number of voters is unknown beforehand but the votes are terminated by a vote of

0 Any vote which is not a number from 1 to 10 is a spoilt vote A file, votes.txt, contains the names of the candidates The first name is considered as candidate 1, the second as candidate 2, and so on The names are followed by the votes Write a program to read the data and evaluate the results of the survey

Print the results in alphabetical order by artist name and in order by votes received (most votes first) Print all output to the file, results.txt

2 Write a program to read names and phone numbers into two arrays Request a name and print the person’s phone number Use binary search to look up the name

3 Write a program to read English words and their equivalent Spanish words into two arrays Request the user to type several English words For each, print the

equivalent Spanish word Choose a suitable end-of-data marker Search for the typed words using binary search Modify the program so that the user types

Spanish words instead

4 The median of a set of n numbers (not necessarily distinct) is obtained by arranging the numbers in order and taking the number in the middle If n is odd, there is a unique middle number If n is even, then the average of the two middle values is the median Write a program to read a set of n positive integers (assume n < 100) and print their median; n is not given but 0 indicates the end of the data

Trang 29

5 The mode of a set of n numbers is the number which appears most frequently For

example, the mode of 7 3 8 5 7 3 1 3 4 8 9 is 3 Write a program to read a set of

n positive integers (assume n < 100) and print their mode; n is not given but 0

indicates the end of the data

6 A multiple-choice examination consists of twenty questions Each question has five choices, labelled A, B, C, D and E The first line of data contains the correct

answers to the twenty questions in the first 20 consecutive character positions, for

example:

BECDCBAADEBACBAEDDBE

Each subsequent line contains the answers for a candidate Data on a line consists

of a candidate number (an integer), followed by one or more spaces, followed by

the twenty answers given by the candidate in the next twenty consecutive character

positions An X is used if a candidate did not answer a particular question You may assume all data are valid and stored in a file exam.dat A sample line is:

Write a program to process the data and print a report consisting of candidate

number and the total points obtained by the candidate, in ascending order by candidate number At the end, print the average number of points gained by the

candidates

7 An array chosen contains n distinct integers arranged in no particular order

Another array winners contains m distinct integers arranged in ascending order

Write code to determine how many of the numbers in chosen appear in winners

8 A is an array sorted in descending order B is an array sorted in descending order

Merge A and B into C so that C is in descending order

9 A is an array sorted in descending order B is an array sorted in descending order

Merge A and B into C so that C is in ascending order

10 A is an array sorted in ascending order B is an array sorted in descending order

Merge A and B into C so that C is in ascending order

11 An array A contains integers that first increase in value and then decrease in value, for example,

It is unknown at which point the numbers start to decrease Write efficient code to code to copy the numbers in A to another array B so that B is sorted in ascending order Your code must take advantage of the way the numbers are arranged in A

12 Two words are anagrams if one word can be formed by rearranging all the letters

of the other word, for example: section, notices Write a program to read two words and determine if they are anagrams

Write another program to read a list of words and find all sets of words such that words within a set are anagrams of each other

39 4

44 5

49 6

36 7

29 8

20

9

Trang 30

2 Structures

In this chapter, we will explain:

• what is a structure and how to declare one

• how to use typedef to work with structures more conveniently

• how to work with an array of structures

• how to search an array of structures

• how to sort an array of structures

• how to declare nested structures

• how to use structures to manipulate fractions

• how structures can be passed to a function

• how to use structures to solve a ‘voting’ problem

In C, a structure is a collection of one or more variables, possibly of different types, grouped together under a single name for convenient handling

There are many situations in which we wish to process data about a certain entity

or object but the data itself consists of items of various types For example, the

data for a student (the student record) may consist of several fields such as a

name, address and telephone number (all of type string), number of courses taken (integer), fees payable (floating-point), names of courses (string), grade obtained (character), etc

The data for a car may consist of manufacturer, model and registration number (string), seating capacity and fuel capacity (integer), mileage and price (floating-point) For a book, we may wish to store author and title (string), price (floating-point), number of pages (integer), type of binding—hardcover, paperback, spiral (string) and number of copies in stock (integer)

Suppose we wish to store data for 100 students in a program One approach is to have a separate array for each field and use subscripts to link the fields together

Thus name[j], address[j], fees[j], etc refer to the data for the jth student

The problem with this approach is that if there are many fields, the handling of several parallel arrays becomes clumsy and unwieldy For example, suppose we want to pass a student’s data to a function via the parameter list This will involve the passing of several arrays Also, if we are sorting the students by name, say, each time two names are interchanged, we have to write statements to interchange the data in the other arrays as well In such situations, C structures are convenient

to use

Trang 31

2.1 How to declare a structure

Consider the problem of storing a date in a program A date consists of three parts—the day, the month and the year Each of these parts can be represented by

an integer For example, the date “September 14, 2006” can be represented by the day, 14, the month, 9, and the year 2006 We say that a date consists of three

fields, each of which is an integer

If we wish, we could also represent a date by using the name of the month, rather

than its number In this case, a date consists of three fields, one of which is a string and the other two are integers

In C, we can declare a date type as a structure using the keyword struct Consider

the declaration:

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

It consists of the word struct followed by some name we choose to give to the structure (date, in the example); this is followed by the declarations of the fields enclosed in left and right braces Note the semicolon at the end of the declaration just before the right brace—this is the usual case of a semicolon ending a declaration The right brace is followed by a semicolon, ending the struct declaration

We could also have written the declaration as:

where each field is declared individually This could be written as

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

but the former style is preferred for its readability

Given the struct declaration, we can declare variables of type struct date, as in:

struct date dob; //to hold a “date of birth”

This declares dob as a “structure variable” of type date It has three fields called day, month and year This can be pictured as:

We refer to the day field as dob.day, the month field as dob.month and the year field as dob.year In C, the period (.), as used here, is referred to as the “structure

year month

day dob

Trang 32

In general, a field is specified by the structure name, followed by a period, followed by the field name

We could declare more than one variable at a time, as in:

struct date borrowed, returned; //for a book in a library, say

Each of these variables has 3 fields—day, month and year The fields of borrowed are referred to by borrowed.day, borrowed.month and borrowed.year The fields of returned are referred to by returned.day, returned.month and returned.year

In this example, each field is an int and can be used in any context in which an int variable can be used For example, to assign the date “November 14, 2006” to dob, we can use:

dob.day = 14;

dob.month = 11;

dob.year = 2006;

This can be pictured as:

We can also read values for day, month and year with

scanf(“%d %d %d”, &dob.day, &dob.month, &dob.year);

If today was a struct date variable holding a date, we could assign all the fields

of today to dob, say, with:

We can print the “value” of dob with

printf(“The party is on %d/%d/%d\n”, dob.day, dob.month, dob.year);

For this example, this will print

The party is on 14/11/2006

Note that each field has to be printed individually We could also write a function printDate, say, which prints a date given as an argument For example,

void printDate(struct date d) {

printf("%d/%d/%d \n", d.day, d.month, d.year);

}

year month

day

dob

Trang 33

2.1.1 typedef

We can use typedef to give a name to some existing type, and this name can then

be used to declare variables of that type We can also use typedef to construct shorter or more meaningful names for predefined C types or for user-declared types, such as structures For example, the statement

typedef int Whole;

declares a new type-name Whole which is synonymous with the predefined type int Note that Whole appears in the same position as a variable would, not right after the word typedef We can then declare variables of type Whole, as in

Whole amount, numCopies;

This is exactly equivalent to

int amount, numCopies;

For those accustomed to the term real of languages like Pascal or FORTRAN, the statement:

typedef float Real;

allows them to declare variables of type Real In this book, we use at least one uppercase letter to distinguish type names declared using typedef

We could give a short, meaningful name, Date, to the date structure above with the declaration:

typedef struct date {

int day;

int month;

int year;

} Date;

Recall that C distinguishes between uppercase and lowercase letters so that date

is different from Date We could, if we wished, have used any other identifier, such as DateType, instead of Date

We could now declare “structure variables” of type Date, such as:

Trang 34

Date dob, borrowed, returned;

Notice how much shorter and neater this is compared to

struct date dob, borrowed, returned;

Since there is hardly any reason to use this second form, we could omit date from the above declaration and write

To pursue the date example, suppose we wish to store the “short” name—the first

3 letters, e.g Aug—of the month We will need to use a declaration such as:

Trang 35

Suppose we wish to store information about students For each student, we want

to store their name, age and gender (male or female) Assuming that a name is no longer than 30 characters, we could use the declaration

We can now declare variables of type Student, as in

Student stud1, stud2;

Each of stud1 and stud2 will have its own fields—name, age and gender We can refer to these fields with

stud1.name stud1.age stud1.gender

stud2.name stud2.age stud2.gender

As usual, we can assign values to these fields or read values into them And, if we wish, we can assign all the fields of stud1 to stud2 with the statement

stud2 = stud1;

2.2 Working with an array of structures

Suppose we want to store data on 100 students We will need an array of size 100 and each element of the array will hold the data for one student Thus each element will have to be a structure—we need an “array of structures”

We can declare the array with

Student pupil[100];

similar to how we say “int pupil[100]” to declare an integer array of size 100 This allocates storage for pupil[0], pupil[1], pupil[2], , up to pupil[99] Each element pupil[j] consists of 3 fields which can be referred to by

pupil[j].name pupil[j].age pupil[j].gender

Firstly, we will need to store some data in the array Assume we have data in the following format (name, age, gender):

Trang 36

If str is a character array, assume we can call the function getString(in, str) to store the next data string in quotes in str without the quotes Also assume that readChar(in) will read the data and return the next non-whitespace character

Exercise: write the functions getString and readChar

We can read the data into the array pupil with the following code:

while (n < MaxItems && strcmp(temp, "END") != 0)

or by inserting

if (n == MaxItems) break;

just after the statement n++; inside the loop

2.3 Searching an array of structures

With the data stored in the array, we can manipulate it in various ways For instance, we can write a function to search for a given name Assuming the data are stored in no particular order, we can use a sequential search as follows:

int search(char key[], Student list[], int n) {

//search for key in list[0] to list[n-1]

//if found, return the location; if not found, return -1

Trang 37

Given the above data, the call

search("Singh, Sandy", pupil, 4)

will return 2 and the call

search("Layne, Sandy", pupil, 4)

will return -1

2.4 Sorting an array of structures

Suppose we want the list of students in alphabetical order by name It will be required to sort the array pupil The following function uses an insertion sort to do

the job The process is identical to sorting an int array, say, except that the name

field is used to govern the sorting

void sort(Student list[], int n) {

//sort list[0] to list[n-1] by name using an insertion sort

This assigns all the fields of list[k] to list[k + 1]

If we want to sort the students in order by age, all we need to change is the while

condition To sort in ascending order, we write

while (k >= 0 && temp.age < list[k].age) //move smaller numbers to the left

and to sort in descending order, we write

while (k >= 0 && temp.age > list[k].age) //move bigger numbers to the left

We could even separate the list into male and female students by sorting on the gender field Since ‘F’ comes before ‘M’ in alphabetical order, we can put the

Trang 38

while (k >= 0 && temp.gender < list[k].gender) //move F’s to the left

and we can put the males first by writing

while (k >= 0 && temp.gender > list[k].gender ) //move M’s to the left

2.5 Putting it all together

We illustrate the ideas discussed above in Program P2.1 The program

• reads data for students from a file, input.txt, and stores them in an array of structures

• prints the data in the order stored in the array

• tests search by reading several names and looking for them in the array

• sorts the data in alphabetical order by name

• prints the sorted data

The program also illustrates how the functions getString and readChar may be

written getString lets us read a string enclosed within any ‘delimiter’ characters

For example, we could specify a string as $John Smith$ or "John Smith" This is

a very flexible way of specifying a string Each string can be specified with its

own delimiters which could be different for the next string It is particularly useful for specifying strings which may include special characters such as the double quotes without having to use an escape sequence like \"

void getString(FILE *, char[]);

int getData(FILE *, Student[]);

int search(char[], Student[], int);

void sort(Student[], int);

void printStudent(Student);

void getString(FILE *, char[]);

Trang 39

while (strcmp(aName, "END") != 0) {

int ans = search(aName, pupil, numStudents);

if (ans == -1) printf("%s not found\n", aName);

else printf("%s found at location %d\n", aName, ans);

Trang 40

int search(char key[], Student list[], int n) {

//search for key in list[0] to list[n-1]

//if found, return the location; if not found, return -1 int j;

void sort(Student list[], int n) {

//sort list[0] to list[n-1] by name using an insertion sort Student temp;

void getString(FILE * in, char str[]) {

//stores, in str, the next string within delimiters

// the first non-whitespace character is the delimiter // the string is read from the file 'in'

char ch, delim;

int n = 0;

str[0] = '\0';

// read over white space

while (isspace(ch = getc(in))) ; //empty while body

Ngày đăng: 05/11/2019, 14:25

TỪ KHÓA LIÊN QUAN