Bài giảng Kỹ thuật lập trình - Chương 7: Cấu trúc dữ liệu
Mảng
Array
▪ Dãy hữu hạn các phần tử liên tiếp có cùng kiểu và tên
▪ Một hay nhiều chiều
▫ C không giới hạn số chiều của mảng
Cú pháp
DataType ArrayName[size];
mảng nhiều chiều
DataType ArrayName[size 1][size 2].[size n];Khởi tạo giá trị
mảng
▪ C1. Khi khai báo
float y[5] = { 3.2, 1.2, 4.5, 6.0, 3.6 }
int m[6][2] = { { 1, 1 }, { 1, 2 }, { 2, 1 }, { 2, 2
}, { 3, 1 }, { 3, 2 } };
char s1[6] = { 'H', 'a', 'n', 'o', 'i', '\0' }; //hoặc
char s1[6] = "Hanoi";
char s1[] = "Dai hoc Bach Khoa Hanoi"; //L = 24
int m[][] = { { 1, 2, 3 }, { 4, 5, 6 } };
▪ C2. Khai báo rồi gán giá trị cho từng phần tử của mảng.
int m[4];
m[0] = 1; m[1] = 2; m[2] = 3; m[3] = 4;

Trang 1

Trang 2

Trang 3

Trang 4

Trang 5

Trang 6

Trang 7

Trang 8

Trang 9

