1. Trang chủ
  2. » Giáo án - Bài giảng

Bài giảng môn kỹ thuật lập trình tự động hóa

111 1,5K 18

Đ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 111
Dung lượng 0,91 MB

Nội dung

Khi bắt đầu làm quen với ngôn ngữ lập trình – Cụ thể là ngôn ngữ C – Sinh Viên thường gặp khó khăn trong việc chuyển vấn đề lý thuyết sang cài đặt cụ thể trên máy. Sách “Giáo Trình Bài Tập Kỹ Thuật Lập Trình” nhằm cung cấp cho các Học Sinh Sinh Viên Trường CĐ Công Nghệ Thông Tin Tp. Hồ Chí Minh hệ thống các bài tập, những kỹ năng thực hành cơ bản và nâng cao về ngôn ngữ lập trình C.Khi bắt đầu làm quen với ngôn ngữ lập trình – Cụ thể là ngôn ngữ C – Sinh Viên thường gặp khó khăn trong việc chuyển vấn đề lý thuyết sang cài đặt cụ thể trên máy. Sách “Giáo Trình Bài Tập Kỹ Thuật Lập Trình” nhằm cung cấp cho các Học Sinh Sinh Viên Trường CĐ Công Nghệ Thông Tin Tp. Hồ Chí Minh hệ thống các bài tập, những kỹ năng thực hành cơ bản và nâng cao về ngôn ngữ lập trình C.

Trang 1

KỸ THUẬT LẬP TRÌNH

Nguyễn Mạnh Sơn

Email: manhsoncntt@yahoo.com

Trang 2

Nội dung

móc nối

Trang 3

Chương 1: Đại cương về lập trình cấu trúc

Trang 4

Lịch sử lập trình cấu trúc

Trang 5

Cấu trúc lệnh

Trang 6

Cấu trúc lệnh

Trang 8

Cấu trúc dữ liệu

 Các cấu trúc dữ liệu được phân thành hai loại:

 Cấu trúc dữ liệu có kiểu cơ bản (Base type), bao gồm:

 Kiểu kí tự (char)

 Kiểu số nguyên có dấu (signed int)

 Kiểu số nguyên không dấu (unsigned int)

 Kiểu số nguyên dài có dấu (signed long)

 Kiểu số nguyên dài không dấu (unsigned long )

 Kiểu số thực (float)

 Kiểu số thực có độ chính xác gấp đôi (double)

 Cấu trúc dữ liệu có kiểu do người dùng định nghĩa (User type) hay còn gọi là kiểu dữ liệu có cấu trúc, bao gồm:

 Kiểu xâu kí tự (string)

 Kiểu mảng (array)

 Kiểu tập hợp (union),

 Kiểu cấu trúc (struct),

 Kiểu file,

 Kiểu con trỏ (pointer)

 Các kiểu dữ liệu được định nghĩa mới hoàn toàn như kiểu danh sách móc nối (link list), kiểu cây (tree)

Trang 9

Nguyên lý tối thiểu

 ??

Trang 10

Nguyên lý địa phương

 Các biến địa phương trong hàm, thủ tục hoặc chu trình cho dù có trùng tên với biến toàn cục thì khi xử lý biến

đó trong hàm hoặc thủ tục vẫn không làm thay đổi giá trị của biến toàn cục.

 Tên của các biến trong đối của hàm hoặc thủ tục đều là hình thức.

 Mọi biến hình thức truyền theo trị cho hàm hoặc thủ tục đều là các biến địa phương.

 Các biến khai báo bên trong các chương trình con, hàm hoặc thủ tục đều là biến địa phương.

 Khi phải sử dụng biến phụ nên dùng biến địa phương và hạn chế tối đa việc sử dụng biến toàn cục để tránh xảy ra các hiệu ứng phụ.

Trang 11

Nguyên lý nhất quán

 Dữ liệu thế nào thì phải thao tác thế ấy

