Kiểu dữ liệu Struct và một số thuật toán sắp xếp
- 08-11-2023
- Toanngo92
- 0 Comments
Mục lục
Giới thiệu
Trong thế giới thực, các ứng dụng thường yêu cầu lưu trữ nhiều loại dữ liệu khác nhau. Các kiểu dữ liệu được xác định sẵn trong ngôn ngữ lập trình C có thể không đủ để đáp ứng nhu cầu trong các tình huống như vậy. Vì vậy, ngôn ngữ C cho phép tạo ra các kiểu dữ liệu tùy chỉnh. Một trong những kiểu dữ liệu tùy chỉnh đó là cấu trúc (structure). Một cấu trúc là một nhóm biến được nhóm lại dưới một tên duy nhất. Một kiểu dữ liệu cũng có thể được gán một tên mới bằng từ khóa “typedef.”
Ứng dụng lưu trữ lượng lớn dữ liệu. Trong các trường hợp như vậy, việc tìm kiếm một mục dữ liệu cụ thể có thể tốn rất nhiều thời gian. Sắp xếp các giá trị thành một trình tự nào đó giúp giảm bớt vấn đề này. Trong phần này, chúng ta cũng sẽ xem xét một số thuật toán để sắp xếp mảng.
Làm việc với cấu trúc và sắp xếp là phần quan trọng của việc quản lý và xử lý dữ liệu trong các ứng dụng thực tế. Các cấu trúc cho phép bạn tổ chức và lưu trữ dữ liệu phức tạp, trong khi các thuật toán sắp xếp giúp bạn sắp xếp dữ liệu một cách hiệu quả để tìm kiếm và truy cập nhanh chóng.
Cấu trúc (Structures)
Cấu trúc (structures) trong ngôn ngữ lập trình C cho phép bạn tổng hợp nhiều dữ liệu khác nhau lại với nhau dưới một tên duy nhất. Khi bạn cần lưu trữ và làm việc với nhiều loại dữ liệu khác nhau dưới dạng một đơn vị thống nhất, cấu trúc là một công cụ hữu ích.
Một biến chỉ có thể chứa một mảnh thông tin một lúc, và mảng chỉ có thể chứa nhiều mảnh thông tin cùng một loại dữ liệu. Tuy nhiên, có những tình huống mà bạn cần làm việc với các mục dữ liệu khác nhau cùng nhau như một đơn vị.
Ví dụ, bạn viết một chương trình để lưu trữ thông tin về một danh mục sách. Chương trình yêu cầu lưu trữ tên của từng cuốn sách (một mảng ký tự), tên tác giả (một mảng ký tự khác), số bản (một số nguyên), giá của cuốn sách (một số thực). Một mảng nhiều chiều không thể được sử dụng để làm điều này, vì mảng phải có cùng kiểu dữ liệu. Đây là nơi mà cấu trúc giúp đơn giản hóa mọi thứ.
Một cấu trúc bao gồm một số mục dữ liệu, không cần phải có cùng kiểu dữ liệu, được nhóm lại dưới một tên duy nhất. Trong ví dụ ở trên, một cấu trúc có thể bao gồm tên sách, tên tác giả, số bản và giá của cuốn sách. Cấu trúc có thể chứa nhiều mục dữ liệu như bạn muốn.
Định nghĩa một cấu trúc
Một định nghĩa cấu trúc tạo thành một 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 thành phần cấu trúc hoặc thành phần cấu trúc.
Thường thì các thành phần trong một cấu trúc có mối quan hệ logic với nhau vì chúng tham chiếu đến một thực thể duy nhất. Ví dụ về danh mục sách có thể được biểu thị như sau:
struct catalog {
char bk_name[25];
char author[20];
int edns;
float price;
};
Trong ví dụ trên, câu lệnh định nghĩa một kiểu dữ liệu mới gọi là “struct catalog.” Mỗi biến của kiểu này bao gồm bốn phần tử: bk_name, author, edns và price. Câu lệnh này không khai báo bất kỳ biến cụ thể nào và không chiếm bất kỳ vùng lưu trữ nào trong bộ nhớ. Nó chỉ định cấu trúc của “struct catalog.” Từ khóa “struct” cho biết cho trình biên dịch rằng một cấu trúc đang được định nghĩa. “catalog” không phải là tên biến, vì không có biến cụ thể nào được khai báo. Các phần tử của cấu trúc được định nghĩa trong dấu ngoặc nhọn và câu lệnh chấm phẩy kết thúc câu lệnh.
Khai báo Biến Cấu Trúc
Sau khi cấu trúc đã được định nghĩa, bạn có thể khai báo một hoặc nhiều biến thuộc kiểu đó. Việc này có thể được thực hiện như sau:
struct cat books1;
Câu lệnh này sẽ cấp phát đủ bộ nhớ để lưu trữ tất cả các mục trong cấu trúc. Câu lệnh khai báo trên thực hiện một chức năng tương tự như việc khai báo biến như int xyz và float abc. Nó thông báo cho trình biên dịch để dành bộ nhớ cho một biến có kiểu cụ thể và gán một tên cho biến.
Tương tự như với các kiểu dữ liệu như int, float, có thể có bất kỳ số lượng biến nào thuộc kiểu cấu trúc cụ thể. Trong chương trình, bạn có thể khai báo hai biến book1 và book2 thuộc kiểu cấu trúc catalog. Điều này có thể được thực hiện theo một số cách.
struct cat {
char bk_name[25];
char author[20];
int edn;
float price;
} books1, books2;
or
struct cat books1, books2;
or
struct cat books1;
struct cat books2;
Những khai báo này dành một phần bộ nhớ cho cả books1 và books2.
Các phần tử cấu trúc riêng lẻ được tham chiếu thông qua việc sử dụng toán tử dấu chấm (.), cũng được gọi là toán tử thành viên. Cú pháp chung để truy cập một phần tử cấu trúc là:
structure_name.element_name
Ví dụ, đoạn mã sau đây tham chiếu đến trường bk_name của biến cấu trúc books được khai báo trước đó.
books1.bk_name
Để đọc tên một cuốn sách, đoạn code sẽ là:
scanf("%s", books1.bk_name);
Để in tên sách, mã sẽ là:
printf("the name of the book is %s", books1.bk_name);
Khởi tạo cấu trúc
Giống như biến và mảng, biến cấu trúc có thể được khởi tạo tại điểm khai báo. Định dạng này tương tự với việc khởi tạo mảng. Xem xét cấu trúc sau đây lưu trữ số nhân viên và tên:
struct employees
{
int no;
char name[20];
};
Biến emp1 và emp2 thuộc kiểu employee có thể được khai báo và khởi tạo như sau:
struct employee emp1 = {346, "Abraham"};
struct employee emp2 = {347, "John"};
Ở đây, sau khai báo thông thường của kiểu cấu trúc, hai biến cấu trúc emp1 và emp2 được khai báo và khởi tạo. Khai báo và khởi tạo của chúng xảy ra cùng lúc thông qua một dòng mã duy nhất. Khởi tạo của một cấu trúc tương tự với khởi tạo mảng – kiểu biến, tên biến, toán tử gán, và sau đó là dấu ngoặc nhọn bao gồm danh sách các giá trị, với các giá trị được phân tách bằng dấu phẩy.
Câu lệnh gán được sử dụng với cấu trúc
Có thể gán giá trị của một biến cấu trúc cho một biến cấu trúc khác cùng kiểu bằng một câu lệnh gán đơn giản. Đó là, nếu books1 và books2 là các biến cấu trúc cùng kiểu, thì câu lệnh sau là hợp lệ:
books2 = books1;
Có thể gán giá trị của một biến cấu trúc cho một biến cấu trúc khác cùng kiểu bằng một câu lệnh gán đơn giản. Đó là, nếu books1 và books2 là các biến cấu trúc cùng kiểu, thì câu lệnh sau là hợp lệ:
books2 = books1;
Cũng có trường hợp nơi gán trực tiếp không khả thi, bạn có thể sử dụng hàm tích hợp memcpy(). Nguyên mẫu của hàm này là:
void *memcpy(void *dest, const void *src, size_t nbytes);
Hàm này sao chép nbytes byte từ địa chỉ src đến một khối nbytes byte bắt đầu từ địa chỉ dest. Hàm này yêu cầu người dùng xác định kích thước của cấu trúc (nbytes), điều này có thể được lấy thông qua hàm sizeof. Sử dụng memcpy(), bạn có thể sao chép nội dung của books1 vào books2 như sau:
memcpy(&books2, &books1, sizeof(struct cat));
Trong ví dụ trên, books1 và books2 là các biến cấu trúc của kiểu struct cat. Để sao chép toàn bộ nội dung từ books1 sang books2, bạn sử dụng hàm memcpy() với kích thước của cấu trúc là sizeof(struct cat).
Cấu trúc bên trong cấu trúc
Có thể có một cấu trúc trong một cấu trúc khác. Tuy nhiên, một cấu trúc không thể lồng vào chính nó. Có lúc, việc có một cấu trúc trong một cấu trúc khác là cần thiết. Xem xét một ví dụ, nơi bạn cần duy trì thông tin về người mượn sách và chi tiết về các cuốn sách mượn. Cấu trúc sau có thể được sử dụng cho mục đích này:
struct issue {
char borrower[20];
char dt_of_issue[17];
struct cat books;
};
Câu lệnh trên định books là một thành phần của cấu trúc issue. Thành phần này chính là một cấu trúc kiểu struct cat. Cấu trúc có thể được khởi tạo như sau:
struct issue iss1 = {"Jane", "04/22/03", {"Illusions", "Richard Bach", 2, 150.00}};
Dấu ngoặc nhọn lồng vào nhau được sử dụng để khởi tạo một cấu trúc trong một cấu trúc.
Để truy cập các phần tử của cấu trúc, định dạng sẽ tương tự như với cấu trúc bình thường. Ví dụ, để truy cập tên người mượn, mã sẽ là:
iss1.borrower
Tuy nhiên, để truy cập các phần tử của cấu trúc cat, mà là một phần của cấu trúc issue, biểu thức sau sẽ được sử dụng:
iss1.books.author
Điều này tham chiếu đến phần tử author trong cấu trúc books trong cấu trúc iss1.
Cấu trúc lồng vào cấu trúc có thể có mức lồng bên trong khá sâu, và tên biến thường được chọn sao cho mô tả rõ ràng về cấu trúc.
Ví dụ, nếu bạn có cấu trúc company, trong đó có một cấu trúc division, và trong cấu trúc division lại có một cấu trúc employees, và trong cấu trúc employees lại có một trường salary, bạn có thể truy cập salary bằng cách sử dụng toán tử dấu chấm như sau:
company.division.employees.salary
Ngoài ra, hãy nhớ rằng nếu một cấu trúc được lồng trong một cấu trúc khác, thì cấu trúc được lồng này phải được khai báo trước cấu trúc sử dụng nó. Điều này đảm bảo rằng trình biên dịch hiểu cấu trúc được sử dụng trong cấu trúc khác.
Truyền cấu trúc làm đối số
Trong ngôn ngữ lập trình C, một biến cấu trúc có thể được truyền như một đối số cho một hàm. Điều này là một tính năng hữu ích và được sử dụng để truyền các nhóm dữ liệu có mối quan hệ logic cùng nhau thay vì truyền chúng một cách riêng lẻ. Tuy nhiên, khi một cấu trúc được sử dụng như một đối số, cần chú ý rằng kiểu của đối số phải khớp với kiểu của tham số.
Ví dụ, một cấu trúc được khai báo để lưu trữ tên khách hàng, số và số tiền gốc gửi bởi khách hàng. Dữ liệu được nhập vào trong hàm main() và cấu trúc này được truyền vào hàm inteal() để tính toán lãi phải trả. Đoạn mã là như sau:
#include <stdio.h>
void main()
{
struct strucintcal /* Định nghĩa cấu trúc */
{
char name[20];
int numb;
float amt;
} xyz; /* Khai báo một biến cấu trúc */
printf("\nEnter name: ");
gets(xyz.name);
printf("\nEnter Customer number: ");
scanf("%d", &xyz.numb);
printf("\nEnter Principal amount: ");
scanf("%f", &xyz.amt);
inteal(xyz); /* Truyền cấu trúc vào một hàm */
}
void inteal(struct strucintcal abc)
{
float si, rate = 5.5, yrs = 2.5;
/* Tính toán lãi */
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 %.6f", abc.amt);
printf("\nThe interest is %.6f", si);
}
Kết quả của chương trình ví dụ trên sẽ là:
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
The interest is 4125.000000
Trong ví dụ này, biến xyz là một biến cấu trúc kiểu struct strucintcal. Biến này được truyền vào hàm inteal() để tính toán lãi.
Mảng cấu trúc
Một trong những cách sử dụng phổ biến nhất của cấu trúc là trong mảng của các cấu trúc. Để khai báo một mảng của các cấu trúc, bạn đầu tiên định nghĩa một cấu trúc, sau đó khai báo một biến mảng của kiểu đó. Ví dụ, để khai báo một mảng của các cấu trúc kiểu struct cat, câu lệnh sẽ là:
struct cat books[50];
Tương tự như tất cả các biến mảng, mảng của các cấu trúc bắt đầu chỉ mục từ 0. Tên mảng, sau đó là chỉ mục của nó được bao bọc bởi dấu ngoặc vuông đại diện cho một phần tử của mảng đó. Sau câu lệnh trên, phần tử này là một cấu trúc theo định nghĩa. Vì vậy, tất cả các quy tắc về việc tham chiếu tới các trường cấu trúc áp dụng sau đó.
Sau khi mảng cấu trúc books được khai báo, bạn có thể sử dụng nó để lưu trữ nhiều cuốn sách, mỗi cuốn sách là một cấu trúc kiểu struct cat.
books[4].author
Khi bạn sử dụng mảng cấu trúc, bạn có thể truy cập trực tiếp vào các trường của các phần tử của mảng. Ví dụ, books[4].author sẽ tham chiếu đến biến author của phần tử thứ tư trong mảng books.
Khởi tạo mảng cấu trúc
Khởi tạo của mảng cấu trúc được thực hiện bằng cách đặt danh sách các giá trị của các phần tử trong nó bên trong cặp dấu ngoặc nhọn. Quy tắc này áp dụng ngay cả khi các phần tử là cấu trúc.
Ví dụ sau minh họa cách khởi tạo một mảng cấu trúc:
struct unit {
char ch;
int i;
};
struct unit series[3] = {
{"a", 100},
{"b", 200},
{"c", 300}
};
Ở đây, mảng series được khai báo là một mảng của các cấu trúc, mỗi cấu trúc kiểu struct unit. Khi khởi tạo, mỗi phần tử của mảng được khởi tạo như một cấu trúc. Toàn bộ danh sách này sau đó được bao bọc trong dấu ngoặc nhọn để chỉ ra rằng mảng đang được khởi tạo.
Con trỏ tới cấu trúc
C hỗ trợ con trỏ tới cấu trúc, nhưng có một số khía cạnh đặc biệt về con trỏ cấu trúc. Giống như 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 biến cấu trúc. Ví dụ, câu lệnh sau đây khai báo con trỏ ptr_bk kiểu cấu trúc cat:
cat *ptr_bk;
Bây giờ để gán địa chỉ của biến cấu trúc books kiểu struct cat cho con trỏ, câu lệnh sẽ là:
ptr_bk = &books;
Toán tử -> được sử dụng để truy cập các phần tử của cấu trúc bằng cách sử dụng con trỏ. Toán tử này là sự kết hợp của dấu trừ – và dấu mũi tên > và còn được gọi là toán tử kết hợp. Ví dụ, trường author có thể được truy cập bằng một trong các cách sau: ptr_bk->author, books.author, hoặc (*ptr_bk).author.
Trong biểu thức cuối cùng, dấu ngoặc đơn là bắt buộc vì toán tử dấu chấm . có mức độ ưu tiên cao hơn so với toán tử gián đoạn *. Mà không có dấu ngoặc đơn, trình biên dịch sẽ tạo ra một lỗi, vì con trỏ ptr_bk không tương thích trực tiếp với toán tử dấu chấm.
Tương tự như với tất cả các khai báo con trỏ, khai báo một con trỏ cấu trúc cấp phát không gian cho con trỏ và không phải cho cấu trúc mà nó trỏ tới.
Cấu trúc con trỏ làm đối số
Các con trỏ cấu trúc hữu ích khi sử dụng làm đối số cho các hàm. Khi gọi hàm, tại thời điểm gọi hàm, một con trỏ đến cấu trúc hoặc địa chỉ cụ thể của một biến cấu trúc được truyền cho hàm. Điều này cho phép hàm có thể sửa đổi trực tiếp các phần tử của cấu trúc.
Từ khoá Typedef
Từ khóa typedef cho phép định nghĩa một tên kiểu dữ liệu mới trong ngôn ngữ lập trình C. Điều này không tạo ra một kiểu dữ liệu mới, mà chỉ định một tên mới cho một kiểu dữ liệu tồn tại. Cú pháp chung của câu lệnh typedef là:
typedef data_type new_type_name;
Ở đây, data_type có thể là bất kỳ kiểu dữ liệu hợp lệ nào và new_type_name là tên mới cho kiểu dữ liệu này.
Tên mới được định nghĩa là một bổ sung, không thay thế kiểu dữ liệu hiện có. Ví dụ, bạn có thể tạo một tên mới cho kiểu float như sau:
typedef float deci;
Câu lệnh này sẽ cho phép trình biên dịch nhận diện deci là một tên khác cho float. Một biến kiểu float có thể được khai báo bằng cách sử dụng deci như sau:
deci amt;
Ở đây, amt là một biến kiểu số thực dấu động của kiểu deci, là một tên khác cho float. Sau khi được định nghĩa, deci có thể được sử dụng trong câu lệnh typedef để gán tên khác cho float. Ví dụ:
typedef deci point;
Câu lệnh trên cho trình biên dịch biết point là một tên khác cho deci, mà là một tên khác cho float.
Tính năng typedef thường tiện lợi khi định nghĩa các cấu trúc, vì nó loại bỏ sự cần thiết phải viết lại struct mỗi khi tham chiếu đến một cấu trúc. Kết quả, cấu trúc có thể được tham chiếu một cách ngắn gọn hơn. Ngoài ra, tên được định nghĩa cho một kiểu dữ liệu cấu trúc tự định nghĩa thường đề xuất mục đích của cấu trúc trong chương trình.
Cấu trúc do người dùng định nghĩa có thể được viết dưới dạng:
typedef struct new_name {
data_type var1;
data_type var2;
// ...
} new_name;
Ở đây, new_name là kiểu dữ liệu cấu trúc tự định nghĩa và không phải là một biến cấu trúc. Các biến cấu trúc có thể được định nghĩa dựa trên kiểu dữ liệu mới này. Ví dụ:
typedef struct {
int day;
int month;
int year;
} date;
date due_date;
Ở đây, date là kiểu dữ liệu mới và due_date là một biến thuộc kiểu date. Hãy nhớ rằng typedef không thể sử dụng với các lớp lưu trữ (storage classes).
Sắp xếp mảng
Sắp xếp có nghĩa là sắp xếp dữ liệu trong mảng theo một thứ tự cụ thể như tăng dần hoặc giảm dần. Dữ liệu trong một mảng dễ dàng tìm kiếm hơn khi mảng đã được sắp xếp.
Dưới đây là 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:
- Sắp xếp nổi bọt (Bubble Sort)
- Sắp xếp chèn (Insertion Sort)
Sắp xếp nổi bọt (Bubble Sort)
Tên của quá trình sắp xếp này mô tả cách hoạt động của nó. Ở đây, các so sánh bắt đầu từ phần tử dưới cùng và các phần tử nhỏ hơn được đẩy lên phía trên. Quá trình sắp xếp một mảng 5 phần tử theo thứ tự tăng dần được mô tả như sau:
- Giá trị ở phần tử thứ 5 được so sánh với giá trị ở phần tử thứ 4
- Nếu giá trị ở phần tử thứ 5 nhỏ hơn giá trị ở phần tử thứ 4, thì giá trị của hai phần tử này sẽ được hoán đổi.
- Tiếp theo, giá trị ở phần tử thứ 4 được so sánh với giá trị ở phần tử thứ 3, và tương tự, các giá trị sẽ được hoán đổi nếu giá trị ở phần tử dưới cùng lớn hơn giá trị ở phần tử trên cùng.
- Giá trị ở phần tử thứ 3 được so sánh với giá trị ở phần tử thứ 2, và quá trình ‘so sánh và hoán đổi’ này tiếp tục.
- Khi kết thúc một lượt so sánh, giá trị nhỏ nhất đến được phần tử đầu tiên. Theo cách biểu tượng, có thể nói rằng giá trị nhỏ nhất đã ‘nổi lên’.
- Trong lượt so sánh tiếp theo, quá trình bắt đầu lại với phần tử thấp nhất và tiến lên đến phần tử thứ 2. Vì phần tử đầu tiên đã chứa giá trị nhỏ nhất, nên nó không cần phải so sánh nữa.
Theo cách này, khi kết thúc quá trình sắp xếp, các phần tử nhỏ hơn sẽ ‘nổi lên’ phía trên, trong khi các giá trị lớn hơn sẽ ‘lặn’ xuống. Hình bên dưới minh họa phương pháp sắp xếp nổi bọt.
Ví dụ 2:
#include <stdio.h>
int main() {
int i, j, temp;
int arr_num[5] = {23, 90, 9, 25, 16};
for (i = 3; i >= 0; i--) { /* Theo dõi từng lượt */
for (j = 4; j >= 4 - i; j--) { /* So sánh các phần tử */
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("\nMảng đã sắp xếp: ");
for (i = 0; i < 5; i++) {
printf("%d ", arr_num[i]);
}
return 0;
}
Sắp xếp chèn (Insertion Sort)
Trong phương pháp sắp xếp chèn, mỗi phần tử trong mảng được xem xét và đặt vào vị trí phù hợp trong số các phần tử đã được sắp xếp trước đó. Khi phần tử cuối cùng được đặt vào vị trí phù hợp của nó, mảng sẽ được sắp xếp. Ví dụ, giả sử một mảng có 5 phần tử
- Giá trị ở phần tử đầu tiên được giả định là ở trong thứ tự đã sắp xếp.
- Giá trị ở phần tử thứ hai được so sánh với phần của mảng đã sắp xếp hiện tại chỉ chứa phần tử đầu tiên
- Nếu giá trị ở phần tử thứ hai nhỏ hơn, nó được chèn trước phần tử đầu tiên. Bây giờ, hai phần tử đầu tiên tạo thành danh sách đã sắp xếp và phần còn lại tạo thành danh sách chưa sắp xếp.
- Phần tử tiếp theo từ danh sách chưa sắp xếp, phần tử thứ ba, sau đó được so sánh với danh sách đã sắp xếp.
- Nếu giá trị ở phần tử thứ ba nhỏ hơn giá trị ở phần tử đầu tiên, giá trị ở phần tử thứ ba được chèn trước phần tử đầu tiên.
- Nếu không, nếu giá trị ở phần tử thứ ba nhỏ hơn giá trị ở phần tử thứ hai, thì giá trị ở phần tử thứ ba sẽ được chèn trước phần tử thứ hai. Lúc này, phần đã sắp xếp của mảng chứa 3 phần tử trong khi phần chưa sắp xếp chứa 2 phần tử.
- Quá trình so sánh các phần tử trong phần chưa sắp xếp với các phần tử trong phần đã sắp xếp tiếp tục cho đến khi đã so sánh với phần tử cuối cùng của mảng.
Tại cuối quá trình sắp xếp, mỗi phần tử đã được chèn vào vị trí phù hợp của nó. Hình bên dưới minh họa cách làm việc của sắp xếp chèn:
Chương trình thực hiện sắp xếp chèn được đưa ra dưới đây.
Ví dụ 3:
#include <stdio.h>
void insertnum(int arrnum[], int x, int y);
int main() {
int i, j;
int arr[5] = {23, 90, 9, 25, 16};
char flag;
/* Vòng lặp để so sánh từng phần tử của phần chưa sắp xếp của mảng */
for (i = 1; i < 5; i++) {
flag = 'n';
for (j = 0; j < i && flag == 'n'; j++) {
if (arr[j] > arr[i]) {
/* Gọi hàm để chèn số */
insertnum(arr, i, j);
flag = 'y';
}
}
}
printf("\n\nMảng đã sắp xếp\n");
for (i = 0; i < 5; i++) {
printf("%d\t", arr[i]);
}
return 0;
}
void insertnum(int arrnum[], int x, int y) {
int temp;
/* Lưu trữ số cần chèn */
temp = arrnum[x];
/* Dùng vòng lặp để đẩy phần đã sắp xếp của mảng xuống
nơi số cần được chèn vào */
for (; x > y; x--) {
arrnum[x] = arrnum[x - 1];
}
/* Chèn số vào vị trí thích hợp */
arrnum[x] = temp;
}
Bài tập
Bài 1: Viết chương trình C triển khai hệ thống quản lý Sản phẩm. Mỗi sản phẩm là một cấu trúc Lưu trữ mã số (ID), tên (Name), giá (price) và số lượng (quantity) . Yêu cầu người dùng nhập các chi tiết cho 5 mục vào một mảng cấu trúc và hiển thị tên mục và tổng số price của nó. Cuối cùng, hiển thị tổng giá trị cuối cùng của hàng tồn kho.
Bài 2: Viết chương trình C lưu trữ tên và điểm của 5 học sinh vào một mảng cấu trúc. Loại mảng cấu trúc theo thứ tự điểm giảm dần. Hiển thị 3 điểm cao nhất.
Bài 3:
Viết chương trình C lưu trữ thông tin chi tiết danh sách vào một mảng cấu trúc.
Cho biết cấu trúc nhân sự bao gồm ID (định danh),Name (tên),salary (lương)
,YearJoining (năm tham gia).
Viết chương trình C thao tác các tác vụ đáp ứng yêu cầu sau:
Vẽ menu yêu cầu người dùng nhập liệu nhân sự:
1. Input 2. Incresease Salary 3. Display engaged employees 4. Exit
1. Nếu người dùng chọn 1, yêu cầu người dùng nhập số lượng nhân sự để lưu lại
2. Nếu người dùng chọn 2, tăng lương cho danh sách nhân sự theo điều kiện:
Lương <= 2000 tăng 15%
Lương > 2000 và <=5000 tăng 10%
Lương > 5000 không tăng lương
3. Nếu người dùng chọn 3, hiển thị nhân sự làm việc trên 10 năm
4. Nếu người dùng chọn 4, thoát
Sau khi nhập xong, menu phải tải lại và yêu cầu người dùng tiếp tục nhập liệu