Trang 10
Tải về để xem bản đầy đủ
Bạn đang xem 10 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình - Chương 7: Cấu trúc dữ liệu", để tải tài liệu gốc về máy hãy click vào nút Download ở trên
Tóm tắt nội dung tài liệu: Bài giảng Kỹ thuật lập trình - Chương 7: Cấu trúc dữ liệu
uả
IntStack *stack = CreateStack(MAX);
do{
//Tính chữ số bên phải nhất,đẩy vào stack
PushStack(stack, n% b);
n/= b; //Thay n = n/b để tính tiếp
} while(n!= 0); //Lặp đến khi n = 0
while( !IsEmptyStack(stack) ){
// Rút lần lượt từng phần tửcủa stack
PopStack(stack, &n);
// chuyển sang dạng ký tự và in kết quả
printf(“%c”, digitChar[n]);
}
}
Ứng dụng
Tính biểu thức dùng ký pháp hậu tố
▪ Biểu thức số học được biểu diễn bằng ký pháp trung tố.
▫ Với phép toán 2 ngôi: Mỗi toán tử được đặt giữa hai toán hạng.
Với phép toán một ngôi: Toán tử được đặt trước toán hạng
-2 + 3 * 5 (-2) + (3 * 5)
▪ Thứ tự ưu tiên của các toán tử
() > ^ > * = % = / > + = –
Ứng dụng
Tính biểu thức dùng ký pháp hậu tố
Ký pháp hậu tố
▪ Toán hạng đặt trước toán tử
▪ Không cần dùng các dấu ().
Ví dụ
a*b*c*d*e*f => ab*c*d*e*f*
1 + (-5) / (6 * (7+8)) => 1 5 -6 7 8 + * / +
(x/y–a*b) * ((b+x) –y ) => x y / a b * –b x + y y ^ –*
(x*y*z –x^2 / (y*2 –z^3) + 1/z) * (x –y) =>
xy*z*x2^y2*z3^ –/ –1z/+xy –*
Ví dụ (7 –11) * 2 + 3
Biểu thức hậu tố:
7 11 – 2 * 3 +
-5
3 +
-8 -8
2 *
- 4 - 4
11 -
7 7
Ứng dụng
Tính biểu thức dùng ký pháp hậu tố
▪ Tính giá trị của một một biểu thức hậu tố được lưu trong
một xâu ký tự và trả về giá trị kết quả
▪ Quy ước
- Toán hạng: Là các số nguyên không âm một chữ số (cho đơn
giản)
- Toán tử: + , - , * , / , % , ^
bool isOperator(char op) {
return op == '+‘ || op == '-' ||
op == '*‘ || op == '%‘ ||
op == '/‘ || op == '^‘ ;
}
int compute(int left, int right, char op) {
int value;
switch(op){
case '+' : value = left + right; break;
case '-' : value = left - right; break;
case '*' : value = left * right; break;
case '%‘ : value = left % right; break;
case '/' : value = left / right; break;
case '^' : value = pow(left, right);
}
return value;
}
int TinhBtHauTo(string Bt) {
int left, right, kq;
char ch;
IntStack *stack = CreateStack(MAX);
for(int i=0; i < Bt.length(); i++)
{
ch = Bt[i];
if ( isdigit(ch) )
PushStack(stack, ch-'0');
// đẩy toán hạng vào stack
else if (isOperator(ch)) {
// rút stack 2 lần để lấy 2 toán hạng
left và right
PopStack(stack, &right);
PopStack(stack, &left);
kq =compute(left, right, ch);
// Tính "leftop right"
PushStack(stack, kq);
// Đẩy kq vào stack
} else //không phải toán hạng hoặc toán tử
printf(“Bieu thuc loi”);
}
// Kết thúc tính toán, giá trị biểu thức
// nằm trên đỉnh stack, đưa vào kq
PopStack(stack, kq);
Return kq;
}
4.
Hàng đợi
Queue
Hàng đợi
Queue
danh sách mà việc thêm
phải được thực hiện tại
một đầu còn xóa phải thực
hiện tại đầu kia.
Thao tác trên
hàng đợi
Enqueue Front
. Thêm một phần tử . Phần tử đầu
. P: Tràn (overflow) . P: Queue rỗng
Dequeue Rear
. Xóa một phần tử . Phần tử cuối
. P: Underflow . P: Queue rỗng
Hàng đợi
Queue
▪ Phần tử đầu hàng sẽ được phục trước, phần tử này được gọi
là front, hay head của hàng. Tương tự, phần tử cuối hàng ,
cũng là phần tử vừa được thêm vào hàng, được gọi là rear
hay tail của hàng.
▪ Biểu diễn hàng đợi
▫ Mô hình vật lý
▫ Hiện thực tuyến tính
▫ Hiện thực dãy vòng
Mô hình
vật lý
▪ Dùng mảng. Phải nắm giữ cả front và rear.
▪ Giữ front luôn là vị trí đầu của dãy.
▫ Thêm phần tử vào hàng ⇒ thêm vào cuối dãy.
▫ Lấy ra 1 phần tử ra ⇒ dịch chuyển tất cả các phần tử của dãy
lên 1 vị trí.
▪ Tương tự hình ảnh hàng đợi trong thực tế
▫ Không phù hợp với lưu trữ trong máy tính
Mô hình
hiện thực tuyến tính
▪ Dùng 2 chỉ số front và rear để lưu trữ đầu và cuối hàng mà
không di chuyển các phần tử.
▫ Thêm phần tử vào hàng ⇒ Tăng rear lên 1 và thêm phần tử vào
vị trí đó
▫ Lấy ra 1 phần tử ra ⇒ Lấy phần tử tại front và tăng front lên 1
▪ Nhược điểm: front và rear chỉ tăng mà không giảm ⇒ lãng
phí bộ nhớ
▫ Khắc phục: Khi hàng đợi rỗng thì ta gán lại front=rear=đầu dãy
Mô hình
hiện thực dãy vòng
▪ Dùng 1 dãy tuyến tính để mô phỏng 1 dãy vòng.
▫ Các vị trí trong vòng tròn được đánh số từ 0 đến max-1, trong
đó max là tổng số phần tử
▫ Để thực hiện dãy vòng, chúng ta cũng sử dụng các phân tử được
đánh số tương tư dãy tuyến tính.
▫ Sự thay đổi các chỉ số chỉ đơn giản là phép lấy phần dư số học:
khi một chỉ số vợt quá max-1, nó đc bắt đầu trở lại vợi trị 0.
▸ Tương tự với việc cộng thêm giờ trên đồng hồ mặt tròn
i = ((i+1) == max) ? 0: (i+1);
hoặc if ((i+1) == max) i = 0; else i = i+1;
hoặc i = (i+1) % max;
Mô hình
hiện thực dãy vòng
Cấu trúc dữ liệu
dùng mảng động
typedef struct intqueue{
int *queueArr;
int maxSize;
int count;
int front;
int rear;
} IntQueue;
Tạo
hàng đợi
IntQueue *CreateQueue(int max){
IntQueue *queue;
queue = (IntQueue *)malloc(sizeof(IntQueue));
/*Cấp phát cho mảng */
queue->queueAry= malloc(max *sizeof(int));
/* Khởi tạo queue rỗng */
queue->front = -1;
queue->rear = -1;
queue->count = 0;
queue->maxSize= maxSize;
return queue;
} /* createQueue*/
Thêm vào cuối
hàng đợi
int enqueue(struct intqueue *queue, int datain)
{
if (queue->count >= queue->maxSize)
return 0;
(queue->count)++;
queue->rear = (queue->rear + 1) % queue-
>maxSize;
queue->queueAry[queue->rear] = datain;
return 1;
}
Xóa ở đầu
hàng đợi
int dequeue(struct intqueue *queue, int *dOutPtr)
{if(!queue->count)
return 0;
*dOutPtr= queue->queueAry[queue->front];
(queue->count)--;
queue->front = (queue->front + 1) % queue-
>maxSize;
return 1;
}
Lấy phần tử
đầu
int Front(struct intqueue *queue,int *dOutPtr) {
if(!queue->count)
return 0;
else{
*dOutPtr= queue->queueAry[queue->front];
return 1;
}
}
Lấy phần tử
cuối
int Rear(struct intqueue *queue,int*dOutPtr) {
if(!queue->count)
return 0;
else{
*daOutPtr= queue->queueAry[queue->rear];
return 1;
}
}
Kiểm tra
rỗng và đầy
▪ Empty
int isEmpty(struct intqueue *queue)
{
return(queue->count == 0);
}
▪ Full
int isFull(struct intqueue *queue)
{
return( queue->count == queue->maxSize);
}
Xóa
hàng đợi
struct intqueue *destroyQueue(struct intqueue
*queue)
{
if(queue)
{
free(queue->queueAry);
free(queue);
}
return NULL;
}
5.
Cây
Tree
Cây
Tree
▪ Nhược điểm của danh sách: Tính tuần tự, chỉ thể hiện được
các mối quan hệ tuyến tính.
▪ Cây được sử dụng để lưu trữ các thông tin phi tuyến như
▫ Các thư mục file
▫ Các bước di chuyển của các quân cờ
▫ Sơ đồ nhân sự của tổ chức
▫ Cây phả hệ
Cây
Tree
Một cây (tree) gồm một
tập hữu hạn các nút (node)
và 1 tập hữu hạn các cành
(branch) nối giữa các nút.
Định nghĩa
đệ quy
Một cây là tập các nút
o là tập rỗng, hoặc
o có 1 nút gọi là nút gốc
có 0 hoặc nhiều cây con,
các cây con cũng là cây
Biểu diễn
cây
Các khái niệm
cơ bản
▪ Cạnh đi vào nút gọi là cành vào (indegree), cành đi ra khỏi
nút gọi là cành ra (outdegree).
▪ Số cạnh ra tại một nút gọi là bậc (degree) của nút đó. Nếu
cây không rỗng thì phải có 1 nút gọi là nút gốc (root), nút này
không có cạnh vào
▪ Các nút còn lại, mỗi nút phải có chính xác 1 cành vào. Tất cả
các nút đều có thể có 0,1 hoặc nhiều cành ra
Các khái niệm
cơ bản
Cây
con
Đường
đi
Độ sâu và
chiều cao
Cấp
Cây
nhị phân
▪ Mỗi nút có nhiều nhất 2 nút con: Nút trái và nút phải
▪ Một tập các nút T được gọi là cây nhị phân, nếu :
a) Nó là cây rỗng, hoặc
b) Gồm 3 tập con không trùng nhau:
1) Một nút gốc
2) Cây nhị phân con trái
3) Cây nhị phân con phải
Cây nhị phân đầy đủ và
cây nhị phân hoàn chỉnh
▪Cây nhị phân đầy ▪Cây nhị phân hoàn
đủ chỉnh
▫Cây nút trừ nút lá có ▫Tất cả các nút lá có cùng độ
cấp bằng 2 sâu và tất cả các nút giữa có
cấp bằng 2
Cây
cân bằng
▪ Khoảng cách từ 1 nút đến nút gốc xác định chi phí cần để
định vị nó:
▫ 1 nút có độ sâu là 5 ⇒ phải đi từ nút gốc và qua 5 cành
▪ Nếu cây càng thấp thì việc tìm đến các nút sẽ càng nhanh.
▪ Hệ số cân bằng của cây (balance factor) là số chênh lệch
giữa chiều cao của 2 cây con trái và phải của nó:
B = HL-HR
▪ Một cây cân bằng khi B = 0 và các cây con của nó cũng cân
bằng
Lưu trữ
cây nhị phân
▪ Lưu trữ kế tiếp: Sử dụng mảng
▪ Lưu trữ móc nối: Sử dụng con trỏ
Cấu trúc dữ liệu
dùng mảng
typedef struct tree_node
{
int data ;
struct tree_node *left ;
struct tree_node *right ;
}TREE_NODE;
Tạo
cây nhị phân
TREE_NODE *root, *leftChild, *rightChild;
// Tạo nút con trái
leftChild= (TREE_NODE *)malloc(sizeof(TREE_NODE));
leftChild->data = 20;
leftChild->left = leftChild->right = NULL;
// Tạo nút con phải
rightChild = (TREE_NODE *)malloc(sizeof(TREE_NODE));
rightChild->data = 30;
rightChild->left = rightChild->right = NULL;
// Tạo nút gốc
root = (TREE_NODE *)malloc(sizeof(TREE_NODE));
root->data = 10;
root->left = leftChild;
root->right = rightChild;
root->data= 50;// gán 50 cho root
Duyệt
cây nhị phân
▪ Duyệt theo thứ tự trước
▪ Duyệt theo thứ tự giữa
▪ Duyệt theo thứ tự sau
Duyệt theo thứ tự
trước
1. Thăm nút.
2. Duyệt cây con trái theo thứ tự trước.
3. Duyệt cây con phải theo thứ tự trước.
Duyệt theo thứ tự
giữa
1. Duyệt cây con trái theo thứ tự giữa
2. Thăm nút.
3. Duyệt cây con phải theo thứ tự giữa.
Duyệt theo thứ tự
sau
1. Duyệt cây con trái theo thứ tự sau.
2. Duyệt cây con phải theo thứ tự sau
3. Thăm nút
Duyệt theo
thứ tự trước
void Preorder(TREE_NODE *root)
{
if (root != NULL)
{
// tham node
printf("%d", root->data);
// duyet cay con trai
Preorder(root->left);
// duyet cay con phai
Preorder(root->right);
}
}
Ứng dụng của
duyệt cây
1. Tính độ cao của cây
2. Đếm số nút lá trong cây
3. Tính kích thước của cây (số nút)
4. Sao chép cây
5. Xóa cây
Tính độ cao
của cây
int Height(TREE_NODE *tree)
{
Int heightLeft, heightRight, heightval;
if( tree== NULL )
heightval= -1;
else
{ // Sửdụng phương pháp duyệt theo thứ tự sau
heightLeft= Height (tree->left);
heightRight= Height (tree->right);
heightval= 1 + max(heightLeft,heightRight);
}
return heightval;
}
Đếm số
nút lá
int CountLeaf(TREE_NODE *tree)
{
if (tree == NULL)
return 0;
int count = 0;
//Đếm theo thứ tự sau
count += CountLeaf(tree->left);// Đếm trái
count += CountLeaf(tree->right);//Đếm phải
//nếu nút tree là nút lá, tăng count
if(tree->left == NULL && tree->right == NULL)
count++;
return count;
}
Tính
kích thước
int TreeSize(TREE_NODE *tree)
{
if(tree== NULL)
return 0;
else
return( TreeSize(tree->left) +
TreeSize(tree->right) + 1 );
}
Sao chép
cây
Sao chép
cây
TREE_NODE *CopyTree(TREE_NODE *tree)
{
// Dừng đệ quy khi cây rỗng
if (tree== NULL) return NULL;
TREE_NODE *leftsub, *rightsub, *newnode;
leftsub=CopyTree(tree->left);
rightsub= CopyTree(tree->right);
// tạo cây mới
newnode= malloc(sizeof(TREE_NODE));
newnode->data = tree->data;
newnode->left = leftsub;
newnode->right = rightsub;
return newnode;
}
Xóa
cây
void DeleteTree(TREE_NODE *tree)
{
//xóa theo thứ tự sau
if(tree != NULL)
{
DeleteTree(tree->left);
DeleteTree(tree->right);
free(tree);
}
}
Ứng dụng của
cây nhị phân
▪ Cây biểu diễn biểu thức
▫ Tính giá trị biểu thức
▫ Tính đạo hàm
▪ Cây quyết định
Cây biểu diễn
biểu thức
▪ là một loại cây nhị phân đặc biệt, trong đó:
1. Mỗi nút lá chứa một toán hạng
2. Mỗi nút giữa chứa một toán tử
3. Cây con trái và phải của một nút toán tử thể hiện các biểu
thức con cần được đánh giá trước khi thực hiện toán tử tại
nút gốc
Cây biểu diễn
biểu thức
▪ Các mức chỉ ra thứ tự ưu tiên
▫ Các mức (độ sâu) của các nút chỉ ra thứ tự ưu tiên tương đối
của chúng trong biểu thức (không cần dùng ngoặc để thể hiện
thứ tự ưu tiên).
▫ Các phép toán tại mức cao hơn sẽ được tính sau các các phép
toán có mức thấp.
▫ Phép toán tại gốc luôn được thực hiện cuối cùng.
Cây biểu diễn
biểu thức
▪ Dễ dàng để tạo ra các biểu thức tiền tố, trung tố, hậu tố
▪ Trung tố: ( ( 8 -5 ) * ( ( 4 + 2 ) / 3 ) )
▪ Tiền tố: * -8 5 / + 4 2 3
▪ Hậu tố: 8 5 -4 2 + 3 / *
(thực chất là các phép duyệt theo thứ tự giữa, trước và sau)
Cài đặt
cây biểu thức
▪ Mỗi nút có 2 con trỏ
struct TreeNode {
InfoNode info ;// Dữ liệu
TreeNode *left ;// Trỏ tới nút con trái
TreeNode *right ; // Trỏ tới nút con phải
};
Cài đặt
cây biểu thức
▪ InfoNode có 2 dạng
enum OpType { OPERATOR, OPERAND } ;
struct InfoNode {
OpType whichType;
union // ANONYMOUS union
{
char operator;
int operand ;
}
};
Cài đặt
cây biểu thức
int Eval(TreeNode* ptr){
switch(ptr->info.whichType) {
case OPERAND :
return ptr->info.operand;
case OPERATOR :
switch ( tree->info.operation ){
case ‘+’:
return ( Eval(ptr->left) + Eval(ptr->right) ) ;
case ‘-’:
return ( Eval(ptr->left) – Eval(ptr->right) ) ;
case ‘*’:
return ( Eval(ptr->left) * Eval(ptr->right) ) ;
case ‘/’:
return ( Eval(ptr->left) / Eval(ptr->right) ) ;
}
}
}
Cây
tổng quát
▪ Biểu diễn giống như cây nhị phân?
▫ Mỗi nút sẽ chứa giá trị và các con trỏ trỏ đến các nút con của
nó?
▫ Bao nhiêu con trỏ cho một nút?
Không hợp lý
▪ Mỗi nút sẽ chứa giá trị và một con trỏ trỏ đến một “tập” các
nút con
▫ Xây dựng “tập”?
Cây
tổng quát
▪ Mỗi nút sẽ có 2 con trỏ:
▫ một con trỏ trỏ đến nút con đầu tiên của nó,
▫ con trỏ trỏ đến nút anh em kề với nó
Ví dụ
Cây tổng quát
Duyệt
cây tổng quát
▪ Thứ tự trước:
1. Thăm gốc
2. Duyệt cây con thứ nhất theo thứ tự trước
3. Duyệt các cây con còn lại theo thứ tự trước
▪ Thứ tự giữa
1. Duyệt cây con thứ nhất theo thứ tự giữa
2. Thăm gốc
3. Duyệt các cây con còn lại theo thứ tự giữa
▪ Thứ tự sau:
1. Duyệt cây con thứ nhất theo thứ tự sau
2. Duyệt các cây con còn lại theo thứ tự sau
3. Thăm gốc
Ứng dụng
Cây quyết định
▪ Dùng để biểu diễn lời giải của bài toán cần quyết định lựa
chọn
▪ Bài toán 8 đồng tiền vàng:
▫ Có 8 đồng tiền vàng a, b, c, d, e, f, g, h
▫ Có một đồng có trọng lượng không chuẩn
▫ Sử dụng một cân Roberval (2 đĩa)
▫ Output:
▸ Đồng tiền k chuẩn là nặng hơn hay nhẹ hơn
▸ Số phép cân là ít nhất
Cây
quyết định
void EightCoins(a, b, c, d, e, f, g, h) {
if (a+b+c == d+e+f) {
if (g > h) Compare(g, h, a);
else Compare(h, g, a);
}
else if (a+b+c > d+e+f){
if (a+d == b+e) Compare(c, f, a);
else if (a+d > b+e) Compare(a, e, b);
else Compare(b, d, a);
}
else{
if (a+d == b+e) Compare(f,c,a);
else if (a+d > b+e) Compare(d, b, a);
else Compare(e, a, b);
}
}
// so sánh x với đồng tiền chuẩn z
void Compare(x,y,z){
if(x>y) printf(“x nặng”);
else printf(“y nhẹ”);
}
Thanks!
Any questions?
Email me at trungtt@soict.hust.edu.vn
Presentation template by SlidesCarnivalFile đính kèm:
bai_giang_ky_thuat_lap_trinh_chuong_7_cau_truc_du_lieu.pdf