trúc dữ liệu và thao tác để kịp thời khắc phục.

Trang 12

Nguyên lý an toàn

 Lỗi nặng nhất nằm ở mức cao nhất (mức ý đồ thiết kế)

và ở mức thấp nhất thủ tục phải chịu tải lớn nhất.

 Mọi lỗi, dù là nhỏ nhất cũng phải được phát hiện ở một bước nào đó của chương trình Quá trình kiểm tra và

phát hiện lỗi phải được thực hiện trước khi lỗi đó hoành hành

 Các loại lỗi thường xảy ra trong khi viết chương trình:

Lỗi xảy ra trong quá trình liên kết

Trang 13

Phương pháp top-down

 Quá trình phân tích bài toán được thực hiện từ trên

xuống dưới Từ vấn đề chung nhất đến vấn đề cụ thể

nhất Từ mức trừu tượng mang tính chất tổng quan tới mức đơn giản nhất là đơn vị chương trình.

 Quá trình phân rã bài toán được thực hiện theo từng mức khác nhau

 Mức thấp nhất được gọi là mức tổng quan (level 0), mức tổng

quan cho phép ta nhìn tổng thể hệ thống thông qua các chức

năng của nó, nói cách khác mức 0 sẽ trả lời thay cho câu hỏi “Hệ thống có thể thực hiện được những gì ?”

 Mức tiếp theo là mức các chức năng chính Ở mức này, những chức năng cụ thể được mô tả Một hệ thống có thể được phân tích thành nhiều mức khác nhau, mức thấp được phép sử dụng các dịch vụ của mức cao

 Quá trình phân tích tiếp tục phân rã hệ thống theo từng chức

năng phụ cho tới khi nào nhận được mức các đơn thể ( UNIT,

Function, Procedure), khi đó chúng ta tiến hành cài đặt hệ thống

Trang 14

cho quá trình cài đặt hệ thống

Trang 15

Chương 2: Duyệt và đệ quy

Trang 16

 f(n+1) = ( n+1) f(n) với mọi n nguyên dương.

 Cấu trúc tự trỏ được định nghĩa bằng đệ qui

struct node { int infor;

struct node *left;

struct node *right;

};

Trang 17

Giải thuật đệ quy

 Một thuật toán được gọi là đệ qui nếu nó giải bài toán

bằng cách rút gọn bài toán ban đầu thành bài toán tương

tự như vậy sau một số hữu hạn lần thực hiện.

 Trong mỗi lần thực hiện, dữ liệu đầu vào tiệm cận tới tập

Trang 18

Giải thuật đệ quy

Thuật toán 2: Thuật toán đệ qui tính ước số chung lớn nhất của hai số

Thuật toán 3: Thuật toán đệ qui tính n!

long factorial( int n){

if (n ==1)

return(1);

return(n * factorial(n-1));

}

Thuật toán 4: Thuật toán đệ qui tính số fibonacci thứ n

int fibonacci( int n) {

if (n==0) return(0);

else if (n ==1) return(1);

return(fibonacci(n-1) + fibonacci(n-2));

}

Trang 19

Phương pháp sinh

 Điều kiện:

 Có thể xác định được một thứ tự trên tập các cấu hình tổ hợp

cần liệt kê Từ đó có thể xác định được cấu hình tổ hợp đầu tiên và cuối cùng trong thứ tự đã được xác định

 Xây dựng được thuật toán từ cấu hình chưa phải là cuối cùng

đang có để đưa ra cấu hình kế tiếp sau nó

 Thuật toán tổng quát

void Generate(void){

<Xây dựng cấu hình ban đầu>;

stop =falsewhile (not stop) {

<Đưa ra cấu hình đang có>;

Sinh_Kế_Tiếp;

}}

Trang 20

Liệt kê các xâu nhị phân độ dài n

 Quy tắc

 Tìm i đầu tiên từ phải xang trái (i=n, n-1, ,1) thoả mãn bi =0

 Gán lại bi =1 và bj=0 với tất cả j>i Dãy thu được là dãy cần tìm

