Giáo trình Lập trình cơ bản C - Bài 19: Các kiểu dữ liệu nâng cao và sắp xếp

Bài 19  
Các Kiểu dữ liệu Nâng cao và Sắp xếp  
Mục tiêu:  
Kết thúc bài học này, bạn thể:  
Giải thích Tìm hiểu cấu trúc (structure) và công dụng của chúng  
Định nghĩa cấu trúc  
Khai báo các biến kiểu cấu trúc  
Giải thíchTìm hiểu cách truy cập vào các phần tử của cấu trúc  
Giải thíchTìm hiểu cách khởi tạo cấu trúc  
Giải thíchTìm hiểu cách sử dụng cấu trúc với câu lệnh gán  
Giải thích cách truyền cấu trúc vào hàm như các đối sốGiải thíchTìm hiểu cách truyền đốitham số  
kiểu kiểu cấu trúc vào hàm  
Sử dụng mảng các cấu trúc  
Giải thíchTìm hiểu sự cách khởi tạo của các mảng cấu trúc  
Giải thíchTìm hiểu con trỏ đến cấu trúc  
Giải thíchTìm hiểu cách truyền các đối số kiểu con trỏ cấu trúc vào hàm như các đối số.  
Giải thíchTìm hiểu từ khóa typedef  
Giải thíchTìm hiểu việc sắp xếp mảng với hai thuật toán sắp xếp mảng Insertion sort và Bubble  
sort.  
Giới thiệu  
Các chương trình ứng dụng trong bối cảnh của thế giới thựctrong thực tế đòi hỏi lưu trữ các kiểu dữ  
liệu khác nhau. thể các kiểu dữ liệu đã được định nghĩa trước của C tỏ ra là không đủ trong những  
trường hợp như vậy. Tuy nhiên, các kiểu dữ liệu của C mà chúng ta đã được học thể không đủ  
trong các trường hợp đó. vậy, C cho phép tạo ra các kiểu dữ liệu tùy ý do người dùng định nghĩa.  
Một trong những kiểu như vậy cấu trúc (structure). Một cấu trúc là một nhóm tập các biến được  
gom nhóm lại với nhau códưới cùng một tên. Một kiểu dữ liệu cũng thể được đặt tên mới bằng cách  
sử dụng từ khóa typedef.  
Các ứng dụng thường lưu trữ một số lượng dữ liệu rất lớn. Trong những trường hợp này, việc định vị  
một mục dữ liệu nào đó thể tốn nhiều thời gian. Sắp xếp các giá trị theo một trật tự nào đó sẽ làm  
cho công việc tìm kiếm nhanh chóng và dễ dàng hơn. Trong chương này, chúng ta cũng sẽ xem một số  
giải thuật dùng để sắp xếp các mảng.  
19.1  
Cấu trúc  
Các bBiến thể được sử dụng để lưu giữ một mẫu dữ liệu tại một thời điểm các mảng thể được  
sử dụng để lưu giữ một số mẫudữ liệu có cùng kiểu. Tuy nhiên, một chương trình có thể yêu cầu xử lý  
các mục dữ liệu kiểu khác nhau trong cùng một đơn vị chung. Ở trường hợp này, cả biến mảng  
đều không thích hợp để sử dụng.  
dụ, một chương trình được viết để lưu trữ dữ liệu trong về một danh mục sách. Chương trình đòi  
hỏi phải nhập lưu trữ tên của mỗi quyển sách (một mảng chuỗi), tên của tác giả (một mảng chuỗi  
khác), lần xuất bản (một số nguyên), giá của quyển sách (một số thực). Một mảng đa chiều không thể  
Các Kiểu dữ liệu Nâng cao và Sắp xếp  
259  
sử dụng để làm điều này, vì các phần tử của một mảng phải có cùng kiểu. Đây chính là lúc mà Trong  
trường hợp này, việc sử dụng cấu trúc sẽ làm cho mọi việc trở nên đơn giản hơn.  
Một cấu trúc bao gồm một số mẫumục dữ liệu, không cần phải cùng kiểu, được nhóm lại với nhau.  
Trong ví dụ trên, một cấu trúc sẽ bao gồm tên sách, tên tác giả, lần xuất bản, và giá của quyển sách.  
Cấu trúc có thể lưu giữ bao nhiêu mụcmẫu dữ liệu cũng được.  
Hình 19.1 mMinh họa sự khác biệt giữa một biến, một mảng một cấu trúc.  
I
L
L
U
S
Tên sách  
I
L
L
I
1
Biến  
O
N
S
U
S
I
O
N
B
A
C
H
Tên  
tác giả  
S
Lần  
xuất bản  
Mảng  
1
Cấu trúc  
Hình 19.1. Sự khác nhau giữa một biến, một mảng một cấu trúc.  
19.1.1 Định nghĩa một cấu trúc  
Một cấu trúc được định nghĩa chính là một khuôn mẫu của biến cấu trúc. Các biến trong cấu trúc được  
gọi là các phần tử của cấu trúc hay thành phần của cấu trúcMột định nghĩa cấu trúc hình thành  
một khuôn mẫu để tạo ra các biến cấu trúc. Các biến trong cấu trúc được gọi là các phần tử của cấu  
trúc hay thành viên của cấu trúc.  
Việc định nghĩa cấu trúc sẽ tạo ra kiểu dữ liệu mới cho phép người dùng sử dụng chúng để khai báo  
các biến kiểu cấu trúc. Các biến trong cấu trúc được gọi là các phần tử hay các thành phần của cấu  
trúc.  
Một cách tổng quát, các phần tử của một cấu trúc quan hệ với nhau một cách logic vì chúng liên quan  
đến một thực thể duy nhất. dụ, về một danh mục sách có thể được biễu diễn như sau:  
struct cat  
{
char bk_name [25];  
char author [20];  
int edn;  
float price;  
};  
Câu lệnh trên định nghĩa một kiểu dữ liệu mới gọicó tên struct cat. Mỗi biến của kiểu này bao gồm  
bốn phần tử - bk_name, author, edn, và price. Câu lệnh không khai báo bất kỳ biến nào và vì vậy  
chương trình không để dành bất kỳ vùng nhớ nào trong bộ nhớ. chỉ định nghĩa cấu trúc của cat. Từ  
khóa struct báo cho trình biên dịch biết rằng một structure đang được định nghĩa. Nhãn cat không  
260  
Lập trình cơ bản C  
phải là tên biến, vì không phải ta đang khai báo biến. Nó là một tên kiểu. Các phần tử của cấu trúc  
được định nghĩa trong dấu móc, và kết thúc toàn bộ câu lệnh bằng một dấu chấm phẩy.  
19.1.2 Khai báo biến kiểu cấu trúc  
Một Kkhi một cấu trúc đã được định nghĩa, chúng một hay nhiều biến kiểu này có thể được khai báota  
thể khai báo một hoặc nhiều biến kiểu này. Điều này có thể thực hiện như sauVí dụ:  
struct cat books1;  
Câu lệnh này sẽ dành đủ vùng nhớ để lưu giữ tất cả các mục trong một cấu trúc. Khai báo trên thực  
hiện chức năng tương tự như các khai báo biến: int xyz float ans. Nó báo với trình biên dịch dành  
ra một vùng lưu trữ cho một biến với kiểu nào đó và gán tên cho biến.  
Cũng như với int, float và các kiểu dữ liệu khác, ta có thể một số bất kỳ các biến kiểu cấu trúc  
đã cho. Trong một chương trình, có thể khai báo hai biến books1 và books2 có kiểu cấu trúc cat . Điều  
này có thể thực hiện được theo nhiều cách.  
struct cat  
{
char bk_name[25];  
char author[20];  
int edn;  
float price;  
} books1, books2;  
hoặc  
struct cat books1, books2;  
hoặc  
struct cat books1;  
struct cat books2;  
Các khai báo này sẽ dành vùng nhớ cho cả hai biến books1 và books2.  
Các phần tử của cấu trúc được truy cập thông qua việc sử dụng toán tử chấm (.), toán tử này còn được  
gọi là toán tử thành viên membership. Cú pháp tổng quát dùng để truy cập một phần tử của cấu trúc  
là:  
structure_name.element_name  
dụ như, lệnh sau đây liên hệtruy cập đến trường bk_name của biến kiểu cấu trúc books1 đã khai  
báo bên trên.  
books1.bk_name  
Để đọc vào tên của quyển sách, câu lệnh sẽ là:  
scanf(“%s”, books1.bk_name);  
Để in ra tên sách, câu lệnh sẽ là:  
printf(“The name of the book is %s”, books1.bk_name);  
Các Kiểu dữ liệu Nâng cao và Sắp xếp  
261  
19.1.3 Khởi tạo các biến cấu trúc  
Giống như các biến mảng, các biến kiểu cấu trúc có thể được khởi tạo tại thời điểm khai báo. Hình  
thức tương tự như cách khởi tạo mảng. Xét cấu trúc sau dùng để lưu số thứ tự và tên nhân viên:  
struct employee  
{
int no;  
char name[20];  
};  
Các biến emp1 emp2 kiểu employee thể được khai báo và khởi tạo như sau:  
struct employee emp1 = {346, “Abraham”};  
struct employee emp2 = {347, “John”};  
Ở đây, sau khi khai báo kiểu cấu trúc như thường lệ, hai biến cấu trúc emp1 emp2 được khai báo  
khởi tạo. SựViệc khai báo và khởi tạo của chúng xảy rađược thực hiện cùng một lúc trong một  
dòng bởi một câu lệnh duy nhất. SựViệc khởi tạo của cấu trúc tương tự như khởi tạo mảng kiểu biến,  
tên biến, và toán tử gán, cuối cùng là danh sách các giá trị được đặt trong cặp móc và được phân cách  
bởi dấu phẩy. theo sau bởi dấu móc chứa danh sách các giá trị, phân cách nhau bởi dấu phẩy.  
19.1.4 Câu lệnh gán sử dụng các cấu trúcThực hiện câu lệnh gán với các biến cấu trúc  
thể gán giá trị của một biến cấu trúc cho một biến khác cùng kiểu bằng cách sử dụng câu lệnh gán  
đơn giản. Chẳng hạn, nếu books1 và books2 là các biến cấu trúc có cùng kiểu, thì câu lệnh sau là hợp  
lệ.  
books2 = books1;  
Cũng những trường hợp, nơi không thể dùng câu lệnh gán trực tiếp, thì có thể sử dụng hàm tạo  
sẳnsẵn memcpy(). Nguyên mẫu của hàm này là:  
memcpy (char * destn, char &source, int nbytes);  
Hàm này thực hiện sao chép nbytes được lưu trữ bắt đầu từ địa chỉ source đến một vùng nhớ khác có  
địa chỉ bắt đầu từ destn. Hàm đòi hỏi người sử dụng phải tả chỉ ra kích cỡ của cấu trúc (nbytes),  
kích cỡ này có thể đạt được bằng cách sử dụng toán tử sizeof(). Sử dụng hàm memcpy(), có thể sao  
chép nội dung của books1 sang books2 như sau:  
memcpy (&books2, &books1, sizeof(struct cat));  
19.1.5 Cấu trúc lồng trong cấu trúc  
Một cấu trúc có thể lồng trong một cấu trúc khác. Tuy nhiên, một cấu trúc không thể lồng trong chính  
nó. Rất nhiều trường hợp thực tế đòi hỏi một cấu trúc nằm trong một cấu trúc khác. Xét ví dụ, một  
mẫu tin về để lưu trữ thông tin về những người mượn sách và chi tiết của quyển sách được mượn cũng  
phải được lưu trữ. Cấu trúc sau đây thể được sử dụng: ta có thể sử dụng cấu trúc sau:  
struct issue  
{
char borrower [20];  
char dt_of_issue[8];  
262  
Lập trình cơ bản C  
struct cat books;  
}issl;  
Câu lệnh này khai báo books một thành phần của cấu trúc issue. Bản thân thành phần này là một  
cấu trúc kiểu struct cat kiểu cấu trúc. Biến Ccấu trúc trên có thể được khởi tạo như sau:  
struct issue issl = {“Jane”, “04/22/03”, {“Illusions”,  
“Richard Bach”, 2, 150.00}};  
Các dấu ngoặc lồng nhau được sử dụng để khởi tạo một cấu trúc nằm trong một cấu trúc.  
Để truy cập vào các phần tử của cấu trúc, hình thức tương tự như cách sử dụng với các cấu trúc bình  
thường, chẳng hạn để truy cập vào tên của người mượn, lệnh sẽ là:  
Đối với biến cấu trúc có thành phần một cấu trúc khác, việc truy cập các thành phần của biến này  
hoàn toàn tương tự đối với một biến cấu trúc thông thường. Chẳng hạn, để truy cập vào tên của người  
mượn ta dùng lệnh là:  
issl.borrower  
Tuy nhiên để truy cập vào phần tử của cấu trúc cat, chính là một phần của cấu trúc issue, biểu thức sau  
đây sẽ được sử dụng:  
Tuy nhiên, để truy cập thành phần author của biến cấu trúc cat biến cấu trúc này lại là thành phần  
của một biến cấu trúc issl ta sử dụng lệnh sau:  
issl.books.author  
Biểu thức này liên hệ đến phần tử author của cấu trúc books trong cấu trúc issl.  
Mức độ lồng của các cấu trúc chỉ bị giới hạn bởi dung lượng hiện thời của bộ nhớ đang . Có thể có  
một cấu trúc lồng trong một cấu trúc rồi lồng trong một cấu trúc khác và v.v…Các tên biến sử dụng  
thường tự tả về hình dạng của nó. Tên của các biến thường được đặt theo cách thức gợi nhớ nội  
dung thông tin mà nó lưu trữ. dụ như:  
company.division.employee.salary  
Cũng cần nhớ rằng nếu một cấu trúc được lồng trong một cấu trúc khác, nó phải được khai báo trước  
cấu trúc khác sử dụng nó.  
19.1.6 Truyền cấu trúc như là các đối số của hàm tham số kiểu cấu trúc  
Một biến cấu trúc có thể được truyền vào một hàm như một đối sốKiểu tham số của một hàm có thể  
cấu trúc. Đây một phương tiện hữu dụng và nó được sử dụng để truyền một nhóm các mục dữ  
liệu có liên quan logic với nhau thay vì phải truyền từng mục một. Đây một phương tiện hữu dụng  
khi ta muốn truyền một nhóm các thành phần dữ liệu có quan hệ logic với nhau thông qua một biến  
thay vì phải truyền từng thành phần một. Tuy nhiên, khi một cấu trúc được sử dụng như một đối  
sốtham số, cần phải lưu ý rằng kiểu của đối sốtham số thực phải trùng với kiểu của tham số hình thức.  
Chẳng hạn như, một cấu trúc được khai báo để lưu trtên, mã số khách hàng và số tiền gửi gốc vào tài  
khoản của khách hàng. Dữ liệu được nhập trong hàm main() cấu trúc được truyền vào hàm  
intcal()-hàm tính toán số tiền lãi phải trả, việc toán số tiền lãi phải trả được thực hiện bằng cách gọi  
hàm intcal() có một tham số kiểu cấu trúc. Đoạn lệnh như sau:  
dụ 1:  
#include <stdio.h>  
Các Kiểu dữ liệu Nâng cao và Sắp xếp  
263  
struct strucintcal /* Defines the structure */  
{
char name[20];  
int numb;  
float amt;  
};  
void main()  
{
struct strucintcal xyz; /* Declares a variable */  
void intcal(struct strucintcal);  
clrscr();  
/* Accepts data into the structure */  
printf("\nEnter Customer name: ");  
gets(xyz.name);  
printf("\nEnter Customer number: ");  
scanf("%d", &xyz.numb);  
printf("\nEnter Principal amount: ");  
scanf("%f", &xyz.amt);  
intcal(xyz); /* Passes the structure to a function */  
getch();  
}
void intcal(struct strucintcal abc)  
{
float si, rate = 5.5, yrs = 2.5;  
/* Computes the interest */  
si = (abc.amt * rate * yrs) / 100;  
printf ("\nThe customer name is %s", abc.name);  
printf("\nThe customer number is %d", abc.numb);  
printf("\nThe amount is %f", abc.amt);  
printf("\nThe interest is %f", si);  
return;  
}
Kết quả của chương trình trên được minh họa như sau: Một kết xuất mẫu của chương trình trên như  
sau:  
Enter Customer name: Jane  
Enter Customer number: 6001  
Enter Principal Amount: 30000  
The customer name is Jane  
The customer number is 6001  
The amount is 30000.000000  
264  
Lập trình cơ bản C  
The interest is 4125.000000  
thể định nghĩa một cấu trúc mà không có nhãn. Điều này hữu dụng khi một biến được khai báo  
cùng lúc với định nghĩa cấu trúc của nó. Nhãn sẽ không cần thiết trong trường hợp này.  
19.1.7 Mảng các cấu trúc  
Một trong những cách sử dụng thông thường của cấu trúc là mảng cấu trúc. Để khai báo một mảng các  
cấu trúc, một cấu trúc sẽ được định nghĩa trước, và sau đó một biến mảng kiểu đó sẽ được khai báo.  
dụ như, để khai báo một mảng các cấu trúc có kiểu cat, câu lệnh sẽ là:  
struct cat books[50];  
Giống như tất cả các biến, mảng các cấu trúc bắt đầu tại chỉ số 0. Tên mảng theo sau bởi chỉ số nằm  
trong dấu móc vuông đại diện cho một phần tử của mảng Tên mảng chỉ số nằm trong cặp dấu ngoặc  
vuông theo sau tên mảng đại diện cho một phần tử của mảng. Sau lệnh khai báo trên, phần tử này là  
một cấu trúc theo định nghĩa của nó. Vì vậy tất cả các qui tắc dùng để truy xuất đến các phần tử của  
cấu trúc đều được áp dụng trên phần tử mảng nàyluật dùng để liên hệ đến các trường (hay các phần tử)  
của cấu trúc đều áp dụng được về sau. Sau khi mảng cấu trúc books được khai báo,  
books[4].author  
sẽ liên hệ đến biến tương ứng là thành phần author của phần tử thứ tư của trong mảng books.  
Các Kiểu dữ liệu Nâng cao và Sắp xếp  
265  
19.1.8 Khởi tạo các mảng cấu trúc  
Một mảng kiểu bất kỳ được khởi tạo bằng cách liệt kê danh sách giá trị của các phần tử trong một cặp  
dấu móc. Luật này cũngvẫn đúng thậm chí khi các phần tử mảng là các cấu trúc. Một khởi tạo hiệu  
quả chứa các dấu móc lồng nhauVì mỗi phần tử của mảng một cấu trúc, mà giá trị khởi tạo của  
một cấu trúc được đặt trong cặp dấu móc, nên ta phải sử dụng các cặp dấu móc lồng nhau khi khởi tạo  
mảng các cấu trúc. Xét ví dụ sau:  
struct unit  
{
char ch;  
int i;  
};  
struct unit series[3] =  
{
{‘a’, 100},  
{‘b’, 200},  
{‘c’, 300},  
};  
Đoạn lệnh này khai báo series một mảng cấu trúc gồm 3 phần tử, mỗi phần tử kiểu unit. Khi  
khởi tạo, mỗi phần tử được khởi tạo một cấu trúc nên giá trị của được đặt trong cặp dấu móc.,  
Vì và vậy toàn bộ danh sáchgiá trị các phần tử được đóng trong dấu móc để cho biết đang khởi tạo  
một mảng.  
266  
Lập trình cơ bản C  
19.1.9 Con trỏ đến cấu trúc  
C hỗ trợ con trỏ đến cấu trúc, nhưng một số khía cạnh đặc biệt đối với con trỏ cấu trúc. Giống như  
các kiểu con trỏ khác, con trỏ cấu trúc được khai báo bằng cách đặt dấu * trước tên của biến cấu trúc.  
dụ, câu lệnh sau đây khai báo con trỏ ptr_bk của kiểu cấu trúc cat.  
struct cat *ptr_bk;  
Bây giờ để gán địa chỉ của biến cấu trúc books kiểu cat cho ptr_bk, câu lệnh sẽ như sau:  
ptr_bk = &books;  
Toán tử -> được dùng để truy cập vàođến phần tử của một cấu trúc sử dụng một con trỏ cấu trúc. Toán  
tử này là một tổ hợp của dấu trừ (-) và dấu lớn hơn (>) và nó được biết đến như một toán tử tổ hợp.  
dụ như, trường author thể được truy cập theo một trong các cách sau đây:  
ptr_bk->author  
hoặc  
books.author  
hoặc  
(*ptr_bk).author  
Trong biểu thức cuối cùng, dấu ngoặc bắt buộc vì toán tử chấm (.) có độ ưu tiên cao hơn toán tử vô  
hướng (*). Không có dấu ngoặc, trình biên dịch sẽ sinh ra một lỗi, ptr_bk (một con trỏ) thì không  
tương thích trực tiếp với toán tử chấmvì toán tử chấm không được áp dụng trên biến con trỏ ptr_bk.  
Cũng như tất cả các khai báo con trỏ khác, việc khai báo một con trỏ chỉ cấp phát không gian cho con  
trỏ mà không cấp phát cho nơi trỏ đến. vậy, khi một con trỏ cấu trúc được khai báo, không  
gian được cấp phát là dành cho địa chỉ của cấu trúc chứ không phải bản thân cấu trúc.  
19.1.10 Truyền con trỏ cấu trúc như là các đối tham số  
thể sử dụng các con trỏ cấu trúc như đối sốtham số của hàm. Tại thời điểm gọi hàm, một con trỏ  
cấu trúc hoặc địa chỉ tường minh của một biến cấu trúc được truyền vào hàm. Điều này cho phép một  
hàm có thể sửa đổi các phần tử của cấu trúc một cách trực tiếp.  
19.2  
Từ khóa typedef  
Một kiểu dữ liệu mới thể được định nghĩa bằng cách sử dụng từ khóa typedef. Từ khóa này không  
tạo ra một kiểu dữ liệu mới, định nghĩa một tên mới cho một kiểu đã có. Cú pháp tổng quát của câu  
lệnh typedef là:  
typedef type name;  
trong đó type một kiểu dữ liệu cho phép bất kỳ name một tên mới cho kiểu dữ liệu này.  
Tên mới được định nghĩa, một tên thêm vào, chứ không phải là tên thay thế, cho kiểu dữ liệu đã có.  
dụ như, một tên mới cho float có thể được định nghĩa theo cách sau:  
typedef float deci;  
Các Kiểu dữ liệu Nâng cao và Sắp xếp  
267  
Câu lệnh này sẽ báo cho trình biên dịch biết để nhận dạng deci một tên khác của float. Một biến  
float thể được định nghĩa sử dụng deci như sau:  
deci amt;  
Ở đây, amt một biến số thực kiểu deci, chính là một tên khác của float. Sau khi được định nghĩa,  
deci thể được sử dụng như một kiểu dữ liệu trong câu lệnh typedef để gán một tên khác cho kiểu  
float. Chẳng hạn,  
typedef deci point;  
Câu lệnh trên báo cho trình biên dịch biết để nhận dạng point như một tên khác của deci, cũng  
chính là một tên khác của float. Đặc tính typedef đặc biệt tiện lợi khi định nghĩa các cấu trúc, vì ta  
không cần nhắc lại nhãn struct mỗi khi một sử dụng cấu trúc. vậy, cấu trúc có thể được liên hệ một  
cách chính xác hơnKhi đó việc sử dụng cấu trúc sẽ thuận tiện hơn. Thêm vào đó, tên cho một kiểu cấu  
trúc do người dùng định nghĩa thường gợi nhớ đến mục đích của cấu trúc trong chương trình. Một  
cách tổng quát, một cấu trúc do người dùng định nghĩa thể được viết như sau:  
typedef struct new_type  
{
type var1;  
type var2;  
}
Ở đây, new_type kiểu cấu trúc do người dùng định nghĩa và nó không phải một biến cấu trúc.  
Bây giờ, các biến kiểu cấu trúc có thể được định nghĩa theo kiểu dữ liệu mới. Một dụ như sau:Ví  
dụ:  
typedef struct  
{
int day;  
int month;  
int year;  
} date;  
date due_date;  
Ở đây, date một kiểu dữ liệu mới due_date một biến kiểu date.  
Cần nhớ rằng typedef không thể sử dụng với storage classes.  
19.3  
Sắp xếp mảng (Sorting Arrays)  
Sắp xếp nghĩa xếp mảng dữ liệu theo một thứ tự đãxác định như tăng dần hay giảm dần. Dữ liệu  
trong một mảng sẽ dễ dàng tìm được nếu mảng được sắp xếpKhi mảng đã được sắp xếp, việc tìm kiếm  
trên mảng trở nên dễ dàng hơn.  
một số phương pháp để sắp xếp mảng. Chúng ta sẽ xem xét hai phương pháp sau đây:  
Bubble Sort  
Insertion Sort  
Các phương pháp được trình bày sau đây áp dụng đối với mảng sắp xếp theo thứ tự tăng dần  
19.3.1 Bubble Sort  
268  
Lập trình cơ bản C  
Tên Bản thân tên của quá trình sắp xếp này đã tả cách thức nó làm việc. Ở đây, việc so sánh bắt  
đầu từ phần tử dưới cùng và phần tử có giá trị nhỏ hơn sẽ nổi bọt dần lên trên đỉnh. Quá trình sắp xếp  
một mảng 5-phần tử theo thứ tự tăng dần được cho như sau:  
So sánh giá trị trong phần tử thứ 5 với giá trị trong phần tử thứ 4.  
Nếu giá trị trong phần tử thứ 5 nhỏ hơn giá trị trong phần tử thứ 4, thì giá trị trong hai phần tử sẽ  
được hoántrao đổi.  
Kế tiếp, so sánh giá trị trong phần tử thứ 4 với giá trị trong phần tử thứ 3, và theo cách tương tự,  
các giá trị sẽ được traohoán đổi nếu giá trị trong phần tử dướisau nhỏ hơn giá trị của phần tử  
trướcên.  
So sánh gtrị trong phần tử thứ 3 với giá trị trong phần tử thứ 2, và quá trình so sánh và traohoán  
đổi này cứ thế tiếp tục.  
Sau một lượt, giá trị nhỏ nhất sẽ được dờiđặt vào đến phần tử đầu tiên. Một cách nôm na, có thể  
phát biểu rằng giá trị nhỏ nhất đã ‘nổi lên’.  
Trong lượt kế tiếp, việc so sánh lại bắt đầu với phần tử thấp nhấtcuối cùng, và so sánh dần lên đến  
phần tử thứ 2. Vì phần tử thứ nhất đã chứa phần tửgiá trị nhỏ nhất, không cần thiết phải so sánh nó  
nữa.  
Với cách như vậy, ở cuối quá trình sắp xếp, các phần tử nhỏ hơn sẽ nổi bọtdần lên đỉnhtrên, trong  
khi các giá trị lớn hơn sẽ chìm xuống. Hình 19.2 minh họa cho phương pháp buble sort.  
23  
90  
9
23  
90  
9
23  
90  
9
23  
9
9
23  
90  
16  
25  
90  
16  
25  
25  
16  
16  
25  
16  
25  
9
9
9
9
23  
90  
16  
25  
23  
90  
16  
25  
23  
16  
90  
25  
16  
23  
90  
25  
9
9
9
16  
23  
90  
25  
16  
23  
25  
90  
16  
23  
25  
90  
9
9
16  
23  
25  
90  
16  
23  
25  
90  
Các Kiểu dữ liệu Nâng cao và Sắp xếp  
269  
9
16  
23  
25  
90  
Figure 19.2: Bubble Sort  
Chương trình thực hiện sắp xếp mảng theo phương pháp bubble sort được cho như sau:  
dụ 2:  
#include <stdio.h>  
void main()  
{
int i, j, temp, arr_num[5] = { 23, 90, 9, 25, 16};  
clrscr();  
for(i = 3; i >= 0; i--) /* Tracks every pass */  
for(j = 4; j >= 4 - i; j--) /* Compares elements */  
{
if(arr_num[j] < arr_num[j - 1])  
{
temp = arr_num[j];  
arr_num[j] = arr_num[j - 1];  
arr_num[j - 1] = temp;  
}
}
printf("\nThe sorted array");  
for(i = 0; i < 5; i++)  
printf("\n%d", arr_num[i]);  
getch();  
}
270  
Lập trình cơ bản C  
19.3.2 Insertion Sort  
Trong phương pháp Insertion sort, mỗi phần tử trong mảng được xem xét,ta xét mỗi phần tử của  
mảng đặt vào vị trí đúng của giữa các phần tử đã được sắp xếp. Khi phần tử cuối cùng được đặt  
vào vị trí đúng của nó, thì mảng đã được sắp xếp. dụ, xét một mảng có 5 phần tử,  
Giá trị trong phần tử thứ nhất được xem như đã ở đúng thứ tự.  
So sánh giá trị trong phần tử thứ hai với phần mảng đã sắp xếp, hiện tại chỉ phần tử thứ  
nhất.  
Nếu giá trị trong phần tử thứ hai nhỏ hơn, được xen trước phần tử thứ nhất. Bây giờ, hai phần  
tử đầu tiên đã tạo thành phần danh sách sắp xếp phần còn lại tạo thànhlà danh sách chưa sắp  
xếp.  
Phần tử kế tiếp trong danh sách chưa sắp xếp, phần tử thứ 3, được so sánh với danh sách đã sắp  
xếp.  
Nếu giá trị trong phần tử thứ 3 nhỏ hơn phần tử thứ 1, giá trị trong phần tử thứ 3 được xen trước  
phần tử thứ 1.  
Ngược lại, nếu giá trị trong phần tử thứ 3 nhỏ hơn phần tử thứ 2, giá trị trong phần tử thứ 3 được  
xen trước phần tử thứ 2. Bây giờ, phần sắp xếp của mảng chứagồm 3 phần tử, trong khi phần chưa  
sắp xếp chứagồm 2 phần tử còn lại.  
Quá trình so sánh các phần tử trong danh sách chưa sắp xếp với các phần tử trong danh sách đã  
sắp xếp tiếp tục cho đến khi phần tử cuối cùng trong mảng đã được so sánh đặt vào vị trí đúng  
của .  
Ở cuối quá trình sắp xếp, mỗi phần tử được xen vào đúng vị trí của nó. Hình 19.3 minh họa cách làm  
việc của insertion sort.  
23  
90  
9
23  
90  
9
25  
16  
25  
16  
23  
90  
9
9
23  
90  
25  
16  
25  
16  
9
9
9
9
23  
90  
25  
16  
23  
90  
25  
16  
23  
90  
25  
16  
23  
25  
90  
16  
9
9
9
23  
25  
90  
23  
25  
90  
16  
23  
25  
Các Kiểu dữ liệu Nâng cao và Sắp xếp  
271  
16  
16  
90  
Figure 19.3: Insertion Sort  
Chương trình thực hiện sắp xếp mảng theo phương pháp insertion sort được cho như sau:  
dụ 3:  
#include<stdio.h>  
void main()  
{
int i, j, arr[5] = { 23, 90, 9, 25, 16 };  
char flag;  
clrscr();  
/*Loop to compare each element of the unsorted part of the  
array*/  
for(i = 1; i < 5; i++)  
/*Loop for each element in the sorted part of the array*/  
for(j = 0, flag = 'n'; j < i && flag == 'n'; j++)  
{
if(arr[j] > arr[i])  
{
/*Invoke the function to insert the number*/  
insertnum(arr, i, j);  
flag = 'y';  
}
}
printf("\n\nThe sorted array\n");  
for(i = 0; i < 5; i++)  
printf("%d\t", arr[i]);  
getch();  
}
insertnum(int arrnum[], int x, int y)  
{
int temp;  
/*Store the number to be inserted*/  
temp = arrnum[x];  
/*Loop to push the sorted part of the array down from the  
position where the number has to inserted*/  
for(; x > y; x--)  
arrnum[x] = arrnum[x - 1];  
/*Insert the number*/  
arrnum[x] = temp;  
272  
Lập trình cơ bản C  
}
Các Kiểu dữ liệu Nâng cao và Sắp xếp  
273  
Tóm tắt  
Một cấu trúc là một nhóm các biến kiểu dữ liệu khác nhau được gom lại dưới cùng một tên.Một  
cấu trúc là tập các biến thể kiểu dữ liệu khác nhau được nhóm lại với nhau dưới cùng một  
tên.  
Một định nghĩa cấu trúc tạo thành một khuôn mẫu, khuôn mẫu này có thể được sử dụng để tạo ra  
các biến cấu trúc.Việc định nghĩa cấu trúc sẽ tạo ra kiểu dữ liệu mới cho phép người dùng sử  
dụng chúng để khai báo các biến kiểu cấu trúc  
Các phần tử độc lập của cấu trúc được tham chiếu đếntruy cập bằng cách sử dụng toán tử chấm  
(.), hay còn được gọi toán tử thành viên.  
Các giá trị của một biến cấu trúc có thể được gán cho một biến khác có cùng kiểu bằng cách sử  
dụng câu lệnh gán đơn giản.  
thể một cấu trúc nằm trong một cấu trúc khác. Tuy nhiên một cấu trúc không thể lồng trong  
chính nó.  
Một biến cấu trúc có thể được truyền vào một hàm như một đốitham số.  
Cách cài đặtsử dụng thông dụng nhất của cấu trúc là dưới hình thức các mảng cấu trúc.  
Toán tử -> được sử dụng để truy cập vào các phần tử của một cấu trúc thông qua một con trỏ trỏ  
đến cấu trúc đó.  
Một kiểu dữ liệu mới thể được định nghĩa bằng từ khóa typedef.  
Hai kỹ thuậtphương pháp dùng để sắp xếp một mảng là bubble sort và insertion sort.  
Trong bubble sort, giá trị của các phần tử được so sánh với giá trị của phần tử kế tiếp. Trong  
phương pháp này, các phần tử nhỏ hơn nổi lên dần, và cuối cùng mảng sẽ được sắp xếp.  
Trong insertion sort, ta xét mỗi phần tử trong mảng sẽ được xem xét, và chèn vào vị trí đúng của  
giữa các phần tử đã được sắp xếp.  
274  
Lập trình cơ bản C  
Kiểm tra tiến độ học tập  
1. Một __________ nhóm một số mụcẫu dữ liệu lại với nhau, các mụcẫu dữ liệu này không cầnnhất  
thiết phải có cùng kiểu.  
2. Các phần tử của cấu trúc được tham chiếutruy cập đến thông qua việc sử dụng _________.  
3. Các giá trị của một biến cấu trúc có thể được gán cho một biến khác có cùng kiểu bằng cách sử  
dụng câu lệnh gán đơn giản.  
(Đúng / Sai)  
4. Không thể một cấu trúc nằm trong một cấu trúc khác.  
5. Một kiểu dữ liệu mới thể được định nghĩa sử dụng từ khóa _________.  
6. Trong bubble sort, các phần tử ______________ được so sánh.  
(Đúng / Sai)  
7. Trong insertion sort, nếu một phần tử chưa được sắp xếp phải được đặt vào một vị trí đã được sắp  
xếp nào đó, thì các giá trị này sẽ được trao đổi với nhau.  
(Đúng / Sai)  
Các Kiểu dữ liệu Nâng cao và Sắp xếp  
275  
Bài tập tự làm  
1. Viết một chương trình C để cài đặt một hệ thống quản lý kho. Hãy lưu trữ số, tên hàng, giá cả  
số lượng đang của mỗi món hàng trong một cấu trúc. Nhập chi tiết của 5 món hàng vào một  
mảng các cấu trúc và hiển thị tên từng món hàng và tổng giá trị của nó. Ở cuối chương trình , hãy  
hiển thị tổng giá trị của kho hàng.  
2. Viết một chương trình C để lưu trữ các tên và điểm số của 5 sinh viên trong một mảng cấu trúc.  
Hãy sắp xếp mảng cấu trúc theo thứ tự điểm số giảm dần. Hiển thị 3 điểm số cao nhất.  
276  
Lập trình cơ bản C  
doc 18 trang Thùy Anh 26/04/2022 14860
Bạn đang xem tài liệu "Giáo trình Lập trình cơ bản C - Bài 19: Các kiểu dữ liệu nâng cao và sắp xếp", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

File đính kèm:

  • docgiao_trinh_lap_trinh_co_ban_c_bai_19_cac_kieu_du_lieu_nang_c.doc