Trang 21

Thuật toán quay lui

 Nội dung chính của thuật toán

 Xây dựng dần các thành phần của cấu hình bằng cách thử tất cả các khả năng Với mỗi khả năng j, kiểm tra xem j có chấp nhận được hay không Khi đó có thể xảy ra hai trường hợp:

 Nếu chấp nhận j thì xác định xi theo j, nếu i=n thì ta được một cấu hình cần tìm, ngược lại xác định tiếp thành phần x i+1

 Nếu thử tất cả các khả năng mà không có khả năng nào được chấp nhận thì quay lại bước trước đó để xác định lại x i-1

 Giải thuật tổng quát

void Try( int i ) {

Trang 22

Đặt hậu;

if i<8 {

DatHau(i+1);

if Không thành công

Bỏ hậu đã đặt ra khỏi vị trí }

} }while (Không thành công) && (Vẫn còn lựa chọn)

}

Trang 23

}

Trang 24

Thuật toán nhánh cận

Trang 29

Ngăn xếp – Các thao tác

Thao tác Pop : Loại bỏ nút tại đỉnh stack.

int Pop ( stack *ps) {

if (Empty(ps) {

printf(“\n stack empty”);

return(0);

} return( ps -> nodes[ps->top ]);

}

Trang 30

Ứng dụng

 Quá trình đảo ngược một xâu kí tự giống như việc đưa vào

(push) từng kí tự trong xâu vào stack, sau đó đưa ra (pop) các kí

tự trong stack ra cho tới khi stack rỗng ta được một xâu đảo

 Biểu thức dạng hậu tố chỉ chứa các phép toán cộng (+), trừ (-), nhân (*), chia (/), lũy thừa ($)

Ví dụ : 23+5*2$ = ( (2 + 3) *5 ) 2 = 625

Trang 32

Hàng đợi

Trang 33

 Người sản xuất có thể sản xuất tối đa n mặt hàng

 Người tiêu dùng chỉ được phép sử dụng trong số n mặt hàng

 Tuy nhiên, người sản xuất chỉ có thể lưu trữ vào kho khi và chỉ khi kho chưa bị đầy

 Ngược lại, nếu kho hàng không rỗng (kho có hàng) người tiêu

dùng có thể tiêu dùng những mặt hàng trong kho theo nguyên tắc hàng nào nhập vào kho trước được tiêu dùng trước giống như

cơ chế FIFO của queue

Trang 34

Hàng đợi – Các thao tác

hàng đợi Ở trạng thái này, font và rear có cùng một giá trị MAX-1.

void Initialize ( queue *pq){

pq->front = pq->rear = MAX -1;

}

hay không Hàng đợi rỗng khi front == rear.

Trang 35

Hàng đợi – Các thao tác

Thao tác Insert: thêm X vào hàng đợi Q Nếu việc thêm X vào

hàng đợi được thực hiện ở đầu hàng, khi đó rear có giá trị 0, nếu rear không phải ở đầu hàng đợi thì giá trị của nó được tăng lên 1 đơn vị

void Insert(queue *pq, hang x){

Trang 36

Hàng đợi – Các thao tác

Thao tác Remove: loại bỏ phần tử ở vị trí front khỏi hàng đợi Nếu

hàng đợi ở trạng thái rỗng thì thao tác Remove không thể thực hiện được, trong trường hợp khác front được tăng lên một đơn vị

Trang 37

Hàng đợi – Các thao tác

Thao tác Traver: Duyệt tất cả các nút trong hàng đợi.

void Traver( queue *pq){

Trang 38

 Mỗi đỉnh trong danh sách đều gồm hai phần

 Phần thứ nhất chứa dữ liệu Dữ liệu có thể chỉ là một biến đơn hoặc

là một cấu trúc (hoặc con trỏ cấu trúc) có kiểu nào đó

 Phần thứ hai của đỉnh là một con trỏ chỉ vào địa chỉ của đỉnh tiếp theo trong danh sách

Trang 39

Danh sách liên kết đơn

NODEPTR Freenode( NODEPTR p){

free(p);

}

Trang 40

Danh sách liên kết đơn

 Chèn vào đầu danh sách

void Push_Top( NODEPTR *plist, int x) {

NODEPTR p;

p= Getnode(); // cấp không gian nhớ cho đỉnh mới

p -> infor = x; // gán giá trị thích hợp cho đỉnh mới

p ->next = *plist;

*plist = p; // thiết lập liên kết

}

Trang 41

Danh sách liên kết đơn

Trang 42

Danh sách liên kết kép

Trang 43

CHƯƠNG 4:

CẤU TRÚC DỮ LIỆU CÂY

Trang 44

Cây là gì

 Khái niệm cây

 Cây là một tập hợp các nút (các đỉnh) và các cạnh, thỏa mãn một số yêu cầu nào đó Mỗi nút của cây đều có 1 định danh và có thể mang thông tin nào đó Các cạnh dùng để liên kết các nút với nhau Một đường đi trong cây là một danh sách các đỉnh phân biệt mà đỉnh trước có liên kết với đỉnh sau

 Một tính chất rất quan trọng hình thành nên cây, đó là có đúng một

đường đi nối 2 nút bất kỳ trong cây

 Định nghĩa cây dưới dạng đệ quy

 Một nút đứng riêng lẻ (và nó chính là gốc của cây này).

 Hoặc một nút kết hợp với một số cây con bên dưới.

 Một số khái niệm khác

 Mỗi nút trong cây (trừ nút gốc) có đúng 1 nút nằm trên nó, gọi là nút cha (parent) Các nút nằm ngay dưới nút đó được gọi là các nút con

(subnode ) Các nút nằm cùng cấp được gọi là các nút anh em (sibling).

Nút không có nút con nào được gọi là nút lá (leaf) hoặc nút tận cùng

 Chiều cao của nút là đường đi dài nhất từ nút tới một lá Chiều cao của cây chính là chiều cao của nút gốc Độ sâu của 1 nút là độ dài đường đi duy nhất giữa nút gốc và nút đó.

Trang 45

Cài đặt cây

Cài đặt cây bằng mảng các nút cha

Trang 46

Cài đặt cây

Cài đặt cây thông qua danh sách các nút

con

Trang 48

Duyệt cây

 Duyệt là gì:

một cây theo một trình tự nào đó Trong quá trình

duyệt, tại mỗi nút ta có thể tiến hành một thao tác xử

lý nào đó Đối với các danh sách liên kết, việc duyệt qua danh sách đơn giản là đi từ nút đầu, qua các liên kết và tới nút cuối cùng

Trang 52

Cây nhị phân

nó chỉ có nhiều nhất là 2 nút con Khi đó, 2 cây con của mỗi nút được gọi là cây con trái và cây con phải

Trang 53

Cây nhị phân

 Một số dạng cây nhị phân đặc

biệt:

 Cây nhị phân đầy đủ:

 Là cây nhị phân mà mỗi nút không phải lá đều có đúng 2 nút con và các nút lá phải có cùng độ sâu

 Cây nhị phân tìm kiếm:

 Là cây nhị phân có tính chất khóa của nút con bên trái bao giờ cũng nhỏ hơn khóa của nút cha, còn khóa của cây con bên phải bao giờ cũng lớn hơn hoặc bằng khóa của nút

Trang 54

Cài đặt cây nhị phân bằng mảng

 Đối với cây nhị phân không cân bằng, có thể sử dụng cấu trúc sau:

Trang 56

struct node *left;

struct node *right;

}

typedef struct node *NODEPTR

Trang 57

Các thao tác trên cây nhị phân

free(p);

}

void Initialize(NODEPTR *ptree){

*ptree=NULL;

}

Trang 58

Các thao tác trên cây nhị phân

Kiểm tra tính rỗng của cây nhị phân:

int Empty(NODEPTR *ptree){

if (*ptree==NULL) return(TRUE);

return(FALSE);

}

Tạo một node lá cho cây nhị phân:

 Cấp phát bộ nhớ cho node;

 Gán giá trị thông tin thích hợp cho node;

 Tạo liên kết cho node lá;

NODEPTR Makenode(int x){

NODEPTR p;

p= Getnode();// cấp phát bộ nhớ cho node

p ->infor = x; // gán giá trị thông tin thích hợp

p ->left = NULL; // tạo liên kết trái của node lá

p ->right = NULL;// tạo liên kết phải của node lá

return(p);

}

Trang 59

Các thao tác trên cây nhị phân

Tạo node con bên trái của cây nhị phân:

 Để tạo được node con bên trái là node lá của node p, chúng ta thực hiện như sau:

 Nếu node p không có thực (p==NULL), ta không thể tạo được node con bên trái của node p;

 Nếu node p đã có node con bên trái (p->left!=NULL), thì chúng ta cũng không thể tạo được node con bên trái node p;

 Nếu node p chưa có node con bên trái, thì việc tạo node con bên trái chính là thao tác make node đã được xây dựng như trên;

void Setleft(NODEPTR p, int x ){

if (p==NULL){

// nếu node p không có thực thì không thể thực hiện được

printf(“\n Node p không có thực”);

delay(2000); return;

}

// nếu node p có thực và tồn tại lá con bên trái thì cũng không thực hiện được

else if ( p ->left !=NULL){

printf(“\n Node p đã có node con bên trái”);

Trang 60

Các thao tác trên cây nhị phân

Tạo node con bên phải của cây nhị phân:

 Để tạo được node con bên phải là node lá của node p, chúng ta làm như sau:

 Nếu node p không có thực (p==NULL), thì ta không thể thực hiện được thao tác thêm node lá vào node phải node p;

 Nếu node p có thực (p!=NULL) và đã có node con bên phải thì thao tác cũng không thể thực hiện được;

 Nếu node p có thực và chưa có node con bên phải thì việc tạo node con bên phải node p được thực hiện thông qua thao tác Makenode();

void Setright(NODEPTR p, int x ){

if (p==NULL){ // Nếu node p không có thực

printf(“\n Node p không có thực”);

delay(2000); return;

}

// Nếu node p có thực & đã có node con bên phải

else if ( p ->right !=NULL){

printf(“\n Node p đã có node con bên phải”);

Trang 61

Các thao tác trên cây nhị phân

Trang 63

63

Trang 65

Các khái niệm cơ bản (tiếp)

 Một cạnh (u, v) của đồ thị có hướng có thể được biểu thị dạng u  v Đỉnh u khi đó được gọi là đỉnh kề của v Cạnh (u, v) được gọi là cạnh xuất phát từ u Ta ký hiệu A(u) là tập các cạnh xuất phát từ u

 Bậc ngoài của 1 đỉnh là số các cạnh xuất phát từ đỉnh đó Do đó, bậc ngoài của u = | A(u) |

 Bậc trong của 1 đỉnh là số các cạnh đi tới đỉnh đó Do đó, bậc trong của v = | I(v) |

 Một đường đi trong đồ thị có hướng G(V, E) là một chuỗi các đỉnh

P = {v1, v2, …, vk}

Trong đó, vi  V (i = 1 k), và (vi, vi+1)  E (i = 1 k-1)

 Độ dài của đường đi trong trường hợp này là k - 1

 Chu trình là một đường đi mà đỉnh đầu và đỉnh cuối trùng nhau Đồ thị liên thông là một đồ thị mà luôn tồn tại đường đi giữa 2 đỉnh bất kì

Trang 66

Các khái niệm cơ bản (tiếp)

 Đồ thị vô hướng là đồ thị có các cạnh không có hướng Hai nút

ở hai đầu của cạnh có vai trò như nhau Định nghĩa về đồ thị vô hướng như sau:

 Đồ thị vô hướng G = <V, E> bao gồm:

 V là một tập hữu hạn các đỉnh

 E là một tập hữu hạn các cặp đỉnh phân biệt của V, gọi là

các cạnh

 Ví dụ, đồ thị có hướng G2 = <V2, E2>, với V2 và E2

được xác định như sau:

 V2 = {a, b, c, d}

 E2 = {(a, b); (a, c}; (b, d); (c, b) } a b

Trang 67

Ninh Bình 96km

45km

Trang 68

Biểu diễn đồ thị - Ma trận kề

Đồ thị có trọng số

Trang 70

 Nếu có nhiều thành phần liên thông

for( i=1; in; i++)

daxet[i] = 0;

for( i:=1;i n; i++)

if (daxet[i]=0)

DeepFirstSearch(i);

Trang 71

}

Trang 72

Duyệt các thành phần liên thông

 Tư tưởng

 Nếu số thành phần liên thông lớn hơn 1 chúng ta có thể tách

chúng thành những đồ thị con liên thông => số thành phần liên thông của nó bằng số lần gọi tới thủ tục DFS() hoặc BFS()

 Để xác định số các thành phần liên thông của đồ thị, chúng ta sử dụng biến mới solt để nghi nhận các đỉnh cùng một thành phần liên thông trong mảng chuaxet[] như sau:

 Nếu đỉnh i chưa được duyệt, chuaxet[i] có giá trị 0;

 Nếu đỉnh i được duyệt thuộc thành phần liên thông thứ

j=solt, ta ghi nhận chuaxet[i]=solt;

 Các đỉnh cùng thành phần liên thông nếu chúng có cùng giá trị trong mảng chuaxet[]

Trang 73

u <= queue; /*nạp u vào hàng đợi*/

solt = solt+1; chuaxet[u] = solt; /*solt là biến toàn cục thiết lập giá trị 0*/ while (queue   ) {

queue<=p; /* lấy p ra từ stack*/

for v  ke(p) {

if (chuaxet[v] ) {

v<= queue; /*nạp v vào hàng đợi*/

chuaxet[v] = solt; /* v có cùng thành phần liên thông với p*/

} }

}

}

Trang 74

for( i=1; i<=solt;i++){

/* Đưa ra thành phần liên thông thứ i*/

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

if( chuaxet[j]==i)

<đưa ra đỉnh j>;

} }

}

Trang 75

 Kết quả thể hiện trong mảng chuaxet[] Nếu chuaxet[t] = False thì

có nghĩa t cùng thành phần liên thông với s Ngược lại chuaxet[t]

= True thì t không cùng thành phần liên thông với s

 Để đưa ra đường đi: sử dụng mảng truoc[] thiết lập giá trị ban đầu

là 0 Trong quá trình duyệt, ta thay thế giá trị của truoc[v] để ghi nhận đỉnh đi trước đỉnh v trong đường đi tìm kiếm từ s đến v

Trang 76

void BFS (int u){

queue = ;

u <= queue; /*nạp u vào hàng đợi*/

chuaxet[u] = false ;/* đổi trạng thái của u*/

while (queue   ) { /* duyệt tới khi nào hàng đợi rỗng*/

queue<=p; /*lấy p ra từ khỏi hàng đợi*/

for (v  ke(p) ) { /* đưa các đỉnh v kề với p nhưng chưa được

xét vào hàng đợi*/

if (chuaxet[v] ) { v<= queue; /*đưa v vào hàng đợi*/

chuaxet[v] = false ;/* đổi trạng thái của v*/

truoc[v]=p;

} }

} /* end while*/

Ngày đăng: 20/06/2015, 19:27

